pax_global_header00006660000000000000000000000064130075027670014521gustar00rootroot0000000000000052 comment=1e66e4b8737755ad1e5bfd3b1507e9716406ffc9 antimicro-2.23/000077500000000000000000000000001300750276700134345ustar00rootroot00000000000000antimicro-2.23/.gitignore000066400000000000000000000004721300750276700154270ustar00rootroot00000000000000*.o .*.swp .directory *.qm *.diff *.mo Makefile antimicro !share/antimicro antimicro.pro.user antimicro.pro.user.* moc_* qrc_resources.cpp ui_*.h *.*~ SDL2-2.0.3/ SDL2-2.0.4/ vmulti/ windows/*.msi windows/*.wix* build/ Build/ CMakeLists.txt.user* other/antimicro.1.gz other/license-template.txt doc/ src/Changelog antimicro-2.23/AntiMicro Future Developments.mm000066400000000000000000000075311300750276700215430ustar00rootroot00000000000000 antimicro-2.23/BuildOptions.md000066400000000000000000000021521300750276700163710ustar00rootroot00000000000000# Build Options for CMake There are a few application specific options that can be used when running cmake to build antimicro. The following file will attempt to list some of those options and describe their use in the project. ## Universal Options -DUPDATE_TRANSLATIONS Default: OFF. Set updateqm target to call lupdate in order to update translation files from source. -DUSE_SDL_2 Default: ON. Compile the program with SDL 2 instead of SDL 1.2. ## Linux Options -DAPPDATA Default: OFF. Build the project with AppData support. -DWITH_UINPUT Default: OFF. Compile the program with uinput support. -DWITH_X11 Default: ON. Compile the program with X11 support. -DWITH_XTEST Default: ON. Compile the program with XTest support. ## Windows Options -DPORTABLE_PACKAGE Default: OFF. Compile the program with extra changes used for containing the final program to a single directory. -DWITH_VMULTI Default: OFF. Compile the program with support for the vmulti driver. -DPERFORM_SIGNING Default: OFF. This option is only included for testing. It should not be used currently. antimicro-2.23/CMakeLists.txt000066400000000000000000000766351300750276700162150ustar00rootroot00000000000000## antimicro Gamepad to KB+M event mapper ## Copyright (C) 2015 Travis Nickles ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see . # Debian Wheezy has a package for version 2.8.9 so # that will be the minimum supported version. cmake_minimum_required(VERSION 2.8.9) project(antimicro) if(WIN32) # Cause cmake to fail if Qt location is not specified. if(NOT CMAKE_PREFIX_PATH) message(FATAL_ERROR "Please set CMAKE_PREFIX_PATH to the Qt installation directory. Exiting.") endif(NOT CMAKE_PREFIX_PATH) # CMP0020: Automatically link Qt executables to qtmain target on Windows. cmake_policy(SET CMP0020 NEW) endif(WIN32) # The version number. set(ANTIMICRO_MAJOR_VERSION 2) set(ANTIMICRO_MINOR_VERSION 23) set(ANTIMICRO_PATCH_VERSION 0) option(USE_SDL_2 "Use SDL 2 libraries rather than SDL 1." ON) if(UNIX) option(WITH_X11 "Compile with support for X11." ON) option(WITH_UINPUT "Compile with support for uinput. uinput will be usable to simulate events." OFF) option(WITH_XTEST "Compile with support for XTest. XTest will be usable to simulate events." ON) option(APPDATA "Build project with AppData file support." OFF) endif(UNIX) option(UPDATE_TRANSLATIONS "Call lupdate to update translation files from source." OFF) option(TRANS_KEEP_OBSOLETE "Do not specify -no-obsolete when calling lupdate." OFF) if(WIN32) option(PORTABLE_PACKAGE "Create portable Windows package" OFF) #option(TARGET_ARCH "Choose which version of some libraries to use. (x86, x86_64)" "x86") option(WITH_VMULTI "Compile with support for vmulti." OFF) option(PERFORM_SIGNING "Sign final executable." OFF) if(PORTABLE_PACKAGE) message("Portable package mode build") add_definitions(-DWIN_PORTABLE_PACKAGE) # Only way to force install target to be dependent on createprofiledir. add_custom_target(createprofiledir) add_custom_command(TARGET createprofiledir PRE_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/profiles" ) install(CODE "execute_process(COMMAND ${CMAKE_BUILD_TOOL} createprofiledir WORKING_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}\")") install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/profiles" DESTINATION ${CMAKE_INSTALL_PREFIX}) endif(PORTABLE_PACKAGE) # Find target architecture based on the compiler. if (CMAKE_SIZEOF_VOID_P EQUAL 8) set(TARGET_ARCH "x86_64") else() set(TARGET_ARCH "x86") endif(CMAKE_SIZEOF_VOID_P EQUAL 8) #if(TARGET_ARCH) # set(ARCH_OPTIONS "x86" "x86_64") # list(FIND ARCH_OPTIONS ${TARGET_ARCH} ARCH_INDEX) # if(ARCH_INDEX EQUAL -1) # message(FATAL_ERROR "No valid architecture choice used. Exiting.") # endif(ARCH_INDEX EQUAL -1) #endif(TARGET_ARCH) if(WITH_VMULTI) add_definitions(-DWITH_VMULTI) endif(WITH_VMULTI) endif(WIN32) # Use pkg-config to find SDL library. if(UNIX) find_package(PkgConfig REQUIRED) #include(FindPkgConfig) if(USE_SDL_2) pkg_check_modules(SDL2 REQUIRED sdl2) elseif(NOT USE_SDL_2) pkg_check_modules(SDL REQUIRED sdl) endif(USE_SDL_2) if(WITH_X11) find_package(X11 REQUIRED) endif(WITH_X11) if(WITH_XTEST AND NOT WITH_X11) set(WITH_XTEST OFF) message("Cannot use XTest without X11. Disabling XTest support.") endif(WITH_XTEST AND NOT WITH_X11) if(WITH_XTEST) message("XTest support allowed for simulating events.") endif(WITH_XTEST) if(WITH_UINPUT) message("uinput support allowed for simulating events.") endif(WITH_UINPUT) if(NOT WITH_XTEST AND NOT WITH_UINPUT) message(FATAL_ERROR "No system is defined for simulating events.") endif(NOT WITH_XTEST AND NOT WITH_UINPUT) endif(UNIX) set(antimicro_SOURCES src/main.cpp src/mainwindow.cpp src/joybuttonwidget.cpp src/joystick.cpp src/joybutton.cpp src/joybuttontypes/joygradientbutton.cpp src/event.cpp src/inputdaemon.cpp src/joyaxis.cpp src/joyaxiswidget.cpp src/joydpad.cpp src/joybuttontypes/joydpadbutton.cpp src/axiseditdialog.cpp src/xmlconfigreader.cpp src/xmlconfigwriter.cpp src/joytabwidget.cpp src/axisvaluebox.cpp src/advancebuttondialog.cpp src/simplekeygrabberbutton.cpp src/joybuttonslot.cpp src/joybuttontypes/joyaxisbutton.cpp src/aboutdialog.cpp src/setjoystick.cpp src/sdleventreader.cpp src/setaxisthrottledialog.cpp src/keyboard/virtualkeypushbutton.cpp src/keyboard/virtualkeyboardmousewidget.cpp src/keyboard/virtualmousepushbutton.cpp src/buttoneditdialog.cpp src/commandlineutility.cpp src/joycontrolstick.cpp src/joybuttontypes/joycontrolstickbutton.cpp src/joybuttontypes/joycontrolstickmodifierbutton.cpp src/joycontrolstickeditdialog.cpp src/joycontrolstickpushbutton.cpp src/joycontrolstickbuttonpushbutton.cpp src/joycontrolstickstatusbox.cpp src/advancestickassignmentdialog.cpp src/dpadpushbutton.cpp src/dpadeditdialog.cpp src/vdpad.cpp src/joydpadbuttonwidget.cpp src/quicksetdialog.cpp src/mousehelper.cpp src/mousesettingsdialog.cpp src/mousedialog/mousecontrolsticksettingsdialog.cpp src/mousedialog/mouseaxissettingsdialog.cpp src/mousedialog/mousebuttonsettingsdialog.cpp src/mousedialog/mousedpadsettingsdialog.cpp src/joytabwidgetcontainer.cpp src/mousedialog/springmoderegionpreview.cpp src/joystickstatuswindow.cpp src/joybuttonstatusbox.cpp src/qtkeymapperbase.cpp src/flashbuttonwidget.cpp src/xmlconfigmigration.cpp src/qkeydisplaydialog.cpp src/antkeymapper.cpp src/inputdevice.cpp src/mainsettingsdialog.cpp src/gamecontroller/gamecontrollertriggerbutton.cpp src/setnamesdialog.cpp src/autoprofileinfo.cpp src/addeditautoprofiledialog.cpp src/editalldefaultautoprofiledialog.cpp src/common.cpp src/localantimicroserver.cpp src/extraprofilesettingsdialog.cpp src/antimicrosettings.cpp src/joybuttoncontextmenu.cpp src/joycontrolstickcontextmenu.cpp src/dpadcontextmenu.cpp src/joyaxiscontextmenu.cpp src/stickpushbuttongroup.cpp src/dpadpushbuttongroup.cpp src/joybuttonmousehelper.cpp src/logger.cpp src/inputdevicebitarraystatus.cpp src/applaunchhelper.cpp src/slotitemlistwidget.cpp src/eventhandlers/baseeventhandler.cpp src/eventhandlerfactory.cpp src/uihelpers/advancebuttondialoghelper.cpp src/uihelpers/buttoneditdialoghelper.cpp src/uihelpers/joytabwidgethelper.cpp src/uihelpers/joyaxiscontextmenuhelper.cpp src/uihelpers/joycontrolstickcontextmenuhelper.cpp src/uihelpers/dpadcontextmenuhelper.cpp src/uihelpers/dpadeditdialoghelper.cpp src/uihelpers/joycontrolstickeditdialoghelper.cpp src/uihelpers/gamecontrollermappingdialoghelper.cpp src/mousedialog/uihelpers/mouseaxissettingsdialoghelper.cpp src/mousedialog/uihelpers/mousebuttonsettingsdialoghelper.cpp src/mousedialog/uihelpers/mousecontrolsticksettingsdialoghelper.cpp src/mousedialog/uihelpers/mousedpadsettingsdialoghelper.cpp ) set(antimicro_HEADERS src/mainwindow.h src/joybuttonwidget.h src/joystick.h src/joybutton.h src/joybuttontypes/joygradientbutton.h src/inputdaemon.h src/joyaxis.h src/joyaxiswidget.h src/joydpad.h src/joybuttontypes/joydpadbutton.h src/axiseditdialog.h src/xmlconfigreader.h src/xmlconfigwriter.h src/joytabwidget.h src/axisvaluebox.h src/advancebuttondialog.h src/simplekeygrabberbutton.h src/joybuttonslot.h src/joybuttontypes/joyaxisbutton.h src/aboutdialog.h src/setjoystick.h src/sdleventreader.h src/setaxisthrottledialog.h src/keyboard/virtualkeypushbutton.h src/keyboard/virtualkeyboardmousewidget.h src/keyboard/virtualmousepushbutton.h src/buttoneditdialog.h src/commandlineutility.h src/joycontrolstick.h src/joybuttontypes/joycontrolstickbutton.h src/joybuttontypes/joycontrolstickmodifierbutton.h src/joycontrolstickeditdialog.h src/joycontrolstickpushbutton.h src/joycontrolstickbuttonpushbutton.h src/joycontrolstickstatusbox.h src/advancestickassignmentdialog.h src/dpadpushbutton.h src/dpadeditdialog.h src/vdpad.h src/joydpadbuttonwidget.h src/quicksetdialog.h src/mousehelper.h src/mousesettingsdialog.h src/mousedialog/mousecontrolsticksettingsdialog.h src/mousedialog/mouseaxissettingsdialog.h src/mousedialog/mousebuttonsettingsdialog.h src/mousedialog/mousedpadsettingsdialog.h src/joytabwidgetcontainer.h src/mousedialog/springmoderegionpreview.h src/joystickstatuswindow.h src/joybuttonstatusbox.h src/qtkeymapperbase.h src/flashbuttonwidget.h src/xmlconfigmigration.h src/qkeydisplaydialog.h src/antkeymapper.h src/inputdevice.h src/mainsettingsdialog.h src/gamecontroller/gamecontrollertriggerbutton.h src/setnamesdialog.h src/autoprofileinfo.h src/addeditautoprofiledialog.h src/editalldefaultautoprofiledialog.h src/localantimicroserver.h src/extraprofilesettingsdialog.h src/antimicrosettings.h src/joybuttoncontextmenu.h src/joycontrolstickcontextmenu.h src/dpadcontextmenu.h src/joyaxiscontextmenu.h src/stickpushbuttongroup.h src/dpadpushbuttongroup.h src/joybuttonmousehelper.h src/logger.h src/inputdevicebitarraystatus.h src/applaunchhelper.h src/slotitemlistwidget.h src/eventhandlers/baseeventhandler.h src/eventhandlerfactory.h src/uihelpers/advancebuttondialoghelper.h src/uihelpers/buttoneditdialoghelper.h src/uihelpers/joytabwidgethelper.h src/uihelpers/joyaxiscontextmenuhelper.h src/uihelpers/joycontrolstickcontextmenuhelper.h src/uihelpers/dpadcontextmenuhelper.h src/uihelpers/dpadeditdialoghelper.h src/uihelpers/joycontrolstickeditdialoghelper.h src/uihelpers/gamecontrollermappingdialoghelper.h src/mousedialog/uihelpers/mouseaxissettingsdialoghelper.h src/mousedialog/uihelpers/mousebuttonsettingsdialoghelper.h src/mousedialog/uihelpers/mousecontrolsticksettingsdialoghelper.h src/mousedialog/uihelpers/mousedpadsettingsdialoghelper.h ) set(antimicro_FORMS src/mainwindow.ui src/axiseditdialog.ui src/advancebuttondialog.ui src/aboutdialog.ui src/setaxisthrottledialog.ui src/buttoneditdialog.ui src/joycontrolstickeditdialog.ui src/advancestickassignmentdialog.ui src/dpadeditdialog.ui src/quicksetdialog.ui src/mousesettingsdialog.ui src/joystickstatuswindow.ui src/qkeydisplaydialog.ui src/gamecontrollermappingdialog.ui src/mainsettingsdialog.ui src/setnamesdialog.ui src/addeditautoprofiledialog.ui src/editalldefaultautoprofiledialog.ui src/extraprofilesettingsdialog.ui src/capturedwindowinfodialog.ui ) set(antimicro_RESOURCES src/resources.qrc) # Files that require SDL 2 support. if(USE_SDL_2) LIST(APPEND antimicro_SOURCES src/gamecontroller/gamecontroller.cpp src/gamecontroller/gamecontrollerdpad.cpp src/gamecontroller/gamecontrollerset.cpp src/gamecontroller/gamecontrollertrigger.cpp src/gamecontrollermappingdialog.cpp src/gamecontrollerexample.cpp ) LIST(APPEND antimicro_HEADERS src/gamecontroller/gamecontroller.h src/gamecontroller/gamecontrollerdpad.h src/gamecontroller/gamecontrollerset.h src/gamecontroller/gamecontrollertrigger.h src/gamecontrollermappingdialog.h src/gamecontrollerexample.h ) endif(USE_SDL_2) # Platform dependent files. if(UNIX) if(WITH_X11) LIST(APPEND antimicro_SOURCES src/x11extras.cpp src/qtx11keymapper.cpp src/unixcapturewindowutility.cpp src/autoprofilewatcher.cpp src/capturedwindowinfodialog.cpp ) LIST(APPEND antimicro_HEADERS src/x11extras.h src/qtx11keymapper.h src/unixcapturewindowutility.h src/autoprofilewatcher.h src/capturedwindowinfodialog.h ) if(WITH_XTEST) LIST(APPEND antimicro_SOURCES src/eventhandlers/xtesteventhandler.cpp) LIST(APPEND antimicro_HEADERS src/eventhandlers/xtesteventhandler.h) endif(WITH_XTEST) endif(WITH_X11) if(WITH_UINPUT) LIST(APPEND antimicro_SOURCES src/qtuinputkeymapper.cpp src/uinputhelper.cpp src/eventhandlers/uinputeventhandler.cpp ) LIST(APPEND antimicro_HEADERS src/qtuinputkeymapper.h src/uinputhelper.h src/eventhandlers/uinputeventhandler.h ) endif(WITH_UINPUT) elseif(WIN32) LIST(APPEND antimicro_SOURCES src/winextras.cpp src/qtwinkeymapper.cpp src/winappprofiletimerdialog.cpp src/autoprofilewatcher.cpp src/capturedwindowinfodialog.cpp src/eventhandlers/winsendinputeventhandler.cpp src/joykeyrepeathelper.cpp ) LIST(APPEND antimicro_HEADERS src/winextras.h src/qtwinkeymapper.h src/winappprofiletimerdialog.h src/autoprofilewatcher.h src/capturedwindowinfodialog.h src/eventhandlers/winsendinputeventhandler.h src/joykeyrepeathelper.h ) LIST(APPEND antimicro_FORMS src/winappprofiletimerdialog.ui) # Add Windows specific resource file used for application icons. LIST(APPEND antimicro_RESOURCES src/resources_windows.qrc) if(WITH_VMULTI) list(APPEND antimicro_SOURCES src/qtvmultikeymapper.cpp src/eventhandlers/winvmultieventhandler.cpp # vmulti/client/client.c ) list(APPEND antimicro_HEADERS src/qtvmultikeymapper.h src/eventhandlers/winvmultieventhandler.h ) endif(WITH_VMULTI) endif(UNIX) set(USE_QT5 OFF) set(USE_QT4 OFF) if(UNIX) # Check if Qt 4 or 5 was specified using an environment variable # or by specifying -DQT_QMAKE_EXECUTABLE. # Otherwise, check for Qt libraries. if("$ENV{QT_SELECT}" EQUAL 5) set(USE_QT5 ON) elseif(QT_QMAKE_EXECUTABLE MATCHES ".*/qmake-qt5") set(USE_QT5 ON) elseif ("$ENV{QT_SELECT}" EQUAL 4) set(USE_QT4 ON) elseif(QT_QMAKE_EXECUTABLE MATCHES ".*/qmake-qt4") set(USE_QT4 ON) else() find_package(Qt5Core QUIET) if(Qt5Core_FOUND) set(USE_QT5 ON) else() find_package(Qt4 QUIET) if(QT_FOUND) set(USE_QT4 ON) else() message(FATAL_ERROR "No Qt libraries could be found.") endif(QT_FOUND) endif(Qt5Core_FOUND) endif("$ENV{QT_SELECT}" EQUAL 5) elseif(WIN32) # Use Qt5 on Windows. set(USE_QT5 ON) endif(UNIX) if(USE_QT5) message("Compiling with Qt5 support") elseif(USE_QT4) message("Compiling with Qt4 support") if(NOT WITH_X11) message(FATAL_ERROR "Cannot build application using Qt4 without X11 support.") endif(NOT WITH_X11) else() message(FATAL_ERROR "No Qt version was specified.") endif(USE_QT5) if(USE_SDL_2) add_definitions(-DUSE_SDL_2) endif(USE_SDL_2) if (WIN32) if(PERFORM_SIGNING) add_definitions(-DPERFORM_SIGNING) endif(PERFORM_SIGNING) endif (WIN32) if(UNIX) if(WITH_X11) add_definitions(-DWITH_X11) endif(WITH_X11) if(WITH_XTEST) add_definitions(-DWITH_XTEST) endif(WITH_XTEST) if(WITH_UINPUT) add_definitions(-DWITH_UINPUT) endif(WITH_UINPUT) endif(UNIX) if (UNIX) if (USE_QT5) # Find includes in corresponding build directories #set(CMAKE_INCLUDE_CURRENT_DIR ON) # Instruct CMake to run moc automatically when needed. set(CMAKE_AUTOMOC ON) find_package(Qt5Widgets REQUIRED) find_package(Qt5Core REQUIRED) find_package(Qt5Gui REQUIRED) find_package(Qt5Network REQUIRED) find_package(Qt5LinguistTools REQUIRED) QT5_WRAP_CPP(antimicro_HEADERS_MOC ${antimicro_HEADERS}) QT5_WRAP_UI(antimicro_FORMS_HEADERS ${antimicro_FORMS}) QT5_ADD_RESOURCES(antimicro_RESOURCES_RCC ${antimicro_RESOURCES}) add_subdirectory("share/antimicro/translations") include_directories(${Qt5Widgets_INCLUDE_DIRS}) add_definitions(${Qt5Widgets_DEFINITIONS}) include_directories(${Qt5Core_INCLUDE_DIRS}) add_definitions(${Qt5Core_DEFINITIONS}) include_directories(${Qt5Gui_INCLUDE_DIRS}) add_definitions(${Qt5Gui_DEFINITIONS}) include_directories(${Qt5Network_INCLUDE_DIRS}) add_definitions(${Qt5Network_DEFINITIONS}) set(CMAKE_POSITION_INDEPENDENT_CODE ON) # Add compiler flags for building executables (-fPIE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}") LIST(APPEND LIBS ${Qt5Widgets_LIBRARIES} ${Qt5Core_LIBRARIES} ${Qt5Gui_LIBRARIES} ${Qt5Network_LIBRARIES} ) else() find_package(Qt4 REQUIRED) set(QT_USE_QTNETWORK TRUE) QT4_WRAP_CPP(antimicro_HEADERS_MOC ${antimicro_HEADERS}) QT4_WRAP_UI(antimicro_FORMS_HEADERS ${antimicro_FORMS}) QT4_ADD_RESOURCES(antimicro_RESOURCES_RCC ${antimicro_RESOURCES}) add_subdirectory("share/antimicro/translations") include(${QT_USE_FILE}) add_definitions(${QT_DEFINITIONS}) list(APPEND LIBS ${QT_LIBRARIES}) endif(USE_QT5) elseif(WIN32) # Find includes in corresponding build directories #set(CMAKE_INCLUDE_CURRENT_DIR ON) # Instruct CMake to run moc automatically when needed. set(CMAKE_AUTOMOC ON) find_package(Qt5Widgets REQUIRED) find_package(Qt5Core REQUIRED) find_package(Qt5Gui REQUIRED) find_package(Qt5Network REQUIRED) find_package(Qt5LinguistTools REQUIRED) QT5_WRAP_CPP(antimicro_HEADERS_MOC ${antimicro_HEADERS}) QT5_WRAP_UI(antimicro_FORMS_HEADERS ${antimicro_FORMS}) QT5_ADD_RESOURCES(antimicro_RESOURCES_RCC ${antimicro_RESOURCES}) add_subdirectory("share/antimicro/translations") include_directories(${Qt5Widgets_INCLUDE_DIRS}) add_definitions(${Qt5Widgets_DEFINITIONS}) include_directories(${Qt5Core_INCLUDE_DIRS}) add_definitions(${Qt5Core_DEFINITIONS}) include_directories(${Qt5Gui_INCLUDE_DIRS}) add_definitions(${Qt5Gui_DEFINITIONS}) include_directories(${Qt5Network_INCLUDE_DIRS}) add_definitions(${Qt5Network_DEFINITIONS}) set(CMAKE_POSITION_INDEPENDENT_CODE ON) # Add compiler flags for building executables (-fPIE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}") LIST(APPEND LIBS ${Qt5Widgets_LIBRARIES} ${Qt5Core_LIBRARIES} ${Qt5Gui_LIBRARIES} ${Qt5Network_LIBRARIES} ) endif(UNIX) if(UNIX) if(WITH_X11) LIST(APPEND LIBS ${X11_X11_LIB}) LIST(APPEND LIBS ${X11_Xi_LIB}) endif(WITH_X11) if(WITH_XTEST) LIST(APPEND LIBS ${X11_XTest_LIB}) endif(WITH_XTEST) if(USE_SDL_2) list(APPEND LIBS ${SDL2_LIBRARIES}) else() list(APPEND LIBS ${SDL_LIBRARIES}) endif(USE_SDL_2) elseif (WIN32) if(USE_SDL_2) set(SDL2_LIBRARY "") set(SDL2_LIBRARY_DIR "") set(SDL2_INCLUDE_DIR "") set(SDL2_DLL_LOCATION_DIR "") if (MSYS OR MINGW) find_package(PkgConfig QUIET) if(PKG_CONFIG_FOUND) #include(FindPkgConfig) pkg_check_modules(SDL2 QUIET sdl2) if(SDL2_FOUND) #find_path(SDL2_INCLUDE_DIR "SDL2/SDL.h" HINTS ${SDL2_INCLUDE_DIRS}) set(SDL2_LIBRARY ${SDL2_LIBRARIES}) set(SDL2_LIBRARY_DIR ${SDL2_LIBRARY_DIRS}) set(SDL2_INCLUDE_DIR ${SDL2_INCLUDE_DIRS}) unset(SDL2_DLL_LOCATION_DIR) find_path(SDL2_DLL_LOCATION_DIR "SDL2.dll" HINTS "${SDL2_LIBRARY_DIRS}/../bin") #set(SDL2_DLL_LOCATION_DIR "${SDL2_LIBRARY_DIRS}/../bin") list(APPEND LIBS ${SDL2_LIBRARIES}) endif(SDL2_FOUND) endif(PKG_CONFIG_FOUND) endif(MSYS OR MINGW) if (NOT SDL2_LIBRARY) # Perform extra voodoo to get proper library paths and include # proper headers. file(GLOB SDL2_BASE_DIR "${PROJECT_SOURCE_DIR}/SDL2-*.*.*/") if (SDL2_BASE_DIR) unset(SDL2_LIBRARY) if(TARGET_ARCH STREQUAL "x86_64") set(SDL2_LIBRARY_DIR "${SDL2_BASE_DIR}/x86_64-w64-mingw32/lib") set(SDL2_INCLUDE_DIR "${SDL2_BASE_DIR}/x86_64-w64-mingw32/include") set(SDL2_DLL_LOCATION_DIR "${SDL2_BASE_DIR}/x86_64-w64-mingw32/bin") find_library(SDL2_LIBRARY SDL2 ${SDL2_LIBRARY_DIR}) list(APPEND LIBS ${SDL2_LIBRARY}) include_directories(${SDL2_INCLUDE_DIR}) else() set(SDL2_LIBRARY_DIR "${SDL2_BASE_DIR}/i686-w64-mingw32/lib") set(SDL2_INCLUDE_DIR "${SDL2_BASE_DIR}/i686-w64-mingw32/include") set(SDL2_DLL_LOCATION_DIR "${SDL2_BASE_DIR}/i686-w64-mingw32/bin") find_library(SDL2_LIBRARY SDL2 ${SDL2_LIBRARY_DIR}) list(APPEND LIBS ${SDL2_LIBRARY}) include_directories(${SDL2_INCLUDE_DIR}) endif(TARGET_ARCH STREQUAL "x86_64") endif(SDL2_BASE_DIR) endif(NOT SDL2_LIBRARY) add_definitions(-DUNICODE -D_UNICODE) endif(USE_SDL_2) list(APPEND LIBS "psapi") if(WITH_VMULTI) include_directories("${PROJECT_SOURCE_DIR}/vmulti/inc") list(APPEND LIBS "hid" "setupapi") endif(WITH_VMULTI) endif (UNIX) include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories("${PROJECT_SOURCE_DIR}/src") if(UNIX) # Store executable in a bin subdir. Needed here so translations can be loaded. set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") endif(UNIX) if(USE_QT5) if(UNIX) add_executable(antimicro ${antimicro_SOURCES} ${antimicro_FORMS_HEADERS} ${antimicro_RESOURCES_RCC} ) elseif(WIN32) # The WIN32 is required to specify a GUI application. add_executable(antimicro WIN32 ${antimicro_SOURCES} ${antimicro_FORMS_HEADERS} ${antimicro_RESOURCES_RCC} src/antimicro.rc ) endif(UNIX) else() add_executable(antimicro ${antimicro_SOURCES} ${antimicro_HEADERS_MOC} ${antimicro_FORMS_HEADERS} ${antimicro_RESOURCES_RCC} ) endif(USE_QT5) # Add link libraries. #message(${LIBS}) target_link_libraries(antimicro ${LIBS}) # Specify out directory for final executable. if(UNIX) install(TARGETS antimicro RUNTIME DESTINATION "bin") elseif(WIN32) install(TARGETS antimicro RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}) endif(UNIX) if(UNIX) install(FILES src/images/antimicro.png DESTINATION "share/pixmaps") install(FILES other/antimicro.desktop DESTINATION "share/applications") install(FILES other/antimicro.xml DESTINATION "share/mime/packages") endif(UNIX) # Add man page for *nix platforms. if(UNIX) add_subdirectory(other) # Only way to force install target to be dependent on manpage. install(CODE "execute_process(COMMAND ${CMAKE_BUILD_TOOL} manpage WORKING_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}\")") if(APPDATA) # Only way to force install target to be dependent on appdata. install(CODE "execute_process(COMMAND ${CMAKE_BUILD_TOOL} appdata WORKING_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}\")") endif(APPDATA) endif(UNIX) # uninstall target configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) # Only way to force install target to be dependent on updateqm. install(CODE "execute_process(COMMAND ${CMAKE_BUILD_TOOL} updateqm WORKING_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}\")") # Use this to use some variables created here in the actual project. # Modify the config.h.in file using the appropriate variables. configure_file( "${PROJECT_SOURCE_DIR}/src/config.h.in" "${PROJECT_BINARY_DIR}/config.h" ) # Copy current Changelog file to location that the resource file expects. file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/Changelog DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/src/) if(WIN32) #if(TARGET_ARCH STREQUAL "x86_64") # # Copy SDL2.dll to find installation directory. # add_custom_target(copy_sdl_dll # COMMAND ${CMAKE_COMMAND} -E copy "${SDL2_BASE_DIR}/x86_64-w64-mingw32/bin/SDL2.dll" ${CMAKE_CURRENT_BINARY_DIR} # ) #else() # # Copy SDL2.dll to find installation directory. # add_custom_target(copy_sdl_dll # COMMAND ${CMAKE_COMMAND} -E copy "${SDL2_BASE_DIR}/i686-w64-mingw32/bin/SDL2.dll" ${CMAKE_CURRENT_BINARY_DIR} # ) #endif(TARGET_ARCH STREQUAL "x86_64") add_custom_target(copy_sdl_dll COMMAND ${CMAKE_COMMAND} -E copy "${SDL2_DLL_LOCATION_DIR}/SDL2.dll" ${CMAKE_CURRENT_BINARY_DIR} ) # Obtain location of Qt5 DLL files and assign them to a list. # This list will only be used for Release builds. get_target_property(QTCORE_DLL_LOCATION Qt5::Core LOCATION) string(REPLACE "/Qt5Core.dll" "" QTCORE_DLL_LOCATION ${QTCORE_DLL_LOCATION}) set(EXTRA_QT_DLL_FILES "${QTCORE_DLL_LOCATION}/Qt5Core.dll" "${QTCORE_DLL_LOCATION}/Qt5Gui.dll" "${QTCORE_DLL_LOCATION}/Qt5Network.dll" "${QTCORE_DLL_LOCATION}/Qt5Widgets.dll" ) find_library(EXTRA_DLLS_PTHREAD NAMES "libwinpthread-1.dll" ) find_library(EXTRA_DLLS_LIBCPP NAMES "libstdc++-6.dll" ) # Don't think find_library will handle versioned DLLS, so we'll try each one until we find something foreach( ICU_VER 51 52 53 54 55 56 57 58 59 ) find_library(ICU_DT_DLL NAMES "icudt${ICU_VER}.dll") find_library(ICU_IN_DLL NAMES "icuin${ICU_VER}.dll") find_library(ICU_UC_DLL NAMES "icuuc${ICU_VER}.dll") endforeach( ICU_VER ) list(APPEND EXTRA_DLL_FILES ${EXTRA_QT_DLL_FILES} ${EXTRA_DLLS_PTHREAD} ${EXTRA_DLLS_LIBCPP} ${ICU_DT_DLL} ${ICU_IN_DLL} ${ICU_UC_DLL} ) # Copy relevant DLL files depending on the chosen architecture. if(TARGET_ARCH STREQUAL "x86_64") find_library( GCC_DLL "libgcc_s_seh-1.dll" ) list(APPEND EXTRA_DLL_FILES ${GCC_DLL} "${SDL2_BASE_DIR}/x86_64-w64-mingw32/bin/SDL2.dll" ) else() find_library( GCC_DLL "libgcc_s_dw2-1.dll" ) list(APPEND EXTRA_DLL_FILES ${GCC_DLL} "${SDL2_BASE_DIR}/i686-w64-mingw32/bin/SDL2.dll" ) endif(TARGET_ARCH STREQUAL "x86_64") # Not a DLL file, but needs to travel with SDL2.DLL list(APPEND EXTRA_DLL_FILES "${SDL2_BASE_DIR}/README-SDL.txt") # Target to copy Qt DLL files. add_custom_target(install_extra_dlls) # Create destination directory if it does not exist. add_custom_command(TARGET install_extra_dlls PRE_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_INSTALL_PREFIX}/" ) foreach(CURRENT_DLL_FILE ${EXTRA_DLL_FILES}) add_custom_command(TARGET install_extra_dlls PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CURRENT_DLL_FILE} "${CMAKE_INSTALL_PREFIX}/" ) endforeach() # Target to copy qwindows.dll platforms file. add_custom_target(install_platforms_dll) add_custom_command(TARGET install_platforms_dll PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy "${QTCORE_DLL_LOCATION}/../plugins/platforms/qwindows.dll" "${CMAKE_INSTALL_PREFIX}/platforms/qwindows.dll" ) # Combine the two targets into a single target that will be used # while bundling the program. add_custom_target(install_dlls) add_dependencies(install_dlls install_extra_dlls install_platforms_dll ) # Copy bundled Qt translation files. SET(QT_TRANSLATION_PATH "${QTCORE_DLL_LOCATION}/../translations/" ) file(GLOB QT_TRANSLATION_FILES "${QT_TRANSLATION_PATH}qt_[^help]*.qm") add_custom_target(copy_qt_translations) foreach(CURRENT_QM_FILE ${QT_TRANSLATION_FILES}) set(CURRENT_QM_FILENAME "") string(REPLACE ${QT_TRANSLATION_PATH} "" CURRENT_QM_FILENAME ${CURRENT_QM_FILE}) add_custom_command(TARGET copy_qt_translations PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy "${CURRENT_QM_FILE}" "${CMAKE_INSTALL_PREFIX}/share/qt/translations/${CURRENT_QM_FILENAME}" ) endforeach() # Sign final executable if(PERFORM_SIGNING) install(CODE "execute_process(COMMAND \"C:/Program Files (x86)/Windows Kits/8.1/bin/x64/signtool.exe\" sign /v /a /s ROOT /n antimicro ${CMAKE_INSTALL_PREFIX}/antimicro.exe)") endif(PERFORM_SIGNING) # Set variables needed for MSI building. set(MSIFOLDER "${PROJECT_SOURCE_DIR}/windows") set(WIXENV $ENV{WIX}) # Use a different file for each architecture due # to some DLL differences. if(TARGET_ARCH STREQUAL "x86_64") set(WIXWXS "${MSIFOLDER}/antimicro_64.wxs") else() set(WIXWXS "${MSIFOLDER}/antimicro.wxs") endif(TARGET_ARCH STREQUAL "x86_64") set(WIXOBJ "${MSIFOLDER}/antimicro.wixobj") # Use version number in output file name. set(MSIFILENAME "${ANTIMICRO_MAJOR_VERSION}.${ANTIMICRO_MINOR_VERSION}") if(ANTIMICRO_PATCH_VERSION AND NOT ANTIMICRO_PATCH_VERSION EQUAL 0) set(MSIFILENAME "${MSIFILENAME}.${ANTIMICRO_PATCH_VERSION}") endif(ANTIMICRO_PATCH_VERSION AND NOT ANTIMICRO_PATCH_VERSION EQUAL 0) # Change output file depending on the target architecture. if(TARGET_ARCH STREQUAL "x86_64") set(WIXMSI "${MSIFOLDER}/antimicro-${MSIFILENAME}-win64.msi") else() set(WIXMSI "${MSIFOLDER}/antimicro-${MSIFILENAME}-win32.msi") endif(TARGET_ARCH STREQUAL "x86_64") if(NOT WIXENV) # Display message when WIX is not set up. No extra target will be added. message("MSI package building not possible: WIX environment variable not defined.") else() # Target to build .msi installer file. add_custom_target(buildmsi) # Change arch value passed to candle.exe set(WIXARCH "") if(TARGET_ARCH STREQUAL "x86_64") set(WIXARCH "x64") else() set(WIXARCH "x86") endif(TARGET_ARCH STREQUAL "x86_64") add_custom_command(TARGET buildmsi PRE_BUILD COMMAND "${WIXENV}\\bin\\candle.exe" ${WIXWXS} -out ${WIXOBJ} -sw1113 -arch ${WIXARCH} && "${WIXENV}\\bin\\light.exe" ${WIXOBJ} -out ${WIXMSI} -sw1076 -spdb ) set(WIXFILES ${WIXOBJ} ${WIXMSI}) set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${WIXFILES}") endif(NOT WIXENV) # Copy extra files to include in the final archive. install(FILES gpl.txt Changelog README.md ProfileTips.md DESTINATION ${CMAKE_INSTALL_PREFIX}) endif(WIN32) antimicro-2.23/Changelog000066400000000000000000001136711300750276700152570ustar00rootroot000000000000002016-11-05 Jeff Backus Version 2.23 * Fixed portable version. (issue #37) * Added ability to specify logging level and file in config dialog. (issue #50) * Updated build system to find libraries on Windows systems instead of using explicit paths. (issue #43) * Added relevant window information to debug messages related to auto profiles. (issue #46) * Fixed issue with anything in profile name after first period being truncated. (issue #70) * Fixed issues with SDL 2.0.5 on all platforms. (issue #71) * Added support for additional small-case Latin characters when using Xtest. (issue #49) * Added inclusion of README-SDL.txt when building Windows distributables. 2016-07-30 Jeff Backus Version 2.22 * Fixed a segfault on startup issue affecting some Linux distributions * Fixed issues with SDL 2.0.4 on Windows. * Updated documentation and URLs in code to note transition in management. * Updated translations and added new ones. * Added code to revert all virtual buttons to beginning of slot list before a set switch. * Build system updates * Fixed a bug where invalid joystick was inserted into device list. * Modified to hide turbo mode combobox for regular buttons * Changed to allow blank config for auto profile entries again. * Fixed matching by process filename in AutoProfileWatcher 2016-01-10 Travis Nickles Version 2.21 * Changed unplug routine slightly. The old behavior was slightly wrong anyway but the old behavior did not work with SDL 2.0.4. * Custom Qt builds are being used for the 64 bit Windows build and noSSE Windows build. * Updated Windows build to use Qt 5.5.1. * Updated Windows build to use SDL 2.0.4. This should clear up a couple of problems for people running Windows 10. * Changes to some acceleration curves. Both the output values and the input offsets were changed to make mouse movement looser. * Removed First Run Wizard from program. In the end, that wizard was causing more problems for other users than it was worth. * Add arguments property for Execute slots. * Allow a real absolute mouse to be used with uinput support. Previously, relative mouse movement was being used to fake an absolute position for the mouse pointer. The WiimoteGlue project provided a way to allow uinput to send absolute mouse pointer events when using uinput. * Fixed set changing with analog triggers. 2015-10-19 Travis Nickles Version 2.20.2 * Change Enhanced Precision and Easing Quad/Cubic acceleration curves * Skipped straight to 2.20.2 since version 2.20 actually had 2.20.1 marked as its version in the application 2015-10-10 Travis Nickles Version 2.20 * Replace usage of QElapsedTimer with QTime for mouse movement calculations. * Start using Qt 5 with Ubuntu Vivid package. * Change XTest pointer acceleration when starting the program. * Allow release slot to have a 0 ms interval. This is useful for people who use a gamepad poll rate less than 10 ms. * Change minimize to tray code to work better with later versions of Gnome 3 and Unity. * Transfer travel distance axis changes when switching sets. 2015-09-29 Travis Nickles Version 2.19.3 * Japanese translation provided by tou omiya. * Make sure Game Controller Mapping dialog window reads raw joystick events. This should fix problems regarding improper mapping causing controller elements to no longer be mappable. * Make Set Change slots activate on button release instead of button press. * Tweaked the locking being performed in various portions of the program. * Fixed a problem with blank info window appearing when escaping from window capture utility dialog. * Fixed issues with document-save-as icon staying displayed after resetting a profile. * Fixed "Media Next" key binding for virtual keyboard. * Fixed various issues regarding binding slots in the Advanced Edit dialog window. 2015-09-15 Travis Nickles Version 2.19.2 * Add --next to allow multiple profiles to be loaded in one command call. * Add a flag to settings file when wizard is finished. Don't depend on any other settings being changed during an application run. * Fixed issue with inserting Pause slots. * Fixed issue with blank application filepath being matched for auto profile support. 2015-09-03 Travis Nickles Version 2.19.1 * Fixed SDL 1.2 build support. * Fixed issue with SDL thread not being stopped due to connections not being made in some situations. * Fixed loading of a profile from a second instance. * Fixed problem with main window not being populated after the App Settings Wizard was finished. * Fixed another portion of the program that assumed that a controller would be connected at startup. Fixes excessive CPU load. 2015-08-31 Travis Nickles Version 2.19 * Added curve options for extra acceleration. * Fixed bug when App Settings Wizard would pop up when not needed. * Simplified Chinese translation updated. 2015-08-24 Travis Nickles Version 2.18.2 * Fixed overly active timer used to reset acceleration distances when no events are returned from SDL in a given gamepad poll. * Sebian translation updated by Jay Alexander Fleming. * Changed behavior of 4 Way Cardinal mode for DPads. Diagonals are no longer counted as a dead zone. This change is more likely temporary. Up+Right - Up, Down+Right - Right, Down+Left - Down, Up+Left - Left 2015-08-18 Travis Nickles Version 2.18.1 * Fixed some threading issues when using X11. * Fixed excessive CPU load on startup when no controller is connected. 2015-08-15 Travis Nickles Version 2.18 * Perform event simulation in its own thread. Timer used for mouse speed calculations has improved as a result. * Slow down Enhanced Precision mouse acceleration curve slightly. Changes were mainly due to overall mouse emulation being tweaked. * Distributing 64 bit builds for Windows again. * Using a simulated event to click the minimize button in title bar now works on Windows. The move to using a dedicated thread for event simulation allows that to work now. * Simplified Chinese translation added thanks to zzpxyx. 2015-08-02 Travis Nickles Version 2.17 * Changed Enhanced Precision acceleration curve. The curve has been slowed down slightly. * Changed how initial mouse movement is performed when the gamepad poll rate and the mouse refresh rate differ. * Flash interface buttons after restoring the main window from the tray icon. * Tweaked mouse movement remainder routine. Remainders now only apply when the direction along an axis is the same. * Raised maximum cycle reset time to 60 seconds. * Fixed improper cycle reset interval. 2015-07-22 Travis Nickles Version 2.16 * Loosen initial mouse movement experienced after going outside the dead zone. * Added option in the mouse settings section that would allow antimicro to reset the acceleration values being used for the uinput virtual mouse pointer. This is useful after playing older Linux games that change the acceleration settings for all mouse pointers after a game exits. Postal 2 and Doom 3 are two examples of games in my game library that exhibit this behavior. * Queue all events before performing any actions. The priority of various events has been changed as well. * Added option to change the gamepad poll rate used by the application. By default, the old 10 ms poll rate will be used. * Bundle a few backup icon files. Mainly useful on SteamOS since the themes used don't bundle a couple of essential icons that are expected to be present. * Compiled vmulti support into Windows build. The driver is not currently provided. The program needs to be started with the arguments --eventgen vmulti. * Temporarily stop packaging a 64 bit version of the program for Windows. Unfortunately, the version of Qt being used has a problem regarding timer accuracy that is not experienced with the 32 bit version of Qt being used. At this time, working around the problem is not feasible so there will be no 64 bit release. Please use the 32 bit version. * Change shortcuts used for the .msi package. * Bundle Qt translation files for Windows version. 2015-06-27 Travis Nickles Version 2.15 * Changed routine for extra acceleration for mouse movement. The new version is a bit faster and more responsive than the previous version. * Added release circle setting for spring mouse mode. This can be used to have the mouse return to a region around a character based on the last detected direction of an analog stick. * Added a sub-menu to the virtual keyboard. Some multimedia and browser keys can now be selected. * Added Execute slot type. A program can be set to launch when a slot is activated. * Added Text Entry slot type. You can now have a string of text typed when a slot is activated. This can be useful for inputting common commands in games. * Added proper interpolation to determine the start of diagonal regions of analog sticks. This is used for mouse movement in order to determine the proper starting dead zone point. * Changed Enhanced Precision mouse acceleration curve. The new changes in the curve should be much looser than before. * Fixed --unload command line option. Enforce reloading of config file when finished. * Fixed issue with spring mouse mode where the mouse would temporarily return to center when switching stick directions quickly. * Fixed some bindings in the virtual keyboard when using SendInput for the event generator. * Fixed issue with widgets used to update stick and dpad delay. The spinbox can now be used to edit the delay. * Reduced multiple instances of some objects. Reduces memory usage slightly. 2015-05-01 Travis Nickles Version 2.14 * Refactored extra axis acceleration. This revision uses individual gamepad polls again. Other changes in the code have made switching back feasible. With minor adjustments, the mouse will be looser but very controllable. * Added longer duration for extra axis acceleration. This allows extra acceleration to be performed over a period of time as opposed to just one gamepad poll. * Changed key repeat routine when using SendInput on Windows. Key releases restart the last active key repeat delay. * Now using Qt64-NG for the 64 bit Windows builds. * Initial experiments with vmulti support in the Windows version. Using that driver would allow antimicro to use a virtual keyboard and mouse rather than using SendInput. That would allow antimicro to work around UAC problems and anti-cheat programs. Support is not currently compiled into the Windows builds due to not being able to properly distribute the vmulti driver. * Do not write empty names tag in profiles if no custom button names have been specified. * Allow mouse history buffer size to go up to 100. * Allow diagonal range to go up to 90 degrees. * Remove old mouse speeds from mouse history buffer if stick has been returned to the dead zone. History buffer will be filled with zeroes. * Omit hotplugging dependent code when compiling against SDL 1.2. * Fixed dpad pointer bug when certain QueuedConnection slots are executed. 2015-03-31 Travis Nickles Version 2.13 * Updated extra axis acceleration routine. Now, extra acceleration is calculated after an axis has stopped moving past the assigned threshold in one gamepad poll. * Stick presets now change the diagonal range of a stick. This is mainly beneficial for mouse control changes so that 65 degrees is used by default. * Added a screen selector for Spring mouse mode in settings menu. * Added a small language selection portion to the settings menu. * Added a small logger. Please run antimicro with "--log-level debug" in order to get output about button presses. 2015-03-22 Travis Nickles Version 2.12.1 * Implemented a small wizard that will be run when antimicro is launched for the first time. It currently only has a page for editing some of the mouse settings and a page for associating antimicro with .amgp files on Windows. * Show slots that are active for a stick modifier button on the main interface. The text for the main stick direction buttons will be prefixed with the currently active slots of the stick modifier button. * Corrected issue with stick and dpad events not getting activated on a set change. Events were being queued but not executed. 2015-03-15 Travis Nickles Version 2.12 * Added option for extra mouse acceleration. Enabling that option will increase the speed of the mouse based on the amount an axis has travelled in one gamepad poll and the set multiplier. This will greatly affect how the mouse behaves and it will make mouse movement looser. Using this feature can be problematic if the analog stick on your controller is worn out and loose. * Corrected issue with extra mouse sync events occurring when not needed (0,0 events). This change seems to have smoothed out mouse movement on the low end of an axis a bit. * Tweaked controller unplug workaround to still invoke release events for axes and buttons. For triggers, the release value is modified from what is provided by SDL so an unplug event will cause a release event to occur for the triggers. 2015-02-25 Travis Nickles Version 2.11.1 * Added workaround to allow gamepad unplugging on Windows to not activate bindings for the triggers. This was caused by the way controller unplugging is handled by SDL (primarily with the Windows version). SDL sends a release value for all elements of an unplugged joystick a brief period before sending the expected SDL_JOYDEVICEREMOVED event. The problem is that the released value used for triggers assumes that the dead zone is half the trigger's full range. This would cause bindings for triggers to usually activate for a brief period before SDL would send the final SDL_JOYDEVICEREMOVED event which would then deactivate those bindings. * Changes for the portable Windows version. Allow relative profile paths for use in the portable package on Windows. Associate profiles registry change prompt skipped. * Queue stick and dpad events. Allows for better control of 8-way sticks and dpads. 2015-02-07 Travis Nickles Version 2.11 * Adjusted the Enhanced Precision, Easing Quadratic, and Easing Cubic mouse acceleration curves. The low end of each curve has been loosened a bit and the rest of the curves have been adjusted accordingly. Comparing the two versions, the resulting mouse speed for a given axis point is slightly lower in the new versions for most of the curve. The extreme low end and the extreme high end of the curves will be slightly faster. * Updated Qt to version 5.4.0 for the Windows builds. * Compiled a 64 bit version for Windows thanks to the Qt-x64 project. * Added a set changing slot. * Added AppData for use when packaging on Linux thanks to Jeff Backus. * Fixed bug with mouse wheel event methods for axes which resulted in negative values being passed to the event timer. 2014-12-29 Travis Nickles Version 2.10.1 * Changed event handler fallback method under Linux. * Changed interface of Assignments page in Advanced Button Dialog. * Reset set number upon changing profiles. * Added "About Development" tab to About Dialog. * Fixed dynamic text resizing in Button Edit Dialog under Linux. * Fixed launching a second instance in order to load a profile in the first instance. 2014-12-10 Travis Nickles Version 2.10 * Changed allowed values for easing duration. The minimum value has been lowered to 0.0 and the maximum value has been increased to 5.0. * Added a stick modifier button. This button is primarily meant to be used to assign walk/run functionality to an analog stick. Instead of having to create distance zones and assign keyboard modifier keys to each stick button, you can now make the assignment on the stick modifier button and it will apply to the stick as a whole. It makes assigning walk/run functionality to an analog stick much less cumbersome. The DreadOut demo has already shown a use case where only the stick modifier button was needed due to the demo not handling running when using the left stick on an Xbox 360 controller. * Increased idle mouse timer interval to 100 ms. * Added a load profile slot. You can now tell the program to load a different profile upon pressing a button. * Added gradient functionality for the high end of the Easing Quadratic and Easing Cubic mouse acceleration curves. * Raise process priority on Windows. Now, the antimicro process will run with High priority. This allows internal timers to work better and be less susceptible to the activity of other running programs. On Linux, the priority of the main thread has been increased. * Take multiple direction buttons into account when assigning set switching to stick buttons. * If uinput is enabled but not usable at runtime then XTest will be used as a fallback option for the Linux version. * Tweaked Gradient and Pulse turbo modes to make them a bit tighter. A lower delay will be needed in profiles to achieve a similar control from previous versions. On the plus side, this has been tested to work with FlatOut 2 fairly well. It is good enough to use and actually win some races against AI opponents. * Added analog control for mouse wheel buttons that are mapped to an axis button. * Tweaked mouse movement code to improve mouse accuracy. This is mainly due to discovering the QElapsedTimer class that is included in Qt. * Fixed middle mouse button binding when using the uinput event handler on Linux. * Fixed memory leaks that were discovered by Valgrind. 2014-11-19 Travis Nickles Version 2.9 * Added mouse refresh rate as an option. Please be mindful of how your system behaves if you set the refresh rate to a low value like 1 ms. In the worst case scenario, you could end up dedicating one CPU core on just the antimicro process. Also, on Windows, you will want to make sure to disable the "Enhance Pointer Precision" option if you use a low value otherwise Windows will severely slow down the mouse pointer. * Added an application level mouse smoothing option. The older button level smoothing option has been removed. The old option didn't do much since it only dealt with the partial distance remainder. * Button responsiveness has been improved. The old mouse movement code was creating a bottleneck for button processing which would result in a slight delay. * Changed mouse movement code. The overall mouse movement should be smoother now. * Allow the Windows setting "Enhance Pointer Precision" to be disabled while antimicro is running. This will make sure Windows does not directly manipulate the mouse events sent to the system. This will allow mouse control on an analog stick to be more accurate on Windows. * Changes to Auto Profile to allow more variables for matching. Multiple window properties can be specified which will cause antimicro to count an entry as a match only if all specified properties match. * Changed how windows are grabbed in X on Linux. * Minor fix for Gradient and Pulse turbo modes. There were times when the timer interval controlling those modes could be negative and cause problems. 2014-11-05 Travis Nickles Version 2.8.1 * Fixed some buttons in virtual keyboard when program is using uinput support. * Fixed Update Joysticks option for SDL 1.2 users. 2014-10-28 Travis Nickles Version 2.8 * Added delay settings for analog sticks and dpads. This is meant to keep some games from overreacting when switching directions quickly. A delay is especially useful for games that utilize a dash on a key double tap. This will also be very useful while playing rougelike games. The new delay setting allows for more responsive controls than the old alternative of using hold zones on individual direction buttons. * Added two new mouse acceleration curves: Easing Quadratic and Easing Cubic. These new mouse acceleration curves are meant to mimic the camera control that is used for gamepad support in some recent first person shooters such as Borderlands 2. Once a stick direction has reached a threshold (80%) then the mouse speed will gradually accelerate over a period of time before the mouse speed reaches its peak. The duration of the easing method is set at 0.50 seconds by default but the setting is configurable per button. * Major refactor to mouse event generation. The new routine requires fewer system resources and it is more accurate. * Made uinput support a runtime option for Linux users. The program can now be compiled with both XTest and uinput support and the event generator can be specified using the --eventgen flag. It defaults to XTest if available. The option is only available when the program is compiled with both XTest and uinput support. * Added right click context menus for buttons in main interface. * Fixed issue with Game Controller Mapping dialog. Controller DPads that are exposed as 4 buttons can now be bound to the DPad of an SDL Game Controller. * Fixed an issue with incorrect profile names being displayed in the profile combobox. * Fixed issue introduced in version 2.7 regarding mouse movement calculations for the left direction of analog sticks. A major portion of the safe zone for that direction was being skipped. * Changed button groups in the main interface to update immediately when a stick or dpad mode has been changed. * Initial removal of old joystick abstraction support in interface when using SDL 2. 2014-10-14 Travis Nickles Version 2.7 * Added a UAC workaround for use in Windows. antimicro can be restarted as Administrator in case a game is running with elevated permissions and the events generated by antimicro are not detected by a game. * Added more key aliases for uinput support. * Force higher dead zones for axes in Game Controller Mapping window. * Fixed virtual keyboard in Button Edit Dialog window for Linux users utilizing XTest support. * Display some minor mouse stats in Mouse Settings dialog. * Alter Analog Stick dialog window to show some new stats. Also, show square stick coordinates as well as adjusted circle stick coordinates. * Added square stick to circle stick conversion. * Fixed issue with VK_LSHIFT and VK_RSHIFT aliases not being saved properly on Windows. * xinput is used for the uinput virtual pointer in order to disable mouse acceleration for the pointer. This allows spring mode to work as intended. * Added some code to guess which axes of a gamepad should be considered triggers by default while in old Joystick mode. The initial values of axes are taken from SDL and those are used as the point of the axes while centered. If the initial value of an axis is below -30,000 then an axis is considered to be a trigger. 2014-09-16 Travis Nickles Version 2.6 * Added two new Turbo modes. Gradient mode is used to change the key press time depending on the position of an axis (useful for racing games). Pulse mode is used to change how many times a key press is invoked depending on the position of an axis (scrolling in a web browser using arrow keys). * Fixed profile resetting in a couple of places. * A Russian translation has been provided by Dima Koshel. * Added option to invoke Game Controller mapping window from command line. The final mapping string will be printed to stdout. This is useful for saving a SDL_GAMECONTROLLERCONFIG for your controller that can be used system wide. Any SDL 2 game can then be set up to use that mapping and it can be changed if needed. * Profiles now use a unique .amgp file extension. Older xml profiles will continue to be supported. * Fixed spring mouse mode so that it uses proper axis distance values. * Set changing has been fixed for analog sticks and virtual dpads. * EXPERIMENTAL. uinput support has been added to the source code. Binary Linux packages will continue to utilize XTest for event generation for the time being. If you would like to test uinput integration then you will have to compile the program using -DWITH_UINPUT=ON and -DWITH_XTEST=OFF when running cmake. Playing Warsow 1.51 in Linux using antimicro requires using uinput integration. Also, keys can now be pressed in a tty. 2014-08-01 Travis Nickles Version 2.5 * Fixed packaging the Windows version so the program will work on Windows XP again. * Delay rendering of flashing buttons. This helps improve controller responsiveness when the main window is not hidden. * Reduced the size of written profiles. Only changed values are now stored in profiles. * Updated German translation provided by phob and Leonard Koenig. * Allow a profile to be listed as the final argument on the command line. Ex: antimicro ~/antimicro-profiles/profile.xml. * Added diagonal distance support for distance slots for Standard mode on Sticks and DPads. This was necessary for some modifier assignments to work properly. The best example is for assigning walking in Half-Life 1. * Allow generated events to be sent to a different X display than the application is running on. This change was mainly done to better work with SteamOS. AntiMicro can be run via ssh with X tunneling in order to configure profiles on one system but the program will send events to the X display that is running Steam and games. * Auto Profile support has improved for SteamOS. Application grabbing can now be done while in the SteamOS BPM Session. Steam BPM can be grabbed as well. * Only show active or soon to be active slots for buttons in the main window. The text displayed on the buttons will update when a new zone has been reached due to using slots such as distance or hold. * Allow no profile to be assigned to an application for an Auto Profile entry. This means that the program will choose an empty profile when the application for that Auto Profile entry has focus. This will help with disabling AntiMicro for applications that already have controller support. * Controller Mapping dialog now stops processing events until all elements have been released on a controller. 2014-05-30 Travis Nickles Version 2.4 * Relative spring mode added. * Key repeating changes in Windows. * Updated Windows version to use Qt 5.3.0. * Set copying added. * Corrected application checks used for Auto Profile support in Windows. 2014-05-23 Travis Nickles Version 2.3.3 * Tweaked Enhanced Precision mouse acceleration curve. * Tweaked "all" option in Auto Profile. No profile assigned to "all" now implies that a blank configuration should be loaded. * Manpage created by Jeff Backus. * Migrated to the CMake build system. 2014-05-15 Travis Nickles Version 2.3.2 * Fixed problem with old profiles not being usable in the program. 2014-05-13 Travis Nickles Version 2.3.1 * Added new Enhanced Precision mouse curve. It is now the default mouse curve. The new mouse curve will make the cursor move slowly towards the low end of an axis and the cursor movement will be accelerated towards the high end of an axis. * Added unsaved profile dialogs. * Added key repeating behavior under Windows. * Increased maximum turbo interval. * Added more options to the Edit Settings dialog. * Added profile name display editing. * Fixed invalid pointer issue for Hold events. 2014-05-02 Travis Nickles Version 2.3 * Added a daemon mode. * Added joystick profile compatibility parser for game controllers. Old profiles are now usable when using SDL Game Controller support. Old profiles have to be mapped against the same controller that is connected. * Added cycle reset support. Sequences with cycles can now get returned to the first cycle zone in a sequence after a period of time. * Changed Auto Profile support to work properly in SteamOS while running the SteamOS Big Picture Mode session. On many tested games (Duke Nukem 3D, SuperTux, World of Goo), the game had to be run in windowed mode in order for Auto Profile support to be able to detect the application. It is recommended that you run games in windowed mode when using Auto Profile support in the SteamOS BPM session. This is not an issue when running the Steam desktop client in desktop mode. * Added a delay slot type. A delay slot can be used for key presses in a key combination. Unlike other macro slots, slots placed before a delay slot will remain active after the specified time has passed. * Added option to allow the program to start on Windows startup. * Changed dialogs for secondary set buttons to display the set that the button is currently in. * Changed turbo mode to give more control. Key presses are now given more time to be active. Key presses and releases now run for a duration of t/2 seconds. * Altered tray menu to display a single list when only one controller is connected. An option has been added to allow for a single list to also be used when multiple controllers are detected. * Fixed issue with Windows XP Auto Profile workaround. On the plus side, now the program is confirmed to work in Windows XP. * Fixed issues with Auto Profile support saving and precedence. 2014-04-19 Travis Nickles Version 2.2 * Added example controller display to Game Controller Mapping dialog window. * Added Auto Profile support. Allows for profiles to be associated with specific applications. * Added button icons in Windows version. * Added a press time slot type. That slot type is used to have keys active for a specific period of time. * Allow Pause slots to have a 0 second interval. Allows for a forced key release. * Windows version is now built with SDL 2.0.3. * Fixed 8-Way D-Pad mode. * Fixed preset options in various dialogs to account for new aliases. * Fixed ampersand rendering in set buttons. * Fixed spring mouse mode dimension support. * Fixed spring mouse mode accuracy under Windows. 2014-02-28 Travis Nickles Version 2.1 * Added new stick and dpad modes. * Added set names. * Minor fixes for Windows. * Fixed QSettings usage to reduce reads and write to config file. 2014-02-10 Travis Nickles Version 2.0.1 * Active keyboard keys now use a reference count. This will be useful for keeping modifier keys held when moving a stick from a diagonal direction to a cardinal direction. This will allow a run to be maintained properly. * A release delay has been added to release slot events. This is needed for some games where a key press and release might happen too quickly for a game, such as The Elder Scrolls IV: Oblivion, to catch it. * Altered data sent to SendInput under Windows. The change should allow games that rely exclusively on scancode data to detect keyboard key presses now. Previously, keyboard emulation would not work while playing The Elder Scrolls IV: Oblivion on Windows. * Improved key associations under Windows. VK_OEM_* keys associations are now generated at runtime which will allow associations to be more layout independent. * Changed some portions of the Windows version so that the Numpad Enter key can be emulated. * The recent profile list is now updated when a profile is added or removed from the list as opposed to when the program is closed. This allows the list to be in sync while utilizing hotplugging. 2014-01-04 Travis Nickles Version 2.0 * Migrated profiles to use Qt key values as opposed to using native key code values. Allows for better cross-platform compatibility. Current joystick profiles will be migrated when first loaded by the program. * Program can now be compiled against SDL 2. * The Game Controller API provided by SDL 2 has been integrated into the application. The API is used to abstract various gamepads to a unified standard. Profiles made against the Game Controller API can be used with any controller that is supported. Unsupported controllers will have to be mapped in the program. * A simple Game Controller mapping window has been made so people that are using an unsupported controller can map that controller so that it can be used with the Game Controller API. Any saved mapping string will be loaded into SDL when AntiMicro is first launched or when you select the "Update Joysticks" option in the main window. * Any new saved profile will include the device type that it is associated with in the filename. Joysticks and game controllers use slightly different file specifications. * Joystick hotplugging support has been added thanks to SDL 2. * On Windows, XInput support is now available. This allows the Xbox 360 controller guide button to be usable and both gamepad triggers can be used at the same time. Previously, only DirectInput was being used so both triggers were being mapped to one axis so they would negate each other if used at the same time. This problem would really affect people trying to play Call of Duty with a 360 controller when the "Hold Aim Down the Sight" option is enabled in the game. * The list of recent profiles is now tied to a joystick GUID or joystick name if the GUID is not available (compiled against SDL 1.2). * Program options window has been made. For right now, it is only being used to allow users to be able to disable Game Controller integration for specific controllers. * Mouse events are queued before a mouse event is sent to the system. This allows for smoother diagonal mouse movement. This really helped improve camera control for me in Warsow. * Key checker dialog has been made so you can check the alias values that are being used for keyboard keys. This is mainly for debugging purposes. If you find that a keyboard key that you use does not have a built-in alias, please let me know so an alias can be added. Although, the key can still be used in the program and saved to a profile. The major downside is that a profile that uses an unsupported key will not be cross-platform compatible. 2013-12-13 Travis Nickles Version 1.2 * Improved while held set changing so that the program should not get stuck on the wrong set. The changes made should behave roughly like the old while held workaround that used turbo. * Windows port of AntiMicro has been made. * Tweaked code used for button presses and releases in order to improve responsiveness. * Allow time-dependent action slots to have an interval as low as 0.01 seconds. * Tweaked Release action slot. Release slots can now be placed at the beginning of the assigned slots. This can be useful for Tap and Hold slot configurations. * Pause slots can now be used with Release slots. * Profiles can be removed from the recent configs list. * Spring mouse mode preview has now been enabled. * Mouse speed modifier action slot has been added. This can be used to modify the mouse speed settings used with any controller element while the slot is active. The setting will modify the mouse speed by the percentage that is specified. The mouse speed modifier can be used to allow for the mouse speed to be slowed down while sniping. * Button and action names have been added. Names can be used to describe the action that a slot sequence performs in the game. * Mouse wheel buttons are now used as a form of mouse movement. Mouse wheel scrolling is now possible without using turbo. The speed that the wheel is rotated can be specified in the mouse settings dialog window. * Added support for two extra mouse buttons. * A new controller properties window has been made. This window shows various bits of information provided by SDL about a controller as well as the current values of all the controller elements. * Added quick assign functionality for sticks and virtual dpads. * Windows version of the program now uses LocalAppData variable to know where to place the program's settings file. * New translations provided by the translation team. 2013-10-03 Travis Nickles Version 1.1 * Added spring mouse mode. This mode is used to move the mouse cursor from the center of the screen based on how much an axis has been moved from the dead zone. The mouse cursor will be returned to the center of the screen when the axis is released. * Added mouse curve options from QJoyPad. * Tweaked mouse movement in cursor mode to improve axis responsiveness and to allow mouse movement to be less jittery. * Added optional mouse smoothing for a further reduction in jitter in exchange for slightly delayed responsiveness. * Moved various mouse settings into a new dialog window. Several other dialog windows have been changed to point to the new dialog window to allow for mouse setting adjustments. * Added an option to start the program hidden. * Tray menu has been tweaked to allow configuration profiles to be disabled. A blank new profile will be enabled in the program for a controller. This is equivalent to selecting in the main window combobox. * Serbian translation provided by Jay Alexander Fleming. * Brazilian Portuguese translation provided by VaGNaroK. 2013-07-12 Travis Nickles Version 1.0 * 8-way controls have been implemented. This allows keys to be mapped to the diagonal directions of controller sticks and dpads. 8-way controls allow rougelike games to be playable. * Virtual Dpad support has been added. Axes and buttons can be mapped to a virtual dpad. This is useful for mapping dpads that are detected as a pair of axes in SDL. * A Quick Set option has been added. Using the Quick Set option, you can press a button on the controller and the program will bring up the edit window for that specific button. The button can then be mapped to an assignment from the edit window. The Quick Set option also works for axes, controller sticks, and dpads. This is more of a convenience function than anything but I have found it really useful since implementing it. * Main interface button text is now updated whenever the assigned slots are changed. This allows the buttons' text to be in sync in many situations that was not possible before. * Toggle and Turbo can be used together to create automated key macros for use in MMORPGs. antimicro-2.23/ProfileTips.md000066400000000000000000000077721300750276700162330ustar00rootroot00000000000000Profile Tips ============ ## Sticks ### Dead Zones The XInput standard of 8,000 will typically be used in profiles for analog sticks. For an Xbox 360 controller, that value tends to be the best minimum value to ensure that no unintentional events are produced due to what position a stick will be centered at. When using a different controller, you will likely want to play with the value of the dead zone used for the analog sticks and find what works best for your controller. As an example, when I make profiles for my Logitech F310 gamepad, I find that using a dead zone value of 2,000 for the analog sticks works best. ### Left Stick (Keyboard) The default diagonal range of 45 degrees is recommended when mapping keyboard keys to an analog stick when using the **standard** stick mode. If only one action should ever occur at a time and the diagonal direction doesn't matter as much, you might want to look into **4-way cardinal** stick mode. That can be useful for navigating menus or mapping weapon hotkeys to an analog stick. Some games will overreact when mapping WASD or other keyboard keys to an analog stick. This is mainly due to how quickly directions can be changed especially if you have the stick positioned right around where a diagonal zone resides. If you encounter problems in game or you just want to make movement a little more definitive, you can adjust the **stick delay** value used for that stick. That will cause direction changes to be slightly delayed. Even setting the value to 0.01 seconds can greatly increase control in some games. ### Right Stick (Mouse) To allow for better mouse control with an analog stick, it is recommended that you use a diagonal range of at least 65 degrees instead of the normal 45 degree value. If you want more twitchy mouse control, you will likely want to set the diagonal range of the stick to 89 degrees or 90 degrees. This will minimize the range used for the absolute cardinal directions. Another tip that will allow for more twitchy mouse control is related to the dead zone used for the analog stick. Decreasing the value used for the stick dead zone can help make mouse control feel more responsive than when using the standard value of 8,000 even when using an Xbox 360 controller. Based on my experience, even decreasing the value to 6,000 can make a huge difference. The big compromise is that there might be some mouse cursor drift if the analog stick does not center back to the assigned dead zone. On my Xbox 360 controller, I find that the stick can get stuck slightly in the southwest region of the stick; the other directions don't have this issue. However, the mouse cursor drift is very minimal and you can easily compensate while playing a game. It doesn't hinder gameplay and the benefit obtained far outweights the minor problem. One final thing that you can do to make mouse movement more twitchy is to enable extra acceleration for mouse events. Changing the **extra duration** of acceleration will have the biggest impact on mouse movement. Increasing the maximum extra duration of the acceleration will loosen the mouse movement. Changing the **multiplier** is another option that will change how mouse movement behaves. One final option that can be changed is to use a different curve for extra acceleration. **Linear** is still the default setting since it was the only option available for many versions but I find myself using **Ease Out Quad** lately. Besides altering the final multiplier used, it also changes the final duration experienced. With all the options available for extra acceleration, you will have an easier time performing a quick 180 degree turn while still having precision on the low end of a stick for aiming at targets. ## Action Names It is generally recommended that you specify action names when making profiles that you will share with other people. This will allow other people to more easily decipher what buttons are used for in a profile. Specifying action names can also be a helpful reminder for yourself in order to document a more complex action. antimicro-2.23/README.md000066400000000000000000000401221300750276700147120ustar00rootroot00000000000000# antimicro ## We've Moved! As of May 24, 2016, antimicro has moved from [https://github.com/Ryochan7/antimicro](https://github.com/Ryochan7/antimicro) to [https://github.com/AntiMicro/antimicro](https://github.com/AntiMicro/antimicro). Additionally, project management has passed from Travis (Ryochan7) to the AntiMicro organization due to Travis having other interests and priorities. So, thank you for your patience as we settle in. And a special thank you to the following GitHub users who have helped us make the transition: * 7185 * DarkStarSword * est31 * ProfessorKaos64 * qwerty12 * WAZAAAAA0 * zzpxyx ## Description antimicro is a graphical program used to map keyboard keys and mouse controls to a gamepad. This program is useful for playing PC games using a gamepad that do not have any form of built-in gamepad support. However, you can use this program to control any desktop application with a gamepad; on Linux, this means that your system has to be running an X environment in order to run this program. This program is currently supported under various Linux distributions, Windows (Vista and later), and FreeBSD. At the time of writing this, antimicro works in Windows XP but, since Windows XP is no longer supported, running the program in Windows XP will not be officially supported. However, efforts will be made to not intentionally break compatibility with Windows XP. Also, FreeBSD support will be minimal for now. I don't use BSD on a daily basis so the main support for FreeBSD is being offered by Anton. He has graciously made a port of antimicro for FreeBSD that you can find at the following URL: [http://www.freshports.org/x11/antimicro/](http://www.freshports.org/x11/antimicro/). ## License This program is licensed under the GPL v.3. Please read the gpl.txt text document included with the source code if you would like to read the terms of the license. The license can also be found online at [http://www.gnu.org/licenses/gpl.txt](http://www.gnu.org/licenses/gpl.txt). ## Download Source code archives and Windows binaries are available from the antimicro Releases section on GitHub: [https://github.com/AntiMicro/antimicro/releases](https://github.com/AntiMicro/antimicro/releases) AntiMicro is currently in the official Fedora repository and can be installed with `$ sudo dnf install antimicro` For Debian and Debian-based distributions, such as Mint, Ubuntu, and Steam OS, please check the LibreGeek Repositories generously hosted by ProfessorKaos64: [http://packages.libregeek.org/](http://packages.libregeek.org/) AntiMicro is currently available for Slackware via SlackBuilds, thanks to NK and Klaatu: [https://slackbuilds.org/result/?search=antimicro&sv=](https://slackbuilds.org/result/?search=antimicro&sv=) Ubuntu users may also check the antimicro page on Launchpad: [https://launchpad.net/~ryochan7/+archive/ubuntu/antimicro](https://launchpad.net/~ryochan7/+archive/ubuntu/antimicro) ## Command line Usage: antimicro [options] [profile] Options: -h, --help Print help text. -v, --version Print version information. --tray Launch program in system tray only. --no-tray Launch program with the tray menu disabled. --hidden Launch program without the main window displayed. --profile Launch program with the configuration file selected as the default for selected controllers. Defaults to all controllers. --profile-controller Apply configuration file to a specific controller. Value can be a controller index, name, or GUID. --unload [] Unload currently enabled profile(s). Value can be a controller index, name, or GUID. --startSet [] Start joysticks on a specific set. Value can be a controller index, name, or GUID. -d, --daemon Launch program as a daemon. --log-level (debug|info) Enable logging. --eventgen (xtest|uinput) Choose between using XTest support and uinput support for event generation. Default: xtest. -l, --list Print information about joysticks detected by SDL. --map Open game controller mapping window of selected controller. Value can be a controller index or GUID. ## Pre-made Profiles There is a repository for pre-made antimicro profiles. Using a pre-made profile, you can have a controller layout that is suitable for playing a game without having to map everything yourself. It makes using antimicro really convenient. In order to use those pre-made profiles, you have to be running at least antimicro version 2.0 and antimicro must have been compiled with SDL 2 support. [https://github.com/AntiMicro/antimicro-profiles](https://github.com/AntiMicro/antimicro-profiles) ## Wiki An effort is now being done to utilize the Wiki section on GitHub more. Please check out the Wiki at [https://github.com/AntiMicro/antimicro/wiki](https://github.com/AntiMicro/antimicro/wiki) to read various help pages that have been created. The Wiki is currently open to all GitHub users so feel free to add a new page or modify an existing page. ## Build Dependencies This program is written in C++ using the [Qt](https://www.qt.io/) framework. A C++ compiler and a proper C++ build environment will need to be installed on your system prior to building this program. Under Debian and Debian-based distributions like Ubuntu, the easiest way to get a base build environment set up is to install the meta-package **build-essential**. The following packages are required to be installed on your system in order to build this program: * g++ * cmake * libqt4-dev (Qt 4 support) or qttools5-dev and qttools5-dev-tools (Qt 5 support) * libsdl1.2-dev (SDL 1.2) or libsdl2-dev (SDL 2) * libxi-dev (optional. Needed to compile with X11 and uinput support) * libxtst-dev (optional. Needed to compile with XTest support) * libX11-dev (optional when compiled with Qt 5 support) ## Building under Linux In order to build this program, open a terminal and cd into the antimicro directory. Enter the following commands in order to build the program: cd antimicro mkdir build && cd build cmake .. make sudo make install The installation path of antimicro can be customized by specifying the CMAKE_INSTALL_PREFIX variable while running cmake. cmake -DCMAKE_INSTALL_PREFIX=/usr .. This will install the antimicro executable to /usr/bin/antimicro. By default, the executable will be installed to /usr/local/bin/antimicro. The cmake step will use pkg-config to attempt to find any SDL libraries that you have installed. The project is set up to look for a copy of SDL 2 followed by SDL 1.2. This behavior should work fine for most people. You can override this behavior by using the -DUSE_SDL_2 option when you run cmake. Using -DUSE_SDL_2=ON when you run cmake will mean that you want antimicro compiled with SDL 2 support. Using -DUSE_SDL_2=OFF when you run cmake will mean that you want antimicro compiled with SDL 1.2 support. Here is an example of how to specify that you want antimicro to be compiled with SDL 2 support when you run qmake. cmake -DUSE_SDL_2=ON .. ## Building under Windows **Instructions provided by aybe @ https://github.com/aybe. Modified by Travis Nickles.** * Download and install CMake: http://www.cmake.org/cmake/resources/software.html * You will need Qt with MinGW support: https://www.qt.io/download-open-source/. The current version of Qt that is being used to create builds is 5.6.0. * download SDL development package : http://www.libsdl.org/release/SDL2-devel-2.0.3-mingw.tar.gz * open the archive and drop the 'SDL2-2.0.3' folder in the 'antimicro' folder * open the project (CMakeLists.txt) in Qt Creator The CMake Wizard will appear the first time you open the project in Qt Creator. * Choose a Build Location. The recommendation is to create a "build" folder under the root antimicro folder and choose that for the build location. * In the Run CMake section, in the Arguments field, please input ```-DCMAKE_PREFIX_PATH=``` -DCMAKE_BUILD_TYPE=Release. Replace "``````" with the actual path to your Qt installation. The default path for version Qt 5.6.0 is C:\Qt\Qt5.6.0\5.6\mingw49_32\. * Choose "MinGW Generator" for the Generator option in the Run CMake section * Click the Run CMake button and then click Finish * In the main IDE window, open the Build menu and select "Build All" (Ctrl+Shift+B) * The application will need SDL2.DLL. A build step has been added to CMakeLists.txt in order to automate the process. Click the "Projects" icon in the sidebar to bring up the "Build Settings" section. Within "Build Steps", click the "Details" button on the Make entry. In the expanded menu, uncheck the "all" checkbox and then check the "copy_sdl_dll" checkbox and run "Build All". * At this point, antimicro has been built for Windows and is runnable from Qt Creator. A couple more steps are required in order to make a distributable package. * Under "Build Settings", expand the Make menu and check the "install" and "install_dlls" checkboxes. * Under the "Build" menu in the main window, select "Run CMake" and add ```-DCMAKE_INSTALL_PREFIX=``` option and replace `````` with the directory that you want to install the application. The default for me is C:\Program Files (x86)\AntiMicro\ although I use a different directory when bundling the Window version for other users. * Run "Build All" to have the application and required DLLs installed into the final location that will be ready for distribution. ### 64 bit build * Some additional steps are required in order to compile a 64 bit version of antimicro. The first step is to download a packaged version of Qt and MinGW compiled for 64 bit from the Qt-x64 project @ http://sourceforge.net/projects/qtx64/. * You will have to manually create a new Kit in Qt Creator. In the main Qt Creator window, click the "Projects" button in the sidebar to bring up the "Build Settings" page for the project. Click on the "Manage Kits" button near the top of the page. Manually add the 64 bit compiled Qt version under "Qt Versions", add the 64 bit MinGW under "Compilers", and add the 64 bit gdb.exe under "Debuggers". * After creating a new kit in Qt Creator, bring up the "Build Settings" page for the project. Hover over the currently selected kit name and click the arrow that appears, hover over "Change Kit" and select the proper 64 bit kit that you created earlier. * Perform a clean on the project or delete the build directory that CMake is using. After that, choose the "Run CMake" option under the "Build" menu entry. The arguments that you pass to CMake will have to be changed. You will have to edit ```-DCMAKE_PREFIX_PATH=``` variable and have it point to the 64 bit compiled version Qt. Also, make sure to add ```-DTARGET_ARCH=x86_64``` so that CMake will use the proper SDL libraries while building the program and copy the proper Qt and SDL DLLs if you perform an **install_dlls**. ## Building the Windows Installer Package (MSI) (these instructions have been tested with WiX 3.8) * you need to have WiX installed, grab it at http://wixtoolset.org/ * the building process relies on the WIX environment, it is recommended that you download the installer instead of the binaries as it it will set it up for you * if Qt Creator is running while you install or upgrade to a newer version then make sure to restart it as it will either not find that environment variable or fetch the old (incorrect) value from the previous version * to build the MSI package, click on the "Projects" icon in the sidebar, click the "Details" button on the make entry, uncheck all other options and check the "buildmsi" box. * currently it relies on INSTALL to copy files at the location they are harvested, this might change in the future Notes about the WXS file and the building process : * the WXS file has been generated with WixEdit and manually modified to contain relative paths, it will only work from the 'windows' sub-folder (or any other) * WixCop can be run against the WXS file and it should not point out any errors as the WXS has been corrected previously with the -F switch * CNDL1113 warning : shortucts are advertised, left as-is as a nice feature about them is that if the program gets corrupted it will be repaired by Windows Installer, by design the shortcuts will not point to antimicro.exe as a regular LNK file * LGHT1073 warning : SDL2.DLL does not specify its language in the language column, not a big deal; it could be recompiled but it's pretty much a time waste as it would only prevent this warning * all of these warnings have been made silent through the use of command-line switches. * built MSI package will be placed in /windows ## Testing under Linux If you are having problems with antimicro detecting a controller or detecting all axes and buttons, you should test the controller outside of antimicro to check if the problem is with antimicro or not. The two endorsed programs for testing gamepads outside of antimicro are **sdl-jstest** (**sdl2-jstest**) and **evtest**. SDL 2 utilizes evdev on Linux so performing testing with older programs that use joydev won't be as helpful since some devices behave a bit differently between the two systems. [https://github.com/Grumbel/sdl-jstest/](https://github.com/Grumbel/sdl-jstest/) ## Support In order to obtain support, you can post an issue on the antimicro GitHub page or you can email me at jeff@jsbackus.com. Please include **antimicro** somewhere in the subject line of the email message or it might be skipped. [https://github.com/AntiMicro/antimicro](https://github.com/AntiMicro/antimicro) ## Ideas For Future Features This section is where some of the ideas for future features for this program will be written. * Allow buttons to be bound to actions. * Use uinput by default and fallback to XTest if necessary. (MOSTLY DONE) * Move simulated event generation to a new thread. * ~~Allow logging as long as it doesn't cause button lag.~~ * Allow notes to be added to a profile in various places. Along with this, I will put the simple mind map that I am using to write ideas for future development into the repository for this program. The mind map will include extra notes that are not available in this README. Opening the mind map will require the use of the program FreeMind which can be downloaded from [http://freemind.sourceforge.net/wiki/index.php/Main_Page](http://freemind.sourceforge.net/wiki/index.php/Main_Page). ## Translating New translations as well as updates to current translations are always welcome. Please refer to [https://github.com/AntiMicro/antimicro/wiki/Translating-AntiMicro](https://github.com/AntiMicro/antimicro/wiki/Translating-AntiMicro) ## Shoutout A big inspiration for this program was the program QJoyPad ([http://qjoypad.sourceforge.net/](http://qjoypad.sourceforge.net/)). I was a user of the program for years and it is unfortunate that the program is no longer being maintained. The source code for QJoyPad was an invaluable resource when I made the first version of this program and the UI for this program mostly resembles QJoyPad. ## Credits ### Original Developer Travis Nickles ### Contributors Zerro Alvein aybe Jeff Backus Arthur Moore Anton Tornqvist ### Translators VaGNaroK - Brazilian Portuguese zzpxyx - Chinese Belleguic Terence - French Leonard Koenig - German phob - German tou omiya - Japanese Dmitriy Koshel - Russian Jay Alexander Fleming - Serbian burunduk - Ukrainian Flavio HR - Spanish WAZAAAAA - wazaaaaa00<@>gmail<.>com - Italian antimicro-2.23/Resources.txt000066400000000000000000000005351300750276700161520ustar00rootroot00000000000000Generate GUIDs for use in .wxs files http://www.guidgen.com/ Site used to check out the behavior of different easing curves http://easings.net/ Repository of code examples for many different easing curves https://github.com/jesusgollonet/ofpennereasing Site used to generate acceleration curve images http://rechneronline.de/function-graphs/ antimicro-2.23/cmake_uninstall.cmake.in000066400000000000000000000020131300750276700202100ustar00rootroot00000000000000if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") foreach(file ${files}) message(STATUS "Uninstalling $ENV{DESTDIR}${file}") if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") exec_program( "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) if(NOT "${rm_retval}" STREQUAL 0) message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") endif(NOT "${rm_retval}" STREQUAL 0) else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") message(STATUS "File $ENV{DESTDIR}${file} does not exist.") endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") endforeach(file) antimicro-2.23/gpl.txt000066400000000000000000001045131300750276700147630ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . antimicro-2.23/other/000077500000000000000000000000001300750276700145555ustar00rootroot00000000000000antimicro-2.23/other/40-uinput.rules000066400000000000000000000001011300750276700173660ustar00rootroot00000000000000SUBSYSTEM=="misc", KERNEL=="uinput", MODE="0660", GROUP="uinput" antimicro-2.23/other/CMakeLists.txt000066400000000000000000000004271300750276700173200ustar00rootroot00000000000000add_subdirectory(appdata) add_custom_target(manpage) add_custom_command(TARGET manpage PRE_BUILD COMMAND gzip -c "${PROJECT_SOURCE_DIR}/other/antimicro.1" > "antimicro.1.gz" VERBATIM ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/antimicro.1.gz" DESTINATION "share/man/man1") antimicro-2.23/other/antimicro.1000066400000000000000000000041731300750276700166310ustar00rootroot00000000000000.\" Manpage for antimicro. .\" Contact jeff@jsbackus to correct errors or typos. .TH ANTIMICRO "1" "05 November 2016" "antimicro 2.23" "User Commands" .SH NAME antimicro \- map keyboard keys and mouse controls to a gamepad .SH SYNOPSIS .B antimicro [\fIOPTION\fR] [\fIPROFILE\fR] .SH DESCRIPTION .PP antimicro is a graphical program used to map keyboard keys and mouse controls to a gamepad. This program is useful for playing PC games using a gamepad that do not have any form of built-in gamepad support. However, you can use this program to control any desktop application with a gamepad. .TP \fB\-\-tray\fR launch program in system tray only .TP \fB\-\-no\-tray\fR launch program with the tray menu disabled .TP \fB\-h\fR, \fB\-\-help\fR display this help and exit .TP \fB\-v\fR, \fB\-\-version\fR output version information and exit .TP \fB\-\-profile\fR \fI\fR use specified profile as default for selected controllers. Defaults to all controllers. .TP \fB\-\-profile-controller\fR \fI\fR apply configuration file to a specific controller. can be an controller index, name, or GUID. .TP \fB\-\-hidden\fR launch program without the main window .TP \fB\-\-unload\fR \fI[]\fR unload currently enabled profile(s). Value can be a controller index, name, or GUID. .TP \fB\-\-startSet\fR \fI\fR \fI[]\fR start joysticks on a specific set. Value can be a controller index, name, or GUID. .TP \fB\-\-next\fR Advance profile loading set options. .TP \fB\-d\fR, \fB\-\-daemon\fR launch program as a daemon. .TP \fB\-\-log\-level\fR \fI{debug,info}\fR Enable logging. .TP \fB\-l\fR, \fB\-\-list\fR Print information about joysticks detected by SDL. .TP \fB\-\-map\fR \fI\fR Open game controller mapping window of selected controller. Value can be a controller index or GUID. .TP \fB\-\-eventgen\fR \fI{xtest,uinput}\fR Choose between using XTest support and uinput support for event generation. Default: xtest. .SH BUGS No known bugs. .SH AUTHOR Jeff Backus (jeff@jsbackus.com) Travis Nickles (nickles.travis@gmail.com) .SH "REPORTING BUGS" Report dir bugs to antimicro home page: https://github.com/AntiMicro/antimicro antimicro-2.23/other/antimicro.desktop000066400000000000000000000013451300750276700201400ustar00rootroot00000000000000[Desktop Entry] Name=AntiMicro Comment=Use a gamepad to control a variety of programs Name[sr]=Ðнти-микро Comment[sr]=КориÑтите џојÑтик или играћу таÑтатуру за управљање различитим програмима Name[fr]=AntiMicro Comment[fr]=Utilisez une manette de jeu pour commander un logiciel Name[de]=AntiMicro Comment[de]=Nutze das Gamepad um Programme/Spiele zu steuern Comment[uk]=ВикориÑтовуйте ігровий маніпулÑтор Ð´Ð»Ñ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð°Ð¼Ð¸ Exec=antimicro Icon=antimicro StartupNotify=true Terminal=false Type=Application Categories=Qt;Utility; MimeType=application/x-amgp; Keywords=game;controller;keyboard;joystick;mouse; antimicro-2.23/other/antimicro.xml000066400000000000000000000005071300750276700172660ustar00rootroot00000000000000 AntiMicro Profile AntiMicro профіль antimicro-2.23/other/appdata/000077500000000000000000000000001300750276700161675ustar00rootroot00000000000000antimicro-2.23/other/appdata/CMakeLists.txt000066400000000000000000000014261300750276700207320ustar00rootroot00000000000000# Make appdata optional when installing an application. if(APPDATA) add_custom_target(appdata) file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/PO_files/") add_custom_command(TARGET appdata PRE_BUILD # Add an entry per language COMMAND msgfmt "${PROJECT_SOURCE_DIR}/other/appdata/PO_files/en.po" -o "${CMAKE_CURRENT_BINARY_DIR}/PO_files/en.mo" COMMAND itstool -i "${PROJECT_SOURCE_DIR}/other/appdata/appdata.its" -j "${PROJECT_SOURCE_DIR}/other/appdata/antimicro.appdata.xml.in" -o "antimicro.appdata.xml" "${CMAKE_CURRENT_BINARY_DIR}/PO_files/*.mo" ) # Only install an appdata file if the user requested to have one built. install(FILES "${CMAKE_CURRENT_BINARY_DIR}/antimicro.appdata.xml" DESTINATION "share/appdata") endif(APPDATA) antimicro-2.23/other/appdata/PO_files/000077500000000000000000000000001300750276700176675ustar00rootroot00000000000000antimicro-2.23/other/appdata/PO_files/en.po000066400000000000000000000046001300750276700206310ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "POT-Creation-Date: 2014-12-06 21:37-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. (itstool) path: component/id #: antimicro.appdata.xml.in:4 msgid "antimicro.desktop" msgstr "" #. (itstool) path: component/metadata_license #: antimicro.appdata.xml.in:5 msgid "MIT" msgstr "" #. (itstool) path: component/project_license #: antimicro.appdata.xml.in:6 msgid "GPL-3.0+" msgstr "" #. (itstool) path: component/name #: antimicro.appdata.xml.in:7 msgid "AntiMicro" msgstr "" #. (itstool) path: component/summary #: antimicro.appdata.xml.in:8 msgid "Graphical program used to map keyboard buttons and mouse controls to a gamepad" msgstr "" #. (itstool) path: description/p #: antimicro.appdata.xml.in:10 msgid "AntiMicro is a graphical program used to map keyboard keys and mouse controls to a gamepad. This program is useful for playing PC games using a gamepad that do not have any form of built-in gamepad support. AntiMicro was inspired by QJoyPad but has additional features." msgstr "" #. (itstool) path: screenshot/image #: antimicro.appdata.xml.in:19 msgid "https://raw.githubusercontent.com/AntiMicro/antimicro/appdata/other/appdata/screenshots/controller_configure01.png" msgstr "" #. (itstool) path: screenshot/caption #: antimicro.appdata.xml.in:20 msgid "Profile Configuration Dialog" msgstr "" #. (itstool) path: screenshot/image #: antimicro.appdata.xml.in:23 msgid "https://raw.githubusercontent.com/AntiMicro/antimicro/appdata/other/appdata/screenshots/controller_configure02.png" msgstr "" #. (itstool) path: screenshot/caption #: antimicro.appdata.xml.in:24 msgid "Key Assignment Dialog" msgstr "" #. (itstool) path: screenshot/image #: antimicro.appdata.xml.in:27 msgid "https://raw.githubusercontent.com/AntiMicro/antimicro/appdata/other/appdata/screenshots/controller_mapping01.png" msgstr "" #. (itstool) path: screenshot/caption #: antimicro.appdata.xml.in:28 msgid "Controller Mapping Dialog" msgstr "" #. (itstool) path: component/url #: antimicro.appdata.xml.in:31 msgid "https://github.com/AntiMicro/antimicro" msgstr "" #. (itstool) path: component/updatecontact #: antimicro.appdata.xml.in:32 msgid "jeff.backus_at_gmail.com" msgstr "" antimicro-2.23/other/appdata/antimicro.appdata.xml.in000066400000000000000000000033411300750276700227150ustar00rootroot00000000000000 antimicro.desktop CC0-1.0 GPL-3.0+ AntiMicro Graphical program used to map keyboard buttons and mouse controls to a gamepad

AntiMicro is a graphical program used to map keyboard keys and mouse controls to a gamepad. This program is useful for playing PC games using a gamepad that do not have any form of built-in gamepad support.

AntiMicro was inspired by QJoyPad but has additional features.

https://raw.githubusercontent.com/AntiMicro/antimicro/appdata/other/appdata/screenshots/controller_configure01.png Profile Configuration Dialog https://raw.githubusercontent.com/AntiMicro/antimicro/appdata/other/appdata/screenshots/controller_configure02.png Key Assignment Dialog https://raw.githubusercontent.com/AntiMicro/antimicro/appdata/other/appdata/screenshots/controller_mapping01.png Controller Mapping Dialog https://github.com/AntiMicro/antimicro jeff.backus_at_gmail.com ModernToolkit game controller joystick keyboard mouse
antimicro-2.23/other/appdata/appdata.its000066400000000000000000000005201300750276700203170ustar00rootroot00000000000000 antimicro-2.23/other/appdata/screenshots/000077500000000000000000000000001300750276700205275ustar00rootroot00000000000000antimicro-2.23/other/appdata/screenshots/controller_configure01.png000066400000000000000000001501311300750276700256230ustar00rootroot00000000000000‰PNG  IHDR@„ùMý¢bKGDÿÿÿ ½§“ pHYs  šœtIMEÞ 7:LwŒ IDATxÚìÝgtTÕ‡ñÿ¤'@BRè ¢ônAé]š (ņ `Ûµ!vEl׊ô¢Ò‹HG¬x•¦ ti$ ¤L9÷Ã!Cz&˜ Ïo­YdN?ïÞ3ÃÚïÙ{[ Ã0$)>>^ÅYXX˜$É‹POCx ÀãA´ëÜ• Ü B"€û)tdî¼ùêе»æÎ›ïÖ7zààA=÷âKêÖ«·ºõê­ç^|IûÈ×1²Kv¬^¾´Xxn ’9OQ¨ˆaZ¼|¹†¬%ËWÈ0 ·¼É#Gé‰gžS£† 4}ÒDMŸ4Q6ГÏ>¯#GQ ð0>…Ùù—_·¨TÉ’êѽ›¾[»V¿lùM7ÝÐĹ¾]ç®<ð}ýÍÙívµiÙRÆ<(—Ö•_~©Û»vQïž=œËzõì¡s‰‰š9k–žyò‰<¯'­wDÚ¿i=?ÚuîêüÛjµj┩Z·a£$©uË<ðùúú:·}ìáš=÷k:}ZÕ®¹FO<öˆªT®,Iúý­ú|òú÷_…–.­»ûõQ环HÅ0 C³fÏÑŠUß)11Q·6½Y{HY¶½\倫 Õdñ²eº½[7IR÷.]´xiÖá ~ûýwÿ迚øéÇú÷ÈaÍš37_ë‹Âÿ~ÿCíڴβ¼}Û6úßï¸t=iIŽÕË—æ8ìÕ—³çèÀ¡CúôÃôé‡hßþYîgËo¿éݱoê›Ù³tc“Æzÿ£OœëÞ|ç]ÝÝ÷.-úzŽÞ7VíÚ}Å*Æü…‹ôÇöízçÍ74cÊ$ÙìvM›ùEŽÛ_ŽrÀUN€;~\»þþGmZ¶dövØõ÷?:~<&Ãv#†Q™ðp• ×ð!C´zíº|­/ gΨLxx–åáááJ8s¦È®gͺõ1tˆ"Ê”QD™2zxØP­Y·>Ã6=›0Q±qqŠ‹Óg&ªmëVöÉk}Q¸·?-Z²Tó,Tü©SŠ?uJó,Ôâ¥Ëtoÿ~._Opp°ýûoŽçiÓª¥>ù|‚NÆÆêdl¬>?A­[¶tù:_û¶:$»Ý.I²xY®XÅèÖ¥³Þûð#ú÷_Ùl6í?p@¯½56Çí/G9àªõY´t™Ü{w¶ëºué¬/¾úJÚµ•$5lÐ@=ò˜ì6›Zµl¡þ}îʰ}^ë‹BÅ 4îÍ74qÊTM½0‘wÚµôö¯«Bùò._O¿»îÔ£?©s‰‰Ù#uwß>š0eª†?:R’Ô²EsÝÝ×õû¹åæ›õÒko(æÄ UªXQÏ>õä«=»w“—Å¢1¯½®ãÇcT¡|y=pß=9n9ÊWY Ã0$)>>¾ÈÞ®s×ç›peýåæn×S\7€» “TÀ!°ÜY†Àj×¹kžÛ¸KW®Õ®—XPx—t,€Ë‰!°€Ç"< àqH€Cx Àã‡ð8$@€Ç!< àqH€ã“ÓŠßþMÕ7žÕ/’‰\A7V Ðà¦%Õü‚¸Èb†!IñññÎ…«v'ë»ÝIª¦R¾D ® ³IVí?¯ÖÕÔ­v r&)‡!°Æ­Ž#ùn¢T ¯ª– Ó‡ëã à¢l‡À²ÈИN¡DÜÈ’_ÿ%€‹²íìk%2àf‚}øn\•m$Ì/…È€› óç»pU¶ p àvÂI€.˾lîÇb!”ƒçÆí7¤®]¯Îzй³ôÖ[.mJï<Àu9 •Ztg Á@n¥÷ß7_WÚ•ø¾zï=ó•””ç¦áþ©ÔÀEÙ•S“'¥¨()%Óúž=3¾ON–"#Íí £è®öøqiÄ©jUÉÏO “n»MZ¾Ü½£œ[£jQ4¸Z,RíÚYcmR­ZÏa±\|EGK÷ß/ÅÅå~ü}û¤nݤÐPóÕ­›¹ÌÕõ†!ýç?溰0éÙg3^k^ë³³c‡ùä|©RRÉ’R§NÒ¶mÅ£œÌ{¼î:)(ȼç=¤5k²/'//³¬úõ“¾´uéJøæé–[¤êÕ/ï½dwŽ¢ü¾Ê|®´Wf5jHMšH‹åyz€®Ë6äcÏ~눩iSiñâ‹ËâãÍ÷±±—-X`6hFDÝ•9"Ý|³h&<¤þ1"~HIIK—f\¶h‘T¢DÖm Ã|ýö›ùÔù£æ~ì{î‘ê×—öï7_uëšË\]?a‚´zµô¿ÿ™ç\µJš<Ùõõ™íÙ#µi#µkgÖ={¤Ž¥¶m¥¿ÿvÿ²êÓÇL:-[&>-íÞ-õï/½újöåd³™±)_ÞL‚xš%K¤;ïôìÏgZYæä®»2~¯æ ÐÛÎwà"¯|ï1`€4cÆÅ÷?ü 9æ¿i¦M3·“2>ñ¼fÔ¨‘™Ä¨REš4éâ:‡Czí5³wGX˜4p 94Nš_4‰ßyGªYÓþXúöÛܽu«yœÒ¥Í×3ϘË\]?}úŲ­ZÕü{Ú4××göÒKÒðáÒã_,ÓQ£Ìe/¿ìz¹þý·Ô»·çéŽ;2&ò R®Ø¸Ñ¥^R¹rÒèÑf‚ȹÕù-¤Ù³3nèyŽ„„¼ë{QÇmË3±z)î%§ïœœ>{éÿ¶ÙÌïÊ•ÍÞIï¾›ýõýö›T¡‚ôßÿ¼NÜz«ôË/.eÈ[þ ]º˜ ~'N˜ï7o–:t0ÿ•ÌžÛ¶™Ûevï½ÒóÏ›O½oÜ(ýôÓÅu|`6¯]+íÝ+Y­fãcš+.&Uò²aƒôóÏfRE’^]Ú¹Ólhݲż¾7ÞÈß}÷ùþ¶mæûo¾Yøè§=žùéð7Þ0™·m3¯wÅŠ¼Õ«—Y&i‰¨õëÍ^wÜQøëìÜÙL<%$˜e7nœ¹ÌÕõ;wJ7Üpñ}“&æ2W×g¶zµY—2»ï>³þ¸êÎ;͆úÇÍFóòåÍ¡© S®hÕJ2Äü̸0ïƒsø·7ß”n¼ÑµsäVçŸ^zå•‹ŸÉ|ÿØcfB#¯ú^Ôq;~\*[öÒÜKNß99}öÒ;VڴɬSûöe?üØÒ¥æ0|Ÿ|bž³ Ê•“Žå (BÃ0[ÿâãã W­]¥¾½ûæ¼×È‘æÓÔ#GšO`+=õ”ôý÷fCiLŒ™ÐÌG–Ó+U2·ëÑÃì¡‘^ÍšÒÂ…Òõ×›ïcb¤›n’0ßûúJgΘOr;¯>ÝãÐiç°XÌ}*W¾¸®Z5s˜ZµÌ÷;v˜×°gOÖkLìôÇܹóâþ;wJ·ß~qÿ<£lɹ‘5»u×^k‡“þzëÖÍû&˜Ã*-ZdΉѫ—4xpÖ{IûûèQé‰'Ì¿¿ú*çë?rÄ|BýàAó}åÊf¢¥\9×Ö{{›óÂøúšï­V³m6×Ögæã#;'d\ž”d6z§õVÈ«\3;sÆœKåß Wy­;sÆL-^l&Ê•3U/¼p1‘Ý£þ¡¡fƒ|íÚyŸ#¯:ãæç·s±6mÌk Ê}/lÜÍd]PPÑßKnß9yÕêÕÍáüêÔÉ>Öl&b.̘À+ÈwAb¢Ùèüù\wŸ=o¶:´éÀ/‹°°0Ié"™=1¦O7šO2‡¯‰7‡¥™>=çž šOS7lhNþÉðƒÍÉ€ÓOÐÖ *IeÊd|/åüôv¥Jß=*]sÍÅ÷×^k6ÚçGúý«UËÿþùqäHÖëuÅý÷K¿þj&3¶m3{Dd'-Æ šÉ‡ôs¨d7Yó€fãò©Sæ«ó\®®/YÒì’æôisòrW×gV¦Löñ?zTŠŒt=Î[¶˜ó†„…™÷";VðrðõÍ8´Zšää‹Ã±IRp°ÙKá?ÌïÅ‹¥“'¥»ïξ~†Ù»gøð¼çkqµÎ§õœ°Û¥1cÌ!ÔÒ' r«ïE·²esïýP˜{Éí;'/‡ç~íï½gÖsW“y•Wn½`ä[Á ˜ÿN›föÒÌ?þØ|*?m}f™OTŸ?l˜9\Ó_™=K¶o7ZÓ¼ü²ÙÀý䓿6IIfoƒ¥Kó¾Ö~ýÌ„ÀáÃæë±ÇÌei76‡$JL4“0™ƒ%s’í#GÌרQYŸÖÏܘêêlÅeʘ÷“^ÿþÏ7r¤ëåòÌ3f|s›ü<¿40'Å>}Ú|k>Qïêúûî3‡wÚ¿ß|½ðBÆz’×úÌÆŒ1ç\xÿ}3©qü¸ù÷'Ÿ˜½\-×ÄD³7F‰f¤!C W?lÖá Ìa¡Îœ1çb<Øì½‘¦U+iî\3eµš×öÌ3R³f9;.Îlh¯_ßµ2Ë«Î[,f¬Æ3ãíççz}/ê¸uë&Í›wiî%·ïœì>{é  =òˆ™|9uʼ§ô*T0ËzòäÂÏ 4ožE¦à »ï6xÓ -[šÃÿdN ¤wûíæ\!!ÒèÑfïƒ4É}ÇfãêÝwglä¬\Ù|ºûÔ)©];s›êÕ¥)S2ö6ÈÎ /˜sŒ4ib¾j×ÎØP>~¼94N™2RëÖæü™µmk>M^·®9$ÐsÏå|¾Í›Í91ÒK?´Tú!¦žyFºå–Œ “çŸ7‡ü©[×­já‰u>b½ô¯ôÍö·•lK,’k ð)¡;ê>­®5á3áB9å&ß 2ç(ª j/¥s‰çÆð5äp8æòCÐ<)_8—£W‚aú{Ï_Š?—aù‡†«[ó{µéÈ }¼öuzY>>>ÎóD„GªÆõµ Ýí©±ž·íM}Þs¼,ÞEóÙ3ìºàZu©ñ0Ÿ‰BÊw$»Ìù’??Ô¼­oå;ÃàSB½ë?£nµå )ª j/%z%msÝF†!‡Ã‘ïãzP;þܦZ5êxD¤¨cjOV‰ RÚ¸y]žÇlqkkÝØ¬¥~ù~CžÇ,ÈçéjüLä&ß ì2çsÿx]{ï“·%çÃ5kÓA߯]•a™Ý°ið¼k®úLÀ•ðã?ªiÓ¦Ú7¿½®z%>~.±,ÖN$jÂÊ=j^¿’Ê„fXwòôy}°p§éVS×”-uuÄÚrébýÏÞ]*^FQQee³Ze÷²ÈËË+Ãvi§OL<§%ew8d†Ê—­(/íøs›êÔªG¬³áïàÒ¹Ó¶seû«ý»ËårÊE¾ ‹%K¡§Ú“UªDi½óÞØl÷yòñÿH’‚‚²fkSíÉü\…M†áÖOƒ¦WÒ•q>ž”Ïo}úÔáÆkäíí­‡.œSr• T«†UôöÜ­JJ±Êpzˆ8ÒýmÈp²X¤;šWÓ]­«»EÜÚtꬵ+—»U¬ãâcU®\99{ZÞÞ>òñö‘·|²i"ööö–ÅËK‡Cv‡]‰çÏ*0(H1'Ž«vͺÔëL|½ýe³[Õ¾Ím.ë¯?çºÞf·Ê×ÛŸÈ•è’݇¯·¿†]ÿyê¹|ªÕ–jîËÀeçp8 Õ.SS—’Åb)ô=RGùJrå·Áö̹$…• Ô¶§äpæËpÈá0ôObŠÊ…ªO»:浆 ãbâÎL”˜ÛmvM]ô‹îlu­ÛÄîR7^ç÷ø‡Cþ~Úw`¯¼. }e±xÉ╵|÷ا3gOËn·_ø ÙU¥ò5r\èrµÉ랻թ¾ÓÂeuä>ßÐ{=Ô7ICõýÊm¹nçëå¯n5GÒq ä;"‹ùa±ÛíÎEÝkŽR¿ée²-àWúÍÖªSod[¨¾^þê^kT†cåW›NuCãÆzëµW²|$Ó pµÈÜÆSýU ¦(L#bÛÛº8ÿ.¥Z5jhø!*_¾(½Ë”šbUªÕ¦Ä¤Ô ‡âw¯QÜþ-r8ìڑ˾^^Þ *W_–è¦jV'ZII94Ó®sW­^¾Ô­ëÝ¥ËápÈËËK6«MåË——¯¯¯³'HfQQ •ÕjUrr²Ž;*›Ížg$11Q_}=O›¾ß¬ØØXùùù©n:êÙ½›6¨ï^ß Eën5Fª[‘Z¶r±nh|£öìùGÑe£åãã+oooùxûè™Mt.à ”dîóÆ-[dµYe³Y•’’¢ã11ªVõZý¼å'ÝÙ³OŽuÈ]cé¼ìv[ž Wß«ÈȽþòEEF*11QlÛ®™_}¥õë¹U½¾±.]:DÑeËêdì •-[NÞ^^òòòÎ0ÏJú‡†––Õæ%/o/(¼L˜BB‚‹]Œ ÃÐâeË5lȃúfábõ¾£g‘ xE†ÀJë’S×ÁÃgviò–‘òó̲·ª¤˜îªó‚® ¿!ÏSY­Výøó/únÍíØù§n¾éF 4(˹>L>þ„6¨¯Š*dù`§kÖœ¹Z±j•ÏëÖ¦7ëᇆ* @÷?8D/~AU*W’$­Z³FÚ¶•$8xHc^}MÓ'MÐÐAƒ´jÍMÿb–êÖ©­mÛªéM7ÊÇÇGÅMúaÎ'Mù\e"Ô®]G•*áÜ&))Iß­ùV'NÄèÁC3ìïî=@ ÚPœ]œ$ó!Ü;{Ý¡¯çãÞÞêݳG®çËõú.u‹™9|v§&ÿ6JA¾ÁjYµ_–m·œ\ _vÏV)ßµŠ,¯óá²¹Ù¾c‡fÏœ¡%‚$IÁÁÁjÑìVµhv«s¿œâée±hàÐaš:a|–:>hØpMÿ™J”(¡¯æÌÕŠï¾3ëøÍ7kÄCCò]Ç/U¬ÓÇøèÙ¿4õ÷§è[RÍ*ß™mŒû{žJùF¨EÔ²ãÿüë•,YR·wíªÕkÖé—-[tc“&Îõ¿oݪ‰S¦êп‡Zº´ú÷¹K·uìPt唋M‚ž[!Lüõµ¹©‹Jø—–í×ÓÎåU£¯W—оӿiÁŸoëÉfss<Ç®Ýë»5k´aÓ÷ºæšªjߦž}ú)^ræs— Ò£#†ë­wÞÕãÆÉÇÇ;ËÛü… µuÛv{ãu•,QBŸ|>AÓf~©¡TãF µmÇU®TQ±±±úø³ÏÕ¬iSjÛöíjÒ¸‘ ÃPƒúõÔ ~=%%'kÓ÷›µhÉR}ðÑÇjÙ¢¹Ú·i£×_Çÿœ@±‘¾a/*2J1'b´lùu¹­›‚‚‚”’’¬å+—êÔ©xEFFei“Éïü—›ÅbqÎaPiûŸ={Nß,Z¤*U*ËáphYP& IDATþÂEÚºm»Þ~ý5•,QBŸN˜¨i3¿ÐAûþôë¯zëÕWZZ /Ñsc^RƒzuõúËcZÚ\öÁGŸhÜ›¯K’¾œ=GÔÇï¿'Izûý÷õåì9ºïîþjvë-Zº|E†áe–®X©Ö-[*((Hó,ÌózòËn·»TÆY 4?DJŠU©V«Î'Y³44oùý—\÷M›p:%Õ.›Í¡T«­@ YsæêÀ¡Cb>kÎ\ÝwwIæ÷Ã?¨§%›Õ¦i_|¡)Ó¦kä#;÷?|äˆÆô_É0÷Ïí|¹Õ3W{%$ÖiC`Y­6}µmŒ:Þr‡Jù‡iÙ¯“³l»Ç²J÷ßö¸&lך&èfËyY¼ò:Kk¶NÔM^lc¼dÙ2ÝÞµ‹ ÃP×.·iñÒeº¡qcçú±ï¾§C‡è¦nЩӧõåWsÔ©Cû"+§Üh¬Üz€†CqÖ}J ÒÝ-Ÿv.ovS+0¶ëxêŸ:oõÊõ‡çÑ'žTdD„^ý¼jÕ¨‘åÇ&»@Ô­][õêÖÕô/¾Ô÷Ý“eŸå+WiÌóÏ*2"B’ôàôØ“OiðÀjܰÖmب.:jõºõòóóÕº Õ©C{mݾ]mZµÊpn??µkÓZíÚ´ÖŽê­wßÕ’e˵rñBþçŠô=@Ú´n¯+—êtÂi-_¹TmZµÕ†MëtêT¼‚ƒCÔºUÛ,m3EÑ8u9î±°=@:v»ÝùwXh¨Þ7V†ahÅ·f{STd¤¤ôíM8·ùð……†J’zvï¦i3¿Ð£Ã‡)4ݲYsæ:¯qíúõzyô “$ d°^zý gdüGÿunëïç§î½GƒG<ì\¶fýz½2ú• ¿¸ÿЇu»Ï‚³w‚Õ&›Ãª“){tÞß_ý[<­M»8·kV¯“ZÔè­]IßjÏÙ-2þJJI’¯¯ožÉÄçž~Ró,ÔÇŸ}®ÃGŽ(<,L·6mªþ}îröXÈ-ž=»wÓs/¾¤^={d¨ãï¼õ†$iÅ·«ôÒ Ï):*J’4xàzô‰§ •ä»t1NÕ¡¤?ä]"U÷·~AvÍwn×¼~µ¬ÑK»“V+Ñ'»Ý·ØÆøØñãÚýÏ~öIR«æÍ5iêt‰qÃÛË[qqñ: ÈˆzôáËV&î’ÓYwÔ|V6SÙkBt¢ê?*íS^’´?ùG9«cûôÈ Ós`ëݱojÍÚõóêëªVµŠÚ´j¥[›6U@€¶Û§ëÞ~}õÄ3Ï©q£ª]³f†u1'NèÁa#²Ü‹ÝnWÚµõÉçd·ÛµvýzäaÍ™7_íÛ¶Ñ_»wë±#2\oRr²~øñ'­^·NûT‹[oQÛÖ­ 5iÀåf·Ûí¾¾¾jß®“V}·B §µp±9ÌS©R¥Ô¡]'ùûùgiû(=@r{×UËš±8£÷þû‘þÙ³WeÊäØÞ”þ|¥CBœïÓ†T É´,55Õù>.>^‘‘Î÷ÑQQŠ‹“ÃáPùråT©bEmÚüƒZ4»U¿ß¬š5®W™ps((W®'¿òSÆéj®JMI5{o¤Úä¸Ik°\óÃÏú;Æ¡ÝÇ N´Ép˜ë†C†ÃLvX£î‘’¤%ßïR¹ ÑZ´y¿º5­œã½d'.>.SÌ£ç|ÿÏž=š<}†öîÛ¯sçÎI’¼¼.>à—uÿÜΗ[üò³m~ŸÖ;!99Y5ÛµzÓûªR3\gªÄè¦ë{:· «ä«-çfjßÁ=:ôW¼ê&á+ùúúåùy Ð=ýúêž~}e†ýû¯æ-X¨·ÞyG/~!Ïx–/WN•*UԦ͛բY3mü~³jÕ¨‘¡Žzhx¡ëø¥Šuú×pÜ®õ?} Øš‡_ù š^ßù]jµôë¹Ú{pý§:çŠoŒ—,_¡„„uë•q˜¯%Ë–kЀû%I/>÷¬fÍ«/¾š­R¥Jê¡T“ÆŠ´œrR  9eTÿÞó§~ø~ŸNþZG v*öø6]W7Þ\·ý°bwY»¡’F|üšÞû’j×È~Vúë«W×õÕ«kðÀúù×-Z³n½>Ÿ¯!ƒÌö¦ÃGŽjîüùzúñQÙîëʲÍnÕ„ÉSôØÃæØŸOž’arãõëiâÔiZ²|…tM•*Îu®\OAêH~z€ä'Ös×ý£îmê)4$0‡ãY”˜lÓ©D«ÇŸröq’Ã3â0 ùûzËÏ‘ªï¯!§å-›7ÓøI“5êœã'NVËæÍœÛ'''+00Pþ~~Š9qBS¦ÏÈp¼V-škÂä)ùðÃÊlr®çs¥žu¬%ÉawÈf·iÏÞ=Ú¼y³9"/5UBùŸô[Â_ªVëŒdH{ÿ:"ûÞò Øß@+´AÕªUS›V­U¥Ê5y~žžyáEu¹­“êÖ®¥’¥J).6N_/X Ú5kºφõëk┩Z¼l¹YÇ«^¬ã;uÔ?ùT=8He££uøÈÍ™7_ÿyâq·ˆun1þýÌ.U«uV†!íýóˆl{ÊûoØ´I×_w"#"2\sTd¤ª_{­6~ÿ½Ú¶n¥±ï¾¯~wÝ©re£%²X¼\Šé•é’ËÇÖm[U¡Be%&ž•ÝfW¥JU$I~¾þ:wöœܧˆˆHy{ûèøñÕ­åú „„ëö®]œ“©äˆ.:êå72öér['ÉbÑ›ãÞQ̉*W¶¬îîÛ']¡×Ó_ÍV³[o‘aj~KSM™>C ê×wnóÁ¸·‹4øWRN {jÛº½s›œ¸ýX²É ™÷ïЮ­f|9Kï}KIo¼=ÎÙÞtO¿>¶Ïoä®Þ½4mæõô$IÍn¹Ewöº#Ã>Ý»vÖ'ã'襞˰¼ëmò¼ž‚Üû¥š˜»LIoÅ'œÓés©J¶ÚåHëáá0“ö =B IŽ Ë.&=t!!bþè«#qñªZ68ÇkèÒ³W–eK¿™§>wöÖÔé3õØ“æ|ÆÍo¹Ewõîå<Îcפ©ÓôÖ¸wª;zt׿ºXf½îЄ)S5|äHùxû¨çíÝõÇÖmn9 ºÝf“aq覦7ê&çš>æ?æ@>j-)ZÒ­÷µ:R%Cyž·ï]½µtùJ}<~¼RSRª5Ò#u9žfïª?¯WF¿ay·Î·Éb‘^{ëmÅœ8¡òåÊêž~ýÜ&ÖyÆ8Öü§e”¤¨âã¥ËWèî CqeÖ¹c}õõ<µiÕR7ßxƒ^;V'NœTÅ ôdºk-Šrʵ gŠw.\µv•úôê“íkÖ­Qíšµ•šššeݬ935xÐP%%W||¼bbbô×®?•œœ,__?µjÙR‘ ÒÄÉŸ«Ÿ{ùŸÀ²eË5iÒ¤Àûûùùiç_;Õ¶u[·¼¿ÕëV«~úJII¡° Èßß_[wlU»ÖírÝߩqƒÆJNNvùØ“–lסSv•/¡3‰V9 CÒ…ä†Ã¸0ÄÕÅ„Gúá®Ò†ÀJVÊ_ÿüsPíêEêζ5Še¬ôÛ¿©}›öEkIZ»~•:´¿M›6¯W£U²T)ùúøÊ××ï¿æ0ÿV«UV›UVkª¬6«Î=«ÿýñ›Úµî¨Ù_ÏR·Î=Š}½¾T±&Æ—·œæÌŸ£m:d».,,LR‡À²ÙlÙNøsü„üüüåçç¯PU­ZM7ß|K¶‡‰9~‚Iî ‡ÃQ¨ö›Í&7ŸDv»áË ?W¤·M•¨ mÚºGÁ!ÁJ8—|q~)CÂ#mYn‡Nö‘NŸ:§Š‘U‹íÈ-ùémS !°Ùí6%$œQJJŠRRR´ÿ>íÝ·W×V«®*UªHRºeתJs^„„3²Ú¬rØ12Î¥Š51¾2å”›"=&&FCœ¯À•QØá¡Ü}ô´¡ÜI€œËÜYòWŸ ÃPù0?=¯ÊgÎÉÇÇÛ™ð!Cù©šçÏ+.>A¡Aî?4[n1qéãdQ 6›M Îe{÷íS¿¾÷èËY3µmû6çò»îì£oÌO×8Ÿ «5µHæÔñäXã+TN¹Èw$((Hç“ÎËßÏ?KA¼úòëù¿\5*pûŒÅbÑù¤ó rÛûËíA^¸&?I®ü4܆¡ð`Õˆ4´ñ‡mdz’ëí†ÎD‡Eª[ÞK¡¥ü‹myç'QWà9@ìvI8ã\Vãúš*¡Áƒ†*%åâ0OçÎÍp=gÎÈjµzLãü¥Š51¾r唓|'@*U¬¤ƒ‡*$8Dþ”ÀU(9%Y gT¹Re·¾N ?Wdbî’%Kê±¾7êܹDÙ…+#o/‹J–,¡’%KJ*ž^_ÊIÐcccåp8äíí¡w¹ÄsZõÝJç<ÎÎxz{«r募턄çpr'OžT™2eŠ}½.êXã+WN¹Éw$:*Z†aèßÃÿ*æD ¿W¡ÀÀ@UªXIÑQÑn{¹d‚¼å«—EùnÌÛÛ[åË—/²y‚½½½åååUl‡E}ÀÙ³gU§¾}û^²cû\ŠƒvìØ‘R9 “a—ìø < àqH€Cx Àã‡ð8$@€Ç!< àqH€Cx é´ëÜUí:w%s>WòäiÉ‹Å"?__«JåÊjÓº¥Úµn-‹Å’eÛ4~~~ŠŠŠT»Ö­Õ§w/ùøøPš@ÒN€¤ùnÙOJÒ‘#GµhɽýîûZ½f^3Zþ~~¶]½|©$)þÔ)Ÿ8YSgÌÔ™3g4lÈ`JHr“ˆ$ªúµÕô䨑òó÷×â¥Ë4kö=pß½ÙnªCkíúõZ·ac†Èü…‹ôÙ„‰²X, -]Z7ßt£ü ‚Û,_ù­æ-X¨cÇ«\Ù²ê{gï,çøk×.M˜2UûöÍjUÝ:µÕ»gO5i܈š€sË9@nïÚE’´fÝú\·3 #ÛåçÏŸ×äñŸjÙ‚ùxÿ}Z¾ò[Mž:ݹ~ù·ßê½?RÙ²Ñúrêd{ã5­ß´)ËqÞxûmß±Sÿyb”¾™;[ýûöÑ‚%K¨5¸9·L€DGEI’bãârÜ&þÔ)}:a’$©uËÖÝÛ¿Ÿ*Wª$???uh×V’ôãÏ?;׳p‘$é¡),,LaaazèÁAYÎqîÜ9ùøø¨Lx¸¼,Õ«SG¯¿4†Z€›s˙Ñ$• ϲ.m2t???EEFê{ïQŸtÃWýµ{·¦Î˜©½{÷éÌÙ³Î^"'cc³?-Ñ"IQ‘‘YÎ5hÀý?i²†?6J^^^º¶Z5 8@ ë×§æàÆÜ2²èÂ0Sm[·Ê².môœ¼þÖÛ:£×^zQM5’ÕjS·^½3 —U6:JÒñ˜U¬PA’sâD–cuí|›:¶o§ýè×ßþ§©3fê­wÞÕœ™3¨9¸1·ë|R’öìÝ«wÞÿ@K–¯PㆠտoŸ|Çn·K’J•PªÕªÉÓ§gÙæŽÛo—$Ÿ4YñññŠ×øI“³l÷Òk¯kï¾ýº¦jU5nØP’à@­À͹Eö]ºÉ××WÁ¥J©r¥JzúñQjß¶,K¾õìÓOê“ñŸë©çžWXh¨úÝug–m:wê(»Ã¡o-Ò½ƒ«BùrêÕ£‡~þå× ÛÝÖ±£&Nª]»vËÇ×WõëÕÕÐlæ îÅb\*>>Þ¹pÕÚUêÓ«O8{öluìØ‘È€………e˜¾"?æÌŸ£m:äx\ɆÀ(*$@€Ç!< àqH€Cx Àã‡ð8$@€Ç!< àqH€Cx Àã‡ð8$@€Ç!< àq|( ÃPÌÉ;~Lç“ÎÜ@P`ÊF—UTD”, n…(bNÆ(.>NõêÔSxX8À ÄÅÇi×ß»$IёѸ  X8vü˜êÕ©§à¥¦¦Ü@Hpˆj\WCÛvl#Ü P,œO:¯°Ð0¥¤¤ Ü„ÃáPXhÃS·D i㊆A0pÓßiwB†aÀ ŸÜ P,Xd‘ar87b†,¢p?$@@±`±Xäp8H€àfC`·D+ ³/§4è¡áš=cš|}}Ë_|å5½òâ Î÷©©©êwßMþü3• !p (,ÌG!ÁÁªU£†6ÿø“Z6o&I:{ö¬~øé'NHPHp°$iÓæT«fM…ó9ŠÃ0ÄXÀ‘ÅBÚ 4ŒÅO‡vmµrÕ*µhv«$iÇŸÉ0 íüóO5½é&IÒ·«W«[çÎ|Æbˆ9@€»"Š‹Å"»ÝÎ @1tCãÆúðÓOê”J‡„hÇÎjܰ¡vìüS7Ýpƒbãâ´oÿÝи1Ÿq ²ÛíÌÜ PlÐ(ž¼½½ÔâÖfZ»~ƒzvï¦ý¥A÷߯IS§É0 ­^»V-›5“··Ÿq ˜þ>¸#  X°X,r8<SíÚ´Ò{~¬.:êìÙsºþºê:sö¬RRRôÝšuzæÉÇù|Å”Ãá pK$@@±A(¾ªT®,ÉЪÕktýuÕåp8týuÕµxÙ2ùúúªJåÊ|¾büû àŽH€€b!­ÃlÅW›V­4ýËY-uµu™9s¦³ÊHcccêjëZô í9hˀҶ畦U@æ<·¬X,:› ŒÛjí9hË€òmÏ+MÛÖòá‹E,(Ó6Z{h®úv IDATÚr 2ÚóJÒ:îI!Åb1Îd(ÃNV!-¸jT{­Î6;ì”§Ìm9P&íy¥i5ÀjllÔÉ€2ÔØØØâÇfhÏ¡uþFÚr <ÚóJÓ¶5}ˆn³…Êwψ{óã[oË¡”¡C; Ð iÏaÙÛnç]“|ü—;v̪=zdÓM6ÎÞƒ¥¦k×y–K’ÚÚšl¶ñ&9êðÃÒ¥Kç¥òŸ{{¿þÅ£>(ЖeÒ'(­£RðœQ¨– ôУæ[‡–{x0{X••ihßíÝe«=‡’úÕÏI’̘1#ïŒ_þê×9üÛGçÊK.NUV™g¹÷ëësÝ7åêë®Ïi'ðé~#±O_Ýe7¿  -ʬOTi{^aZÕ :YPÙž{þùt^±SöÜ}·üßOäÏ¿/l¶©UÐÉZœç†kÏ¡„(IûöíÓkíµó­Ã×Ί+¬[ï¸3§œpÜ<Ëu««ËÑG™CŽ<*Åb1ïŒ[n¿#/ük²QÿþùÞ±G§k—.I’>ú(×ÝxSž|ú™´]n¹ 4°ÙúZº€¶(>Píy¥i5c€444xÎ(T¸‡y4{ì¶k³Û.;çÁGɦ›lìÀ@…khhhñsõçP:óûîí¸ýWsìñ'6›×ìÏÅÆ¦içœaŽ:ìМxÜ÷òÑìrÛwææ[oËw9:Ir×°{òöèѹþê+“brÑå—/p»-Ý?@[”®OTg{^iZÍ ®2Ê6vÜø¼þ÷¿çôSNN±XÌW¶Ú*?¾õ¶Œ7Î-¶Pm´ö*ó»Z[[›¦Li6oΟë'LÈ7ßš H±XÌuW]Ñ´L»å—ÏA_; ‡}LÓò¿~ò©œ}Æÿ¦[]]’ä¨ÃË‘ÇëЖÚ'ª·=¯$­æÆÆFUh¨`üüç™%ûï;4í–_Þ‚* PÚs¨Œïê/<úõk6ï‘ûFÌ÷µ^riöÛgïœrÂñYq…2uÚ´ìwàAM¯íV×-cÆŽÍÿ¬±z’dÌØ1‹õá·´å@yõ €êmÏ+I«ºÄmxP™ž~æ·éÝûóY¹{÷fßã•WîžuÖé•§ûÛl·Í6Tp'kq®ÕžCiÌùîÍœ93£ÇŒÉ¯Ÿ|*¿ýýïsñyçÍ÷XŸ4cÆŒtìØ!íÛµËøwßÍ­wÜÙlù¯l½UnºåÖ|çèo%In¼ùÖ…®oAûhËòèÕÙžWšÖQIÁsF¡‚=ò‹ÇrÀ¾ûÌ÷;¼ó;äž#²íW¾â@A¨BZð&Ús(©ÝïB¡öíÛ§gU²Ñ€¹òâ‹Òµk×@ŽùÖQ¹ù¶Ûsá%—¥®¶6÷Ø=¿ûÚ–ß{ÐÀüøÖÛrôwËrmÛfà»ç¥‘#úŸûј»Þ;IòЈŸù°@[”AŸ¨Îö¼Ò´ŽG`â*¨`—^x~Óñ'm¶ÉÆÙl“}¿¡‚566¦E},í9”̃ÃïYhPš{¹}G7Ùh@6Ùh@³i»î¼SÓòmÛ¶Í‘‡š#;´iþÀ=v_èw~~ûå7´å@éû@·ç¦ÕŒÒÐÐà9„P¦m´ö´å@e´ç•¤U¢“ågqŸ®=m9Pšö¼Ò´š1@ÜŠe¨¡¡¡ÅÏ ×ž€¶(]{^iZÍ#°cÇÍ´éÓ(+t\!={ôÌ*ÝWI¡Pp@€²¢T„ñïOý„úôëÛ/Ýêº9 Pê'ÔçµQ¯%Iz¬ÜÃÊŠPÆŽ›~}û¥k—®™5k–e k—®Y¯÷zùòH ì(€aÚôi©«­ËÌ™3 (©«­óxJ ,)€aÎsŋŢƒeÚN” b‹E(Ãö )€¡BŠÅb (#Åb1…¸(? @E( illT€2ÓØØèX@YR*ŠÇl@åš:uj~ú³áyúÙgóþ{ï§]»vé·aßìµÇîÙxÀøL)€•¡` ¨tç\paVîÞ=çŸýý¬²òÊ™:uj^92?¹û§Ù¨*T±XŒ'`åH¨sÆQÊõ׿¾œ{î¼#+®¸b’¤K—.ùòV[åË[må» Ì @¹R*B¡PHCCƒ1@ ‚õÛpÃ\vÕ5ÙkݲN¯^iß®ƒU ¡¡Á @YR*†;@ ²zâñqÿ¹æºëóÎè1éVW›-·Ø"û Ý'+®°‚Ü>”# " …466º*X‡òµýöÍ×öÛ7Åb1ÿ~ûÜûÀùá%—æû§ÿ¯ª±±Ñ @YR*†T—5V_-‡|P:üHßm¨ðö )€aÎ ³•ëÔ3ÏÊ®;혾ëoN;¥¾¾>#î ë÷YÏw*˜;@€r¥T„B Æ ·ï!yô±Çríõ7fÖ¬Y©­­Í¦o”ãŽ=Æw*X±XL! @ùQ*C!î ·aß ²aß æ;Ïw*WcccÔ?€r¤TŒ††Ï€2lŸÊ‘P挢åÅ @¹R*B!…444xL”™††c€eI¨Æ€òlŸÊ‘P:vì˜iÓ§¥}»öŠ P& …B¦MŸ–Ž;:@ÙQ*ª=WÍè1£SÓµ&Úwp@  ̘9#“&OÊj«®æ`eG¨µ5µillÌØqc3sæLÊ@ûöíÓ³GÏÔÖÔ¦¡¡ÁÊŠPÒ}¥îéÙ£gÚ´iã€@hllÌG}”Ù³g;@ÙQ*ÆìÙ³ý Ð".ŸªŽPu@€ª£T ê(€UG¨: @ÕQªŽPu@€ª£T ê(€UG¨: @ÕQªŽPu@€ª£T ê(€UG¨: @ÕQªŽPu@€ªÓ¶TÞb‹:GªÜ¨Qû¤¾þzYZy(…¶¥=N¨^ÃeJÆ#°€ª£T ê(€UG¨: @ÕQªŽPu@€ª£T ê(€UG¨: @ÕQªŽPu@€ª£T ê(€UG¨:m€êñ§gŸÊ&[nSöû8G¹ïkk|?Èúβ@µp@:pÿ·óü3¿Éû¿½X¯û4î?=ûTÓŸeXÐ~ν¯zö©\sÙÈ ‹^W¯µ§æªKGæ™_=“g~õL®ºtdÖé5u±ög^Sóˇ~—¯í÷ö<ïý“Çáú«þ’¡ƒG7{ý¾CFçº+ÿ2ß÷•”¾ôÅ ¹þª¿ä÷O>_>ô»œqêëéÚu¶, T€rûanSÌA£sé•ëdÈÀ1iÓ¦¸L¶[êÎûä)m³Ï Ñ ]fէ熫_ÊŸ¯Í^C7Ï^C7Ïs¬ËõW½”5VŸÞ¢íôë;%×]ñ—\~M¯ÜùÓ5æyÿsÿ—$×\¿V¾¾ÿÛYn¹?‡¶m‹ùÚ~oçšÖr²PñYàkû¾ŸÜ½F¶ÛeËì÷MÓðQ!çœþš, TGÛê”—/}qB>˜²|†X-“&·Í›Ohšwꉣ²Ç®ãš-¿çncsꉣ’4¿ºé ›NÌÝ·¾ß?ùt¹÷Ùk÷±Ÿj¿>‹;CæÂKzgèÑYósӸ̇¼•á÷­–;‡­‘úúv©¯o—»îY=#î_-‡ó­EncóÍ&æ’ó_ÎéçôÉc¯Ò¢ýzù•.õNÙy‡ñI’¶Ÿ×ÿÞ){¥‹“€ŠÏßúnÿ<û‡ºL›¾\&Ll—+®í•úO–d€ª Pfö4&÷Ü»Z’dø}«eèà1Mó.¹bì¾Ë¸l¿í»I’¶{7»í<>_þùyÖsææÛ?—¯ì°UýÖ€lØwJY¿ï>l›ó.êsÏ|5mÛÎÿJ·Í7˜G›7¬<ò‹U²ù¦ºþí¶y/göZŽ=qÃ<÷|íbíÛµ7¬•÷;mÚsàoçG7ºâ €êÌ_ØdbFýcEY@¨ A(#«­:=ë÷™’NÛ IòË_­œï|û¬ÖsFFíÙ³Ûää3ÖÏm7¾˜õz˜í¿ún:|ã|ôѼÌmh(¤ûJ³R[;;ãÆwȹ¬û©ömaÇšßaŸœÖ’ÇkýéÏ5yáÅšyè?sÍõkÏ3¿¦fvÞ}¯ý<Óß{¿}jjþœâ Îy%§œ±~^{½s‹ßÜ}~ãÍ3êrÖi¯çõQòÆ›+:Y¨º,°nïsÒqÏ÷NÚPª‚@Ù{à˜ÔÖÌÎïŸ|ºÙô!ƒFçÊk{%I&Lh—Ÿ?Ö#‡üV.¿¦W&Lh7ßuwJßvпrø7ßÊä)msɟϳ¨[*ûýÉ@ó§gŸZâñD~tãZ¹õ†?ç·¿›œ—Fvm6oÒäå³r÷™ygtÇfÓ»¯43“&-¿ÐõžwQïœqʨLš¼|^|©f‘ïá“®»iÍ<4ü¹ì±÷æNTª. l²Ñ¤œ{æ«9ýì>yýïdY *x@™h×®1»í2.»ùb³Á÷öòÅì¾Ë¸´kט$é½Î‡Ùc×±9á´¾9`è; ðïµ×;çøSûf»]·Ì¥W­“³N{­"ŽÃìÙmræ9ëåô“_Ï +44›÷Çj²ëNãçyÍn;Ïÿ´ð[Ù|¤g¾Þº¹ô—ó•­Þ_ìý=¦c³ÿ@µd¶{7ç}ÿÕœø¿Ì·@ È•J LìøÕwóòߺdÌØÍ;Ûc;ä•×:g‡íÞMÇ MWe=ù›•rÁŽóÃsÿ–öíçYßùg¿’µ×œš¶m?ž×X,|ªý[ÚÎíÍ·V̈VÍÉÇý½ÙôoY3û †¾“nÝf¥[·Y9`è;Ù{ÐèÜtËç¹Þßüv¥wò†9ë´×³û.ãœt´ú,ðµ}ßÎw¾ýfŽúNÿî- P©<  Lì3xt®¿iþê¸oµzð[Ùl“I6bõ¦«²ž~¶[ÖX}zN9~TÎ>½æügVÊ%ü-={ÌÈ?ßZ!§ŸÝg¡ÛŸ;ÔÌùó’ÞºþY¸gÄê¹úґͦýëß+äÈcûçØ£ÞÌQ‡ý3IòÒÈ®9êØþù×Û+´h½þK×qlÿ\}é_S[3;wܽÆC])ß?²À²Èß;æ·s×›Mßú«[gÚôåd*Z¡X,“d„ Mâñ Ž>´B²°,”¬R_½£­,, ƪŽPu@€ªS²1@¶Ø¢ÎÑ€*7jÔ>óŒù! @ë˥ж´Á‰Õk¸,r@ÉxPu@€ª£T ê(€UG¨: @ÕQªŽPu@€ª£T ê(€UG¨: @ÕQªŽPu@€ª£T ê(€U§­CP=þôìSÙdËmÊ~ç(÷}mïY@ßY¨î(Cîÿvžæ79pÿ·ëuKÚéÞr‹úÜtíKùýSOç—ý.gŸþZêêf}&A`Aû9÷¾þéÙ§rÍe#S(,z]½Öžš«.™g~õLžùÕ3¹êÒ‘Y§×ÔÅÚŸuzMÍ/ú]¾¶ßÛMóç÷_’\Õ_2tðèf¯ßwÈè\wå_æû^ ’²À5]gçç÷ÿ~‘}yY@¨$ åöÃܦ˜!ƒFçÒ+×ÉcÒ¦Mq™„¬»¶zvØíK¸ïæygt‡œÿýW—éûž<¥mö4z¡Ë¬±úôÜpõKùãóµÙkèæÙkèæyîu¹þª—²ÆêÓ[´~}§äº+þ’˯é•;ºÆ Ìqä¡oeø}«•ä}Ë,µ¶Õ!(/_úâ„|0eù ±Z&Mn›-6ŸÐ4ïÔGe]Ç5[~ÏÝÆæÔG%i~uÓ6˜»o}!¿òéø°m¦M[.w [#n0¥Ù2ŸöJ°E¹ð’Þ:dtÖüÜ´ïç!‡²;‡­‘úúv©¯o—»îY=#î_-‡ó­EncóÍ&æ’ó_ÎéçôÉc¯Ò¢ýzù•.õNÙy‡ñI’¶Ÿ×ÿÞ){¥‹“€ŠÏI²ÖšÓ²Åær×=«Ïw¾, T*€2³Ï 1¹çÞ¯¼~ßj:xLÓ¼K®X'»ï2.Ûoûn’d‡íÞÍn;ÏÅ—~žõœ{櫹ùöÏå+;l•C¿5 öÒ¢íwìÐ}†ŒÎ /Ö,Ó÷ýÁ‡msÞE½s¦mÛù_é¶ù¦óècó†•G~±J6ßtâB׿Ý6ïå¬Ó^˱'n˜çž¯]¬}»ö†µràþo§M›b<àíüèFW|P=Yà{G¿‘ë~¼ffÍ*Í?É,-A(#«­:=ë÷™’NÛ IòË_­œï|û¬ÖsFFíÙ³Ûää3ÖÏm7¾˜õz˜í¿ún:|ã|ôѼÌmh(¤ûJ³R[;;ãÆwȹ¬»ÈíϹ²kÂÄvùæ‘5›·°gÛÎONkɳqÿôçš¼ðbMŽ<ôŸ¹æúµç™_S3;ï¾×~žéï½ß>55³ºî Îy%§œ±~^{½s‹ßÜ}~ãÍ3êrÖi¯çõQòÆ›+:Y¨Š,°ùfSÓuv~ù ¾+B*•@Ù{à˜ÔÖÌÎïŸ|ºÙô!ƒFçÊk{%I&Lh—Ÿ?Ö#‡üV.¿¦W&Lh7ßuwJßvпrø7ßÊä)msɟϳ¨[èö7Ùr›¬¸âGùÚ¾ïä¬Ó^Ë¡ßÚ¨EûýÉ@ó§gŸZâÁtãZ¹õ†?ç·¿›œ—Fvm6oÒäå³r÷™ygtÇfÓ»¯43“&-¿ÐõžwQïœqʨLš¼|^|©f±B]’\wÓšyhøsÙcïͨTM8î˜ä‚Kz§¸„ÃÈ”3À(íÚ5f·]Æe÷!_l6øÞC¾˜Ýw—ví“$½×ù0{ì:6'œÖ7 }gþ½özçjßl·ë–¹ôªurÖi¯µh?¦Nm›;‡­žõzX’ã0{v›œyÎz9ýä×³Â Íæýñ…šìºÓøy^³ÛÎãóÇ?-üVöé™ïŸ·n.½ðå|e«÷{¿FéØìÿP Y`^SsóuΟž}ªéNˆ¥=æ‡,À²¢P&vüê»yùo]2fl‡æí±òÊk³Ãvï¦c‡†œ{æ«9ýì>yò7+å‚‹{ç‡çþ-íÛ7γ¾óÏ~%k¯95mÛ~<¯±XXà¶Ï9ãÕ¬µæ´´m[Ì*+ÏÌ·øgþôçæWF-Ëôæ[+fÄ«æäãþÞlú·¬™}ÎCßI·n³Ò­Û¬0ôì=htnºås‹\ïo~»RŽ;yÜuÚëÙ}—qN:Z}˜»à2çNˆùÝÕ! P‰<  Lì3xt®¿iþê¸oµzð[Ùl“I6bõ¦Û¶Ÿ~¶[ÖX}zN9~TÎ>½æügVÊ%ü-={ÌÈ?ßZ!§ŸÝgÛ~úÙ•rÁÙ¯dÍÏMË„‰Ëç·¿ë–3Î]¯¤Çãž«çêKG6›ö¯¯#íŸcz3GöÏ$ÉK#»æ¨cûç_o¯Ð¢õþù/]sıýsõ¥MmÍìÜq÷ uKzë>TJ(G²Ÿ•B±øñS'L˜Ð4ññ'ÏÐÁC—h…Æ ËŽ;î¸Èå¶Ø¢.£FùZ›OóL`ï  Ò O2<õõ×ËÈ­<ÌO]]]ŠK8Õ=÷Þ“¶ÝaëMÜ@‰BRWU•êùÈ È,œËTµ]åJ/(OAªŽPu@€ª£T ê(€UG¨: @ÕQªŽPu@€ª£T ê(€UG¨: @ÕQªŽPu@€ªÓ¶´›î€VI–®’@FÚÇÑ€VH–…’@êë¯wô ’€eÁ @ÕQªŽPu@€ªÓ¶”/‹ÿÞøŒ76Ó¦Oói@X¡ã éÙ£gVé¾J …‚,r@I”´2þ½ñ©ŸPŸ~}û¥[]7gTú õymÔkI’+÷@(‰’@ÆŽ›~}û¥k—®™5k–3ª@×.]³^ïõ2òå‘ >²´¾°¬•´2mú´t«ë–™3g:; J444¤[]·…>ÚJ€Ö—–µ¶¥Þb±˜b±èì€*Ò’>¾,­/,Km|$@µ)é sF‚wÕTŸ9ý}Yä€RpPuŒ,•~¾,r@)¹¨:¥$W}@*‹)¤ €P2mËå ­3 , ¥}VÁU« €P:A–J?_9 ”JzHÁe_Pµ5кrÀ²æ`©ôóeJ©¨6mËa'\õ­“,,-îªNiï)xî/T£b±˜…Ž}( @ëˢ;@€ªSÒ;@ )¸ê ªP±XLa!—~ÉÐúrÀ²æ ÖŸŽþ IDATê Œì°Ûÿý‰,RÓµkú÷Û0‡ó଴ÒJ-^Çã<´ÈiK{ÿw{ŸÜǾõ¯œzæ™2p`† ܫٺkkj²éÆçˆÃI—Ηè˜ÌoŸç6gùùÍü‘‡øº%yïÕÈ ­' <ÿ§3ü¾ûòÊ«¯¥S§ó…M7͡Ԣ¾z’L:-÷Œ‘gžý]Þÿý,ß®]úõÝ {î¾[6êß¿E}ú¹ûïK³/?÷k»tîœ>ë­›#;4«­ºª“ å7HÛ²8 ÌÓá.‹™0qbî½ÿœÑ%¹ì¢ +fß(Zâ•×^ËÙ?8?GzH¶Ýæ+ó¬ÿýúú\Óó£nÌ)'ÿ™í÷âÌŸ{Ú²*0T\ð‘ZE¸÷²÷Àé{Æ™9cfn¿ë®\|Ùå9÷¬3[ôúó~xQVîÞ=?øþ™Yeå•3uêÔ¼4ò¯¹ë§÷4@>˾þ§íËÏY~ÊäþÊÅ—]‘+.¹È P†}|c€”qCQW[›ý‡Í~~£iúŽ»ï™_>ü`³×Ì™¶ãî{6uâ“,pZ’Ìž=;7ßv{žzú™$É6_Þ:‡ô,¿üòMë<ö[Ge؈{3iÒ¤ôZk­|÷˜ogÍÏ}n‰¼ùíû'_óâK/å¢Ë®ÈÉÇ—ôo¶ž9îVW—oyD;êÛ-nC¶Ü¢Öáñ–¬=3@ëÈœsvÓŸ;´oŸÃ>(ûôÍfïgaYà¯/¿œŸÞq{V\q…$I—.]òå­¶Ì—·Úr¾y`QÇ®¥¯YÒ¾üœå;wꔽ ̈ûîמ´0,kÆ(ãcâĉ6bDÖíÝ»E¯™(~ùðƒÍþüÉiIòÓŸ Ï[ÿþw®¹ü²\sùeyó­·òÓŸ o¶¾^üs.¹à¼ ¿ë'ÙlÓMrÕµ×-Õ÷üÛßý.—]yu~pÖÙh@'²@f—FŽÌÚk­Ùâåûm¸a®¸æÚüíÕW3sÖ¬Šùœ>øàÃüìÞû²æšŸsÒ”©²x–*9À͹JkŽN:åÒ Ï_äUL‹3?Ižx꩜}ÆééÖ­.IrÔa‡åìóÎÏ×÷߯i™cŽ:"µµµI’Á{í™aÃG|ª;.{è…¾þü‹.Éi'^k¯½Ð÷P?aBn¼ùÖl4`ÀgrÈ'ùœ}]Ðü¹çµdý­QK¯¸õû P]Yà7ßÌ5×ß³O?½Ùò ˧žx|FÜÿ@®¹îú¼3zLºÕÕfË-¶È~C÷ÉŠ+¬°Ð~û¢ŽÁÒèËϽκÚÚ\~ñµgKø›º´µuPÊË/¼¿éÏ“'OÉ?œÝxS.<÷œÏ4ôÔO˜UV^¥izÏ=R?¡¾Ùr555Mo×®]fÍšõ™äØo•+®¾6]:wNß 6˜gþN{ìõñ~uíšôχò™ìÏÜÇ|~Ër~KŽ/²@kË#_~9_vEN>þ{Y{­5[üß±cÇ|}ÿýòõý÷K±XÌ¿ß~;#î ?¼äÒœ}Æé í·'ÉÎ{\à1X}ù_<øñ#¯ÆŸK¯¼*ÿxã¬Ü½»  •v ‚çþ,¬óÝ¥Kçì=h`öûÆÁs…å3cÆŒ´oß>I2qâ¤f¯›óÛ:¿ßÛ¹ÕÕÖe츱ùŸ5ÖH’Œ;&Ýêº-vxjÉûh©í·Û6;wÎÙç_˜ãŽ=&_üÂfÍæÿüû–Êþ`é´g…BAh%Yàéß>››n¹5§ŸzrÖýüç?Õïûÿ¬±FŽ8ä›9ðÐÃËz «¬’“¾÷½|÷¤“2 _¿tìØÑI hË‘–µ6åp@˜¿)|÷?Ðìù¹ëôê•{x03fÌȸñãsõuÍŸÅÛ¥sç¼ýÎ;‹œ¶Í—·Î ?¾9ï××çýúú\ÿã›ó•/o½TßÏ.{ Zä2_üÂf9ó´SrÅÕ×äÿžxÂIPÁÁGhYàþÊÍ·ßžóÏù~Öýüç; œü¿gä™gŸÍ¤I“òQCCÆŸ[ïøI6èÓ§ì?§îÝWÊ}úäÉÿ ( xÖ<Dð˜0èÜ©SÖ_¿ONøîwš~+>òˆ\uíuùÙˆ{SSS“!ƒæ|¾iþÞƒ帓OÍÔ©Sóèý÷.pÚн‡ä–Ûïȱǟ˜$ÙzË/eèÁŸêª¯]žç}ÌÙ^K^?gÞ}úäüsÎΙçþ “'OÉà½öüÔèüל}[ؼ–nW[°ø¿‹²@ud›n½-IrÄÑÇ6›>â§w¥c‡‹|ý~C÷ÎÃ?ÿE®¾î†Ìš93µuµÙlãMrÂ÷¾SÖw€Ì±ãöÛç¶ŸÜ™wØÞI ÈeÖ¿/ÿ³G&Lhšøøgèà¡K´ÂaÆeÇwlѲϿø|6ßtóLŸ>Ý™U¤cÇŽyî…ç²ÙÆ›É ÌW]]ÝMî¹÷žì°í \oRê1@⹿PŠÅb )È ”LY< >Ý Yà¼Gîá”i?_@¶h}9`Y*m¤à¹¿|zß;¼b^€V| ²²€P:m|$@µ)i¤œž,»þ¾,­/,ke1ˆ[ º´t YZWX–Jû,}@õ*È ”Ž;@€¥ÒÏ—@(¥6PŠ~¾,­/,KîJ|dh}9`YrP’~¾,­/,K%½¤‚«¾ JƒOa!£ÊÐúrÀ²æXÀRéçË ”Ri ¡ª6ødJÇ @Iúù²´¾°,X*ÁÇ ”’;@€’ôóeh}9`Y2:P’à# @ëËË’;@€’ôóeh}9`Y*i¤P(8# J-¬¿/ @ëËËZIÕ¡C‡L›>-íÛµwõTQà™6}Z:tè €P2%-€¬ÚsÕŒ3:5]kÒ¡}gT3gdÒäIYmÕÕdJ¦¤ÚšÚ466f츱™9s¦3ª@ûöíÓ³GÏÔÖÔ¦¡¡A9 $JZihhH÷•º§gžiÓ¦3ª@ccc>úè£Ìž=[9 dÚ–zfÏž]V€ÊçR+ ê(€UG¨: @Õ)é èÅb1ãߟ±ãÆfÚôi> ¨+t\!={ôÌ*ÝWI¡P@(‰’@Æ¿7>õêÓ¯o¿t«ëæ €*P?¡>¯z-IÒcå²È%QÒÈØqcÓ¯o¿tíÒ5³fÍr†@èÚ¥kÖë½^F¾}zÖ^kÍ 28[o¹e‹úãs¿ßEõ±ç>ÖŸôÉù]:wNŸõÖÍ‘‡šÕV]u±÷eIŽ}K¶ЪrÀ2Ö¦,@+ôø#åñGÊc=]uEVêÖ-ç_tIÙï÷ðûîÏ =÷È=wÞ‘[o¸>={ôÈ/Ù~¿òÚk9åô3rø7¿™!÷šçØ\{åå™9kf~tËu\ùðƒvÇm9þ;Çfæ¬Y9ò˜ïdüøw›–3vlN<íôl< n½é†ÜzÓ ÙdÀ€œô¿§gÌØ±éÚµkÖ_o½üþ¹?6½æƒ>ÈïŸ{.“§Lišöìïÿ ú¬×T\éܹSzôçNn€öóe@¿|Ýq×ÝÙ}×]ûu£ÇŒÉ §œ–õûôÉuW]‘‡ß“£<2O=ýL‹ûãs[T{ÎqžSœøäßçžvË×g^½rñeW,Ѿ|Úsa~Ûh9`Y2@4uµµÙèÐìwà7š¦ï¸ûžùåÃ6{Íœi;î¾g’ÿ^M´ iI2{öìÜ|ÛíMc›/oCúFÓ ;î¾gŽýÖQ6âÞLš4)½ÖZ+ß=æÛYósŸ›ï~_tÞšý}Ð^{æž÷6{?óÛ÷O¾÷_z)]vEN>þ¸l4 ³×Ïùs·ºº|ûÈ#rØQßnq[1g¹öíÛ§×Úk娵ÍŠ+¬Ûî¼3'÷½ÿ†¹]vΠ=÷lzÝÀ=÷È~˜ŸÜýÓœtÜ÷²ývÛæ±Ç•­·üR’äo¯¾šb±˜¿½òj¶Øü ™_ý:»í²SÓ6>êÈ|çø³Qÿ~YcõÕ˺°,Ú9c€úû•×ßO’¿ýN^xñÅÜxÍÕ¹åö;æù­^XÿŽ»îΞ»ï–Á{ý·¯½nïÏçôSNnZOKúãs,n{aÓ:wꔽ ̈ûî_¢}YÒ6kaÛhm9`Y3@4 'N̰#²nïÞ-zÍœ°ñˇlöçONK’ŸþlxÞú÷¿sÍå—åšË/Ë›o½•Ÿþlx³õ½ðâŸsÉçeø]?Éf›n’«®½®Eû1cÆŒ<ôÈ£éßoÃÅzÏ¿ýÝïrÙ•Wçg‘ô_êÇx§¶Ï‹/ý¥éï~é/ùêÿûó,·ý¶Û6-÷…M7ËßßøG&Mžœ$ùÛ+¯f“6Ê+¯¾š$y¿¾>o¾õV¾°éfM¯ï´âŠùη¿•‹.»<}Ôàä "ûû7ÝrK¾qÀi×®Ýb¿ß—þ22Û|yë….Ó’þøÒècðÁ‡ùÙ½÷e͹mµ8ûòiÍoû,]mK½®úZ«9Wp5uì;uÊ¥ž?ß;!>ù»ÙÒùIòÄSOåì3NO·nuI’£;,gŸw~¾¾ÿ~MËsÔ©­­M’ ÞkÏ >b‘¿Í;íññ#«jºvÍe]ØlùÇz`¡¯?ÿ¢KrÚI'¤×Úk/ô=ÔO˜o¾5 °Øw€Ì­¶¶6L™Ò4oò”)©««gÙººÚLùÏrË-×&_Þr«<ñÔo2pÝó·W_Í!ßøF~|ëm)‹ùÕOä+[m•å–kÓ´žb±˜ ûn~n˜;îº;øµ…î@5ké#°ü>úûåÕßñ¥—2yÊ”|eë­šõsç¶°þþ”>H]míBß[ÒŸûý.N{~Óæþ,êjksùÅ?\¬lðiûô Û>@kÌËR[ 4~ñàýÿ “§ä‡În¼)ž{Îgˆê'LÈ*+¯Ò4½g©ŸPßl¹ššš¦¿·k×.³fÍZäoó/¼?Ó¦MË}>”Ë®¼:_p^‹ßû±ß:*W\}mºtl0Ïü¹‹+ èŸ#9äS@êëëÓ¥K—¦y]:wÎûõõéÙ£G³åÞ¯¯O—.›–Û~»ÿ—K¯¼:»í¼S>üðì·nïLùàƒÌš5+ÿ÷ë'sê‰ÇÏ÷óøÆû縓NÉf›lœ ÖýýŠéïßxó­9úÈ#šmkq~«»tîœúú éÑc•….Ó’þø’ô±ç7í~üÈ©qãÇçÒ+¯Ê?Þx#+wï¾Äû²$ç‚¶ÀÒUÚ1@ žû ´^sÿöuéÒ9{˜ý¾qð\Ádù̘1#íÛ·O’Lœ8©Ùëæü†Îïwunuµu;nlþg5’$cÆŽI·ºn‹¬æ§cÇŽ¸Çî¹÷ë·|ûí¶MçÎsöùæ¸cÉ¿°Y³ù?à¾%ÚŸ-÷Øãÿ—ýû5ÍЯ_~ýäS9`ߡ͖ûÕOf@¿ÿ.·Öšk&Iÿõ¯³îç{§X,f½Þ½óУ?O»å—ÏZk®9ßã¸ÜrËåøï›ó~xq®¸ø‡Ÿ*,Tr;W(d@¿Âúûoýë_9áÔÓšMÛyÏóí£ÏOÿ~æ7Ï<“}† ^à2-í/I{aÓz¬²JNúÞ÷òÝ“NÊ€~ýÒ±cÇ%Ú—%=æ·}€Ö––µ6åp@Z»)|÷?µ×Z³iÚ:½zåÞÌŒ32nüø\}]óçôvéÜ9o¿óÎ"§móå­sÃoÎûõõy¿¾>×ÿøæ|eÏä]˜K®¸2o¿óN>jhÈ{￟Ûïº;ýú6¿‹c—½-r=_üÂf9ó´SrÅÕ×äÿžxâ3?¦3gÎÌoþ37Ü|KÿÕ¯›=`ÿ}÷ÉÃ?ÿEîèáLœ8)'NÊý=œG~ñXöºO³õ|uÛÿ—ÛrW6üÏ{ܰï¹ë§ÃòÕí¶]èöÿg5²ËN;溛~ìZmð‘*¯¿ÿóîkößœi-íïmß}óà£æþ‡Îûõõ™={v^ÿûßsÞ/^¢þøgÝÇîÞ}¥lЧOžüÏ ñKº/ŸÕöZcX–ŒP"s‡†Î:eýõûä„ï~§é7ñè#ÈU×^—Ÿ¸75552h`þðÇç›æï=xPŽ;ùÔL:5Þï§ Ý{Hn¹ýŽ{ü‰I’­·üR†¼ÄW„m¾Ù¦¹ð’Kóö;£S[S“M7Ù8Ç}çØy–_Øoûœyôé“óÏ9;gžûƒLž<%ƒ÷ÚóS7–»ì5(…B!Ú·O=²ÉFrÕe—¤¦kצõ®¶êª9ÿìïçÖ;~’ŸÜ}w’dý>}rþÙgeÕž=›m›/o[n»=öÝ Åb1}7X?³gÏÎ6_Þz‘ïy÷]vΙçþ ,;å|d@¿üúû-ýM_Ðë{öì‘ Î9;·ßuwî¾çg™9sfÖ^sÍ ¸×õÇ·Ý’i;n¿}nûÉÙy‡ík_æWø™ó9,Îñ›{û­1,K…âöh„ Mâñ È®¿ATdÆ…!,IFº“ÙÓ]¿?´Û4dé„tÝîª÷}ž²Ô^¨$3@€Bê|Yj/TR¡3@J)¹ê ª4ø”V³ú¡,µ—*Í-°€n©óeŠTìHI耪 >%Yä€âX(¤Î— ör@%Yè–àc ŠdPH/ @íå€J²:PHð‘ ör@%™RçËP{9 ’ )•JzT©ÕÕû²Ô^¨´BoU__Ÿ…‹¦®_«¿ ŠÏÂE S__/ €P˜B@6¹I^~åå4 iH}]½U`ñ’Å™7^6ÝdSYä€Â:ÒØÐ˜¶¶¶Ìš=+K–,ÑC  ÔÕÕe䈑ilhLkk«,r@! immÍFÃ6ÊÈ#Ó§O=ª@[[[–/_žeË–É ¦oѰlÙ²Õ €,ô~.µªŽ êªŽ êºz¹\Μ?Íɬٳ²pÑBŸTýd䈑¾Ñð”J%Yä€B:2çOsÒÜÒœQ;ÊЦ¡zTæ–æüö÷¿M’ŒØx„,r@! ™5{VFí4*CÉÒ¥Kõ¨CÉÛí§Ÿyz•ÁG€ÚË•VèÈÂE 3´ih–,Y¢w@•hmmÍЦ¡«½µ•,µ—*­oÑP.—S.—õ¨"]©ñe¨½PI}|$@µ)tHûJð®ú€êÓ^ïË Á  êXè–:_9 Hf€U§Ø5@RrÕT¡r¹œRJ²È…éÛS¨Í€ÐŠ)¹ï/T£r¹œÕ^ø% @íå€ ³Pu¬¬wÖ9 hf€UÇ"è€,T3@€ªSì RÜ÷ªP¹\Îjoý+ @íå€ 3¨:…Î)¥äª/¨Bår9¥Õ\ú% @íå€J3¨:Å€”|PµJ²ÈÅé[ô˜öÐý<ô𿞃J¥4 ’]FíœS?qb† Öå}ÜwÇíkÜÖÇÞnm~çÊ^?`À€L»u¢ŽÐÍu¾,P›5|’<÷Ç?æšü(ÿý›ßdÃrÂqËè>Ô¥×.X°0·LžœGú³¼úê«Ù _¿ŒÚé]sØ¡yÏ.»¼¥}²û®»æ´SNÊàAƒ:¶Ošr[®»þ†œtüÇsÔøqoù=/¾ôR~xÃó«_?“E‹å[m™ GŽÏ>{íµÊ,±¶y@(VX€î×^¤—Ëå´Ì›)S§å‚‹/É¥_ÔkŽ}}¼ö¶iÓÓÜÒ¢CT øte ª¯†éå—óÕóþ%'ðñüã9_ÌÂE‹rÝ®ïòÈù߸8o´Qþõkÿ”áoœ ä—Oÿ:7Þ|KÇÈŠíójss®¼æÚ|ÿª«ó¥/œÝÑf3îº;§Ÿrr¦N¿=GŽ›Ré¯ç¥—_y%_øÒWrÔøq9ý”“ÓØÐ?<÷ÇLºí¶Ž·›Eä€â™PC' vM9v„óñã;¶>lLî1½ÓkÚ·>lL’¿^µªmI²lÙ²\÷£ëóÐ#&IöÛwŸœtÂñÙ`ƒ :öyÖ'ÏÈÄÉS2oÞ¼l½ÕVù왟ʖ[lÑ¥c_™•ûÊ,_¾<ÓfÜ‘o}ãBç€ žwd€Úªá|ãÍùÈ‘ãó÷¿?I²á†æK_8»ÓûY] ÿëgžÉÍ7\Ÿ 7$rĈ4·4wz^CCCÇÿûõë—¥K—®ñ\зoßl»õÖù‡³?—O~æs9õ¤O¬Õûä±Çò·›lšÍþvSç @ ß5|}}}NýÄ'2dðà$Éé§œ”Ó>}V—¿óû÷ïŸãŽ=&Ç{LÊårf¾øb&O–o\ò­œ÷Õs;žwÐáGüù؆ É{Þ½KN;餔ËåÜq÷Ý™?ÿµ~äG:í÷Ž»îÎI'Ÿ$~ò©öq×´ÛÞòÜ%K–æþŸ<^}e†o¼qÇöÙsæäs_<';æ˜ôë·Avµs~ôÑ|äÈñ]þ xû9 Òúô„ ²^{ýõLž:-ïØjËŽmÛl½u¦L›žÅ‹göœ9ùîïé;xР¼øÒKkܶ߾ûäªk¯Ë«ÍÍyµ¹9W^{]Þÿ6î­ûo]šfÎÌòåËóâK/å²ï|7ûîõ¾NÏùðãV»'þë©ÔÕÕeÇwîàÃèAu¾,P5üÜ?×üà‡™7~æÍŸŸ«®ûAöÜc÷.×ðçüãWóèOšyóæeykkfÏ™“Þðã¼ëï\ãï~ø±G³ývÛuüH’ÇgÛm¶É#=–$ùØÑGgúwfêí3òjss–-[–ß=ûlÎÿÆ7u6€nΕd €±bÀ4p`vÜñùÂg?ÓñüéÓOËw¾wEn<% 9rÜØüçÏŸèxü¨ñãòùs¾œ äΩSV¹mÂQGæ×ß³Îþb’dŸ½Þ— GŽ_ç«ÇÞ÷w{æâK/ËK/¿’aC‡fß½÷ÊÑ9ê-Ï_ݹäÖÉSräØ1Î7=,øÈÕYÃðÁý3çÿþ/§Ÿù™´µµå½»ï–SN<¡Ë5ü1ŽÊŒ»îÎw¯¸*K—,IcScöØu·|ásŸYã1Ýq×ÝùØ1G¯ô±4:o”~`¿Œ9"~ý¼\ãM¹é–[³dÉ’¼cË-3~ì^»²šöv`Ýr@%•Ê9¢–––Ž÷=p_&ŒŸ°N;œ8qbFÝ¥ç>ñÔÙs÷=³hÑ"=ªHÿþýóø“g]÷@X©¦¦¦u4¹eÊ-9pÿW¹ß¤è5@⾿PÊårJ)É Æ @!u¾,µ—*©Ø5@Jîû U|J²ÈÅéã#ª5@€õÎ Í  êXXï¬r@Ñúôˆª/øÈ ¨oOhÁj/øÈP{9 ’Ì ©óe¨½PI…Î)¥äª/¨ÒàSZÍÍe¨½PintK/ €P¤b@JBTmð)É Ç @!u¾,µ—*É @·k€€P$3@€Bê|Yj/T’EЀB‚,µ—*É  :_€ÚË•TèH©TÒ# J­®Þ— ör@¥z ¬úúú,\´0uýê\ýUx.Z˜úúzYä€Â:²ÉÈMòò+/§aHCêëêõ¨‹—,μùó²é&›Ê ¦ÐƆƴµµeÖìYY²d‰U ®®.#GŒLcCcZ[[e QèHkkk6¶QFŽ™>}úè!PÚÚÚ²|ùò,[¶L9 0}‹>€eË–õ¨d ÷s©Pu €UÇPu €U§ÐEÐËåræüiNfÍž•…‹ú4  è? #GŒÌð†§T*É ¢Ð9𓿖æŒÚiT†6 ÕC  4·4ç·¿ÿm’dÄÆ#d QèȬٳ2j§Q2xH–.]ª‡@2xHvØn‡<ýÌÓ« >²Ô^¨´B@.Z˜¡MC³dɽªDkkk†6 ]í­­d¨½Pi}‹>€r¹œr¹¬w@éJ/ @íå€Jêã#ªM¡3@ÚW‚wÕTŸöz_9 f€UÇ @·Ôù²ÈE2¨:Å®’’«¾  •Ëå”R’@(LßžÒ(@m$€îPì-°J>¨Z%Yä€âXè–:_9 H…Î)¹ì ªÖšÖj+Tš @·Ôù²ÈEêã#ªMßžp®ú€Ú$ ÝÅ  ê;¤ä¾¿PÊårV»ö¡,µ—*Ì  ê:¤”’«¾  •Ëå”Vsé—,µ—*­¯€jwÀ!‡uüüwÎÐ 5À 5âÀCÿë×o©”†!C²Ë¨sê'N̰aú¼ûî¸}ÛºóØÛ 0 ÓnØå}´£s@eX@¿&³fÏÎ÷¯¾&ÿýßÿ“$y×»vÌ'O=%#GŒX眰â1¯øø›ßK¹\Îu?º>wÝsoR*åЃʉ?.¥RI§èÎPa}{DƒP+´Ì›)S§å‚‹/É¥_Ô+Ž»ÝmÓ¦§¹¥Å ÐÓƒ, Î_o\ri޽˨œsöç“$·Nž’o\ri¾}ÉÅëœVöØÊJîºçÞ<õË_åûßùv’äë\”‘#FäàÑêPÝœ*É 5zjjḻ&ä˜ß±}ôacrïŒé^Ó¾môac:…‡UmK’eË–åº]Ÿ‡y4I²ß¾û䤎Ïlбϳ>yF&Nž’yóæeë­¶ÊgÏüT¶Üb‹5¾‡åË—gÚŒ;ò­o\Øéý¬ìØ{ò  Î9ÖP篮ÎÿÃÿ˜ ¾þµôïß?I2áÈñ™zûŒn©óßü¼û~ò@N8ñÆI’Žûhn¾eR:ð  s@¥õñ‘ÔæÉhîܹ™8yr¶ßn».½¦=tÜ;cz§Ÿß¼-In¾uRžŸ93—_vi.¿ìÒ<÷üó¹ùÖIö÷äS¿È%žŸI7þ8{ì¾[¾ó½+ºtÿñÀƒµóN6t¨zqÿÞÝwˤۦfÁ‚…ycÁ‚LºmjÞ»ûni«fÎÌvÛnÛñÿí¶Ù&/Ìœ©T™q ,W}TFû•\í˜o]tA§ïá•}'¯ÍãIòÀC弯ž›¡C›’$gœrJÎ;ÿ‚wì1Ï9óŒÓÒØØ˜$ĘLœ4yçƒr¹œI·Ý–þÊWÞòÜ{nŸ¶Ú×;×T¾Î—Ôù««óO?ù¤|îœ/寉·$I6Þx£\vñ7:=Muþ›ßû=·OëÒyiÑ¢E0`@Çön˜…‹9/T TR_P;îž>µãçùó_Ë´3òý«¯ÉEÿòõõŒš[Z2|ãáÛGŽ‘æ–æNÏkhhèø¿~ý²téÒ5žyì±üí&›f³¿Ýt­ÏÎ5€:¿gÕù—|û;ùÀ¾ûæ¨qc“$“n›šK.û·\ðõ¯­Ó{_ÝyåÍÛû÷ïŸo¼‘Áƒ'IÞxýôïßßy  Ê»HÉ}*iÅïÛÁƒå¨qcsÌñ'®P6ÈâÅ‹SWW—$™;w^§×µo¯ì»|EMM™5{V6ßl³$É+³^ÉЦ¡k°Þì–É·å“§ž²Nç ç€ÊŸsJ¥’, Î_åwýÿæ79÷KÿбÈQãÆæ£'ž´Vç†u]d‹Í6Ëïž}6»ïºk’ä÷ÿûl¶Ø|3ç%€nΕ֧'4•÷Úë¯gòÔiyÇV[vlÛfë­3eÚô,^¼8³çÌÉw¯è|¿ÞÁƒåÅ—^Zã¶ýöÝ'W]{]^mnΫÍ͹òÚëòþ}÷y[ÇûÄ=•ºººìøÎVúø‡çCèaÁGPç¯ÎÖ[m•IS§eÁ‚Yð—5@¶~ÇV©ó?øýrÃ7eöœ9™=gNn¸ñ¦°ÿþ:@r@%Y †¬ ˜w|g¾ðÙÏt|úôÓòï]‘['OICCCŽ76ÿùó':?jü¸|þœ/gÁ‚¹sê”Un›pÔ‘ùÁõ7䬳¿˜$Ùg¯÷e‘ãßÖ ['OÉ‘cǬó:Î5=/øÈµ]çþ3gæÊk®Ë §œ–$yç;äógù–ç¯kÈØñoi£ö÷rÐdÖìÙ9óó_H’<úÀðÁý—**©Tþ˵´´tl¼ïû2aü„uÚáĉ3zôè.=÷‰§žÈž»ï™E‹ét›CÆŽï:TFÿþýóø“g]÷@X©¦¦¦u4¹eÊ-9pÿW¹ß¤è5@⾿TFûÕ_wÜ6YcT@¹\N)%Yä€Âôˆ[`@w2èÐ3ë|Yj/TR± %÷ý€ª >%Yä€âôñ‘զОt/0 rõ¾,µ—*­G¬bÚ;T—®®" @må€J*öX.ú€êU’@(Ž @·Ôù²ÈEê£A€"ê|Yj/T’ @!ÁG€ÚË•dPH/ @íå€J*tH)%W}@•ŸÒjV?” ör@¥¹Ð-u¾,r@‘Š) =PµÁ§$ €Pk€…Ôù²Ô^¨$k€Ý|¬r@‘Ì ©óe¨½PIA >²Ô^¨$3@€Bê|Yj/TR¡ ¥RI€*µºz_€ÚË•Vè-°êëë³pÑÂÔõ«sõTQàY¸haêëëe SèÈÉ˯¼œ†! ©¯«×C  ,^²8óæÏ˦›l* €P˜B@ÓÖÖ–Y³geÉ’%zTºººŒ12 imm•@(D¡ ­­­ÙhØF9bdúô飇@hkkËòå˳lÙ2Yä€Âô-ú–-[Ö£€ÞÏ¥V@Õ1T @Õ1TBA/—Ë™ó§9™5{V.ZèÓ€*0 ÿ€Œ12Ã7žR©$ €PˆB@æüiNš[š3j§QÚ4T€*ÐÜÒœßþþ·I’@(D¡ ³fÏʨFeÈà!Yºt©U`Èà!Ùa»òô3O¯2øÈP{9 Ò Y¸ha†6 Í’%Kô¨­­­Ú4tµ·¶’ ör@¥õ-úÊårÊå²ÞU¤+5¾,µ—*©¨6…Îi_ ÞU_P}Úë}Yä€"˜Tk€ÝRçË É  ê»HJ®ú€*T.—SJI9 0}{J£µºC± %÷ý€jT.—³Ú ¿d¨½PaÖªŽ5@€õÎ Í  êX€ªcPuŠRŠûþ@*—ËYí­e¨½Paf€U§Ð ¥”\õU¨\.§´šK¿d¨½Pif€U§Ø’ªVI9 8}‹>Ó޺߇þ×sP©”†!C²Ë¨sê'N̰aú¼ûî¸}ÛÖ·7,ÈW]“ÿ|â‰ô)•rø¡‡ä¸cY§÷ÞØÐÝwÝ5§rR¤cts/ ÔVíþæãóï+—˹îG×ç®{îMJ¥zðA9ñãÇ¥T*­óûZÕcÏ¿ðB®ùáòÌ3ÿ$Ùi§wåäNÈV[nÑé5[l¾Y®þÞ厡\.ç”O~:3_|±cŸ+¾¯U¢Mª-TRX€î×^˜—Ëå´Ì›)S§å‚‹/É¥_Ô£ûÊk®Í²åËríßK’|ÿª«sïý÷gô‡>´ÖïýÕææ\y͵ùþUWçK_8[§èæàÓ•5@¨žÚ}Åc_Ù€Á]÷Ü›§~ù«|ÿ;ßN’|ý‚‹2rĈ<úÀõz ¯Ìš•/~åÜ}Ôøœý™³’$=üHþáÏÍ¿]rq69²ã¹uuuyü‰'òwï}oǶÿ÷øã©¯¯[å{`Ýs@¥™PC' vM9v„óñã;¶>lLî1½ÓkÚ·>lL§³ªmI²lÙ²\÷£ëóÐ#&IöÛwŸœtÂñÙ`ƒ :öyÖ'ÏÈÄÉS2oÞ¼l½ÕVù왟ʖ[l±ÒãþÏÇžk®ø^† I’œqê)ù× ¿‘?øÁ·çšÞûЦ¦|êôÓrÊŸrî¨àyG¨Ú}Mç‚û~ò@N8ñÆI’Žûhn¾eR:ð€µ®íW÷Ø 7Þ”Ã>|pÆÓñØØ1‡çõ7ÞÈoº9ÿðùÏul?jܸÜ2iJöÜcŽm·Lš’ŒŸ½è~ŸsÀúÉ•dt€<Í;7'OÎöÛm×¥×´{gLïôó›·%ÉÍ·NÊó3gæòË.Íå—]šçž>7ß:©Óþž|ê¹äÂó3éÆgÝwËw¾wÅjÿŠ× ”J¥<ÿ >HÔî=°v_fÎÌvÛnÛñÿí¶Ù&/Ìœ¹ÞÛí¿üU>ô¼eûû~ù«NÛöÙë}™7~þç7¿M’<ýëgòÚë¯gï÷ý½P̨íW}µ8p`¾uÑk¼¢imO’z(ç}õÜ Ú”$9ã”SrÞùtZ·ãÌ3NKccc’düc2qÒäUž öØ}·\yíu9õ¤O$I®ºöº,Z¼¸Óóï¹}Z—®kniÉÕ×ý0ïy÷»{*Pç˵U»¯é÷-Z´( èØ>`à ³pÑ¢µªíßÜ6+û}ó_{-MMoÙOSSc^{íµ·l?öˆÜ2yJ¾vîW2qòä9öˆ•¾‡•ýî{nŸ¦Ã¬e¨¤¾ 6Ü=}jÇÏóç¿–i3fäûW_“‹þåëë5D5·´døÆÃ;¶1"Í-Íž×ÐÐÐñÿ~ýúeéÒ¥«<œvòI¹âªkròŸÊ}ûæðCÉàÁƒÖêÜqÐá0 C†ä=ïÞ%§t’s€€ v_ϵûš~_ÿþý³à72xðà$ɯ¿‘þýû¯Õ¹`ŶYÑÁcÆvìgð Ayµ¹9#GŒèôœW››ß’%Êår>ôýòï7Ýœ~$üãóùç¯|¹ã9+>we¿Ûy  g+vôRÉU_²âwíàÁƒrÔ¸±9æøW3dñâÅ©«ûóbsçÎëôºöïì•}¯¨©±)³fÏÊæ›m–$yeÖ+Ú4t­ÃX»n˜/~þ³ÿ¿ãî{²ËÎ;¯Õ¹ã®i· *œwJ¥’,PCµûšž·Åf›åwÏ>›ÝwÝ5Iòûÿ}6[l¾ÙZ º2óûÝ£Få'>”=¡Óã÷?ð`Þ=jÔ[Þ_ß¿\huÉ·ÿ-ÿè±éÛ·ïJ@œ³Þ~¨´>=¡A¨¬×^=“§NË;¶Ú²cÛ6[o)Ó¦gñâÅ™=gN¾{Eç{û4(/¾ôÒ·í·ï>¹êÚëòjss^mnΕ×^—÷ï»Ï:ë7/ûv^mn΂ òð£eÒ”Ûrì„tz·çCèÁG¨­Ú}M>øýrÃ7eöœ9™=gNn¸ñ¦°ÿþë½¶?öèdÆ]wgêí32wî¼Ì;/SoŸ‘;î¾ç-Y¢ÝGÆËŒ)“rÔ¸±:@7ç€J²@X1H 80;îøÎ|᳟éøþôé§å;ß»"·Nž’†††9nlþóçOt<~Ôøqùü9_΂ rçÔ)«Ü6á¨#óƒëoÈYg1ÉŸœpäøu¾ŠlÔÎ;ç³_<' ,ÈŽ;ì¯~ùKÙt“MÞòü®\ @Ï >²@uÕîIrÈØñoyí¿ï Ȭٳsæç¿$9xô9àƒû¯·Ú¾ý±M7Ù$œ÷µüð†çÇ7Ý”$ÙñïÌçýs69r­fu¬øøÊgÚß]Ï•T*ÿåˆZZZ:6Þ÷À}™0~Â:ípâĉ=zt—žûÄSOdÏÝ÷Ì¢E‹ô ¨"ýû÷ÏãO>ž=vÝC9`¥šššÖyÐä–)·äÀý\å~“¢×‰ûþ@5*—Ë)¥$ €Pk€…Ôù²Ô^¨¤b×)¹ï/Tmð)É §¨6ÖÖ;k€€P43@€ªc `½³ÈEëÓ#¨¾à# €P ¾=¡A¨½à# @íå€J2(¤Î— ör@%:¤”’«¾ JƒOi57ÿ• ör@¥¹Ð-u¾,r@‘Š) =PµÁ§$ €Pk€…Ôù²Ô^¨$k€Ý|¬r@‘Ì ©óe¨½PIA >²Ô^¨$3@€Bê|Yj/TR¡ ¥RI€*µºz_€ÚË•Vè-°êëë³pÑÂÔõ«sõTQàY¸haêëëe SèÈÉ˯¼œ†! ©¯«×C  ,^²8óæÏ˦›l* €P˜B@ÓÖÖ–Y³geÉ’%zTºººŒ12 imm•@(D¡ ­­­ÙhØF9bdúô飇@hkkËòå˳lÙ2Yä€Âô-ú–-[Ö£€ÞÏ¥V@Õ1T @Õ1TBA/—Ë™ó§9™5{V.ZèÓ€*0 ÿ€Œ12Ã7žR©$ €PˆB@æüiNš[š3j§QÚ4T€*ÐÜÒœßþþ·I’@(D¡ ³fÏʨFeÈà!Yºt©U`Èà!Ùa»òô3O¯2ø¬˜^~ùå<÷ÜsŽŠ+—˽öw;vmWkÇþv¯$~;¯/ú*æ"ß»cOMö›žrå>½ËV[m•áǯ1TZ¡ -ÌЦ¡Y²d‰U¢µµ5C›†®öÖV+fçž{.ï}ï{5ôR?þx† ¶ÆPi}‹>€r¹\øÕÀú¯ó»šdèýõO¬ëûøh€jSè öûÉ¹Ú ªÏêî½b0z·kúž´ŽŒ @Õ±Ð-uþÚd™z°@7+v ”Ì€*T.—SJ©KY@&€Þ_ÿ·ÿ[]¨´¾=¥q€ÚJ@ï®ë{šboUÒ1 j•dŠct [êü®f¶¶6™z±öšÞ"è+(¹ì ªÖšÖigðj#Tš @·Ôùk“dèýÀ  jôÔ šúj È,` èÝzjMoP(ƒ@w(vHÉ PÊårV»öá Y@&€Þ­}Ès@…™Êà¨é»C¡3@J)¹Ú ª4•Vsé׊Y@&€êÈkÊ•f°ÎÌYk€t‹=ü¯_µ¥R† É.£vΩŸ81Æ ëò>î»ãö5nëîã_Ùï[Óã«óó'ŸÌ-“§ä·¿û} ˜ÝÞóžœ|â ilhÐqÖwêâ í÷  vëü'þë©Lºí¶üÏo~›7Ì{wß='ŸxB´Vû}³öß3iÊm¹îúrÒñÏQãÇ­÷vPÿ—{ä }{Bðþµúår9-sçfÊÔi¹àâKréÅõšc_UYÓã«3é¶©7æðì2jTþ¦OŸL™6=~ó’\|þ¿ê4®óÛŸ#¨ó§L›–£ÆŽÍN_}W–,^’ëo¼1ß¼“­Éß IDATô²üË?ÿS—÷Û¾ï7®”Ëå̸ëîœ~ÊÉ™:ýö9nlJ¥RÕ´+@Oªÿ{Zmo €*?ñ$ISccŽ0!Ç|üøŽí£“{gLïôšöm£Ó)˜¬j[’,[¶,×ýèú<ôÈ£I’ýöÝ''p|6Ø`ƒŽ}žõÉ32qò”Ì›7/[oµU>{æ§²å[¬õûèêã+{oíÞ<Ð1îˆ1¹eòç"€n8Y@ßÕ:þ¯Ÿ×ñs}]]N9ñ„{Â':=ouuþêöýó'žÌÀ3æÐCrÿæçOþWÞ»ûnkÕ®¬^û¬nk€Pñ€4wîÜLœ<9Ûo·]—^Ó*î1½ÓÏoÞ–$7ß:)ÏÏœ™Ë/»4—_viž{þùÜ|ë¤Nû{ò©_ä’ ÏϤœ=vß-ßùÞ=¢m/^œÛï¸3»ŒÚYG(ø\€:E¿|úé¼c«-×˾fÜuWÆzH’ä°CÎŒ;ï\¯í @ÏÕ#n%ð¬íWrµ8p`¾uѾsWöý»6'É=”ó¾zn†mJ’œqÊ)9ïü rܱÇt<çÌ3NKccc’düc2qÒä.÷¯Ë {nŸ¶Æ×tøI’†!CréÅ9tCßÕ, ¨óWô‡çžËåW^•óÎ=·ÓóºRç¿yß³fÏÉïž}6ç~霔Ëå¼ï½sí”Y³ggÄðákÕ®t­¶ïIúö”Æ`ýº{úÔŽŸçÏ-ÓfÌÈ÷¯¾&ýË××k0jniÉð‡wl9bDš[š;=¯¡¡¡ãÿýúõËÒ¥K»u¤«í³páÂÜ6ýö\úoßÍ7/<_§(( X@ßîégžÉ7/ývÎ9ûsyÇV[®ÓùaÅ×Üq÷Ý™?ÿµ~äG:=玻îÎI'¿Ví ÀªõÔš¾Ø5@JÖè.+~·<(G›cŽ?q…€²A/^œººº$Éܹó:½®ý;zeßÛ+jjlʬٳ²ùf›%I^™õJ†6 ]뀵¶Áhm÷³2ýû÷ÏØÃË”iÓ‹ºá<ôæfW—|¨óyì§¹æ?̹_>'Ûo»í:ŸÚ_·té²Üÿ“òë¯Ìð7îx|öœ9ùÜÏÉÇŽ9&ýúmÐ¥v kß¿kʕ֧'4 Ýëµ×_Ïä©Ó:ÝCw›­·Î”iÓ³xñâÌž3'ß½¢óýz”_ziÛöÛwŸ\uíuyµ¹9¯67çÊk¯Ëû÷ݧÐ÷ûá#Æ­ò±K¾ýoyñ¥—²¼µ5zõÕ\ãMµÓ»t€êüÿ@m×ùS§ßžë®¿>|ýkÙ~Ûm׺Î_™‡{4Ûo·]§Á$1|x¶Ýf›<òØc]nWV¯½¦w ¬•„ƒ ëߊá`ÐÀÙqÇwæ ŸýLÇwî§O?-ßùÞ¹uò”444äÈqcóŸ?¢ãñ£ÆËçÏùr,X;§NYå¶ G™\CÎ:û‹I’}öz_&9þm]vÈØñoyí¿¯+¯nÿ{î±{.ºä[yñ¥—ÓØÐÝwÛ5ŸÿÌYÎEÝPçw5 Èêük~ø£$ÉiŸ>«Ók&ß|cú×ׯõù%ùóm®>vÌÑ+}͇‰·NÊ?°_—Ú€®e€žö½Y*ÿåˆZZZ:6Þ÷À}™0~Â:ípâĉ=zt—žûÄSOdÏÝ÷Ì¢E‹ô¨"ýû÷ÏãO>ž=vÝcYàg?ûYÞ÷¾÷i4è¥Úkú5å€7kjjZçA“[¦Ü’÷?p•ûMŠ^$Ö€jT.—SJ©ËY@&€ÞŸÖ”*Í @!u¾,ÕÁ +mk€@5*—ËYí…_+dR©$@d€5æ€ ëãcªM¡ =é^`@åê}Yª¨ö/•zd­ß·èp ,¨>]]Ä-° z2@O«ë‹½–‹¾ z•dŠcÐ-u~W³€LÕ‘ÌY‡`ô¾ðÓÕç¬x¿` ÷i¯é{Úßûͺ¥Î_›, @ï®ÿÍYÇ`ô¾$ @m0de’’ P…ÊårJ«YýðÍY@&€ÞŸÖ”*Í-°€n©ó»šdèýõO¬ë‹)€j @«½ð«dª©þï¨ë{Îk€ÅÔù²Ô^¨$k€Ý|¬µSÿ÷Ä5@Ì ©óe¨½PIA >Ö€êÊ=­®7(¤Î— ör@%:R*•ô¨R««÷e¨½Pi…Þ«¾¾> -L]¿:W@ž…‹¦¾¾¾KY`³Í6Ë/~ñ GŽZt†}»¿¿7gð"½··{‘}þí¾þíþ1­È?ÆÕò±÷ößïs‡®Û|óÍ“d9 Ò Ùdä&yù•—Ó0¤!õuõz TÅKgÞüyÙt“M»”† –aÆi8¨òPi…€464¦­­-³fÏÊ’%Kô¨uuu9bdÓÚÚ* €PˆB@Z[[³Ñ°2rÄÈôéÓG€*ÐÖÖ–åË—gÙ²e²È…é[ô,[¶¬G5 ½ŸK­€ªc¨:@€ªc¨:@€ªc¨:@€ªc¨:}»c§MMMZ(Ìz9úè£S.—µ,P·ÀªŽ êªŽ êªŽ êªŽ êªŽ êªŽ êªŽ êªŽ êªŽ êªŽ êªŽ êªŽ êªŽ êªŽ êªŽ êªŽ êªŽ êªNßµ}A[[[f¾43Ï¿ð|ÞXð†¤p7˜-·Ø2›ÿíæéÓ§þKÕõÝ?üá‹íä“O΃>¨ÿ¢ÿ‚¾ ú/ú/è»PÑþ»&k=2ó¥™yù•—³ÓŽ;ehÓP­Oáš[šó»g—$Ùró-õ_ª²ï¾øâ‹Œéá‡^ãsô_ô_ÐwAÿEÿ}º«ÿ®ÎZ€<ÿÂóÙiÇ2dð,]ºÔ'@ᆠ’í·Ý>ÏüÏ3kü#²þKoí»ÀÚYë7¼‘¦Æ¦,Y²DëÑ#´µµ¥©±©K·´Òé­}X;k=R*•’$årYëÑ£´÷Mý—jì»ÀÚé»./*—Ëþ€L²6ýQÿ¥·ö] ëÖ~HJ)—ËikkÓzôår9¥”ô_ª¶ïkgnÕÖÖæÈô(mmm]¾–þKoì»ÀÚé»®/¬•Û¶,X° 7ß:)üô§yõO¯¦_¿~µóN9âðòë»ßÝ¥}|ðàCò“»ïÔÛz·Zw<øŽŸõkz“ßþþ÷yð‘Góü 33 ÿ¼sûísÈÁ£³á€‡ï7¿û]xø‘Ì|ñ¥ èß?Ûo»m9xt ¨qè%5õÂ\úÝË3oþü|ëÂó5½ÂÙ_þÇ·lÓéM^™5+wÜ}oþøÂ ©¯¯ÏÁ|(ïÝ}7 C¯ûî­¯«Ëù_û'C×ÜÒ’i3îÌŸ>I²Õ–[æˆÃÉЦ&S µ)ÕÖ _¿ð¢l¼ÑF¹à¼¯eøÆgÁ‚ùåÓOçÇ7Ýœ÷ì²K—÷ãî]wÍuWf£aå€ʆ6ìØ¾hÑ¢Üwÿ=sØØ•·oIÿ­„ûïº#Iò¡ª׃.÷]Þ¶‡ûi>°Ï>Ùêã[fÙÒe¹çþûsó¤É9ùøkz¼‡y,ûîµW¶ÙúéS*åáÇ~šŸxKÎ8ù$C¯pïý÷ç}·gîº÷>A¯bÀƒÞêO¯¾šë®ÿq9htŽ;fB/Y’;ï¹×½î{÷‘Ç~šù¯½®aènºeR¶Ùú9vÂQI’~$7Ý2)gžqšÆ)Ð:¯R+øüõ¯ŸÉ-ÿ~C6Üðψ}úi©¯¯Ï‡–äÏ,N’ÿ¸sF’ä¿üU®þÁ2óÅ—ÒØÐ=!>PL2bøˆÌž3;wÜy{ýðá0`@/^”;ï¾#s綬´ï­í þp¿~hÇõÓ†Ö©ŒÓ>qbÇÏuýúå°ƒÊ×/ü††¡W8ã”Îïßgï<øð#†^aÎÿý)¿}öÙüÃg?c Bî½ÿ'Ùÿýûf×wÿùÂÍþýûçcGOÐ0ô*­­­yôgÿ/Ÿ>ýTA¯ðʬY9õ'¤®®.I²ÿ~ïÏ£?ý™†)Ø:­ÒÚÚZ3k(ŒÚyç\úËsÄá‡f›­·N]¿~oyΔiÓó«§‹Ïÿ× ÜpÃ|ÿêkò£ÿ{N=é¹wÆôŒ>lLî1=I:Úí¢o}+Ÿ:íÔì¹Ç™;o^n¼ù–Œ>àCzd’ý?p@î¾çŽÌ77wÞ=#üÀ‡òÐ#dîÜ– ó…/æ”®6~s{ýMŸ¿É«Í-™;o^66,Ÿ=óS®¦ÿ‹ºººŒ>ðùçÞ;3oþ¼L>%år9ƒ ÊA~x•3@ôßÊÓŽÚ°·zù•WrÛí3rÒñÇi z•ö{"¸aÎ<Ý4jz¾ß?û¿Y°pAÞ³Ë(A¯Ó~–åË—gÖì9™~ÇiiiɘCÑ8ôx .LËܹ9û¬3“$Óî¸#Óï¸3G9^ãÐk²òƒ<šû˜Æ ×8â°CòÝ+®Ê}?y IÒØÐ³Üþªpë4¤­­­f®ü®¯¯ÏÇŽ9:;æè”ËåÌ|ñ¥L™6-߸ä[ùÚ¹þ#Äœÿû¿œ|ƧVÚNíÞÜ^_ýò—ró­“rãÍ3pÐÀœ~òIÙ}×]õÈ¿¨««Ë”{ï½+¯½þZ6Üp`Fppú÷ï¿Ò¾×ÖÖÖå µÔ»›v\?mhHeýá¹?æÆ['åcþ{÷U™öü{RH$¤Š¿]B&‚J¯ Mý=‹R¤(kEÑ»‚EPQ¤IoJQ”±íã®ÒÔuQé%!3çù#dHH›I&É$~Þ¾FÆÓÏu®™àuç¾ïAФ*™é¯¾¬ŒË—•¸ó+­\ó¡ÆÝ?’ À¥møäÅ÷íËÏ:TîÿiöðP¨HÝ=d¦ÏœE*…jžžêÓ³‡j\λ_¯^zí7 *Ý{÷),4Dáa¡•ÆŠÕkÔ¼Yœ:uì ){å«×èþá÷œŠü»\Ivú3ëDEjä½Ã4lÔh[ ÂBCôü3ÿ°õÉ')cˆ$Õ¯WWO?ñ¸LÓÔ¿~øA¯¿9[‹ç¿OFæâíå­;ïè®_'ªm›vòññ-4ïÉG@œ‡8ÃÊfמ½Z¿éÝ{ÏÝŠ®E@PI>z©ã­íµcçW.ïÄÉ$Í~÷½<Ëø4K£Rr3 †rC¥Q«V„”«³¹)zž£rÙ¶#Qýûö&¨T:¬a÷Ügç_~•ÀT°÷ùÓ 5éYõìÖUMnl¬~5”––¦5­ÓÚbнkWÍz{ŽF ¿Oµ"ÂuôØq­Z»VyX’äïç§ÃGŽªNT¤í¸S_CC&¨VD„LS2Ü †Â)€···îèÜ5û/lEÄÇÑ ÄÚ9ˆcéѤü$~õµv~ýF¿ß"B¥³lÕu¾­£B‚ƒtþÂmOüR ê×#0py×7tÐøÊdÉŠ•êÒé6…†„(5í”Ömܨ¸¦±•Bë-´~Ó&õí™ÝciýǛԸa#ƒJá—_•g5OÕ‹‰!¨T"kÕÒö/wªã­í%IÛ¿Ü©ÈÚµ Ls¼DÆŸj…! Úôé§zkÎ{ÊÌÌT`` Z6¿IŒÐƒ^Ý»ÉôÊkS•”œ¬Úµjéž¡ƒmëãû÷ÓãO=­ôôtmX³J’ts«–zyÊT¥¤¤(**JŽO1¹LÓ”!ƒü-}ÙÞ÷Ž(I¶¼FÙå.JoæO$I¯½ž·ëÿ+Ï?+¯jÕ\ZãF µxù %§¤È¯F 5jøWÝ5p €2Û¸±–¬X¥”ÔTøë¦¦MuÇí *…Ö-[èô™3zí7dµšº±aCõéÕƒÀ Rغ#Q:t ¨t†LÐG?ÖKS¦J’êÆDkèÀSÁï¿kèOõô±M+¶Iã×åŽAÏîÝÔ³{·×÷íÕÓ6NlβömÛª}Û¶…ޱZ­²«†ü'Ëß²°~õÊ"? (£ÜE©ñǨÌâb›(.¶ ßÅß½€Ýºv鬮]:T:Ü?Š  R ÖÈ{ÿF \L‰0µX,Œ[—b±XÈ_TùÜ`¿ÏB®ÄÑ9@È_T¶Üà˜Íb±Xò.Åb±Ø=ù‹Ê˜»S¢!°˜C®Æ‘ä/*kî°ŸÃ ¾¾¾ºx颼ªyQD†K0 C/]”¯¯/ù‹*›»ãpHth:|Hþòöò&‚¨p—3töÜYÅDÇ¿¨²¹›˜˜HÀPi‘¿ r Aþä.Pn‰iš:rôˆ’’“ˆ *œ¢ëD+"<‚üE•ÌÝ#F,TZä/È_€ÜÈ_¿¹ Tü:ЩS§l ·lÛ¢Áñƒ‹ÞÑ`Ò^¸G‡³"QYs€´ríJÝyû® ’TÂIÐ%Šv¨ÜÈ_¨ÚܨjhU  Ê¡T94€€*‡PåЪ@@•C¨rhU  Êñ 8ÕjÕᣇuðÐA]H¿@@T£z Õ©«è¨h¹¹•¼ 8Ñᣇuìø15¹±‰‚ƒ‚ ˆƒÒN¥é×ý¿J’êF×-ñqhÀ‰:¨&76Q€€233 ˆƒüô×ÿ÷Wíûy_ù6€Ðu…q¤[yT~±peÔ‰J‡šœkÆúBúëòåË®,‹‚ƒ‚K§7€Ðu…q¤[yT~±peÔ‰J‡šœkÆZ’LÓ”iš®„œ;‡@躃Â8Ò-‰<*¿X¸2êD¥CMÎ5cm†$û‹ø—3/ëÀÁß•œrRYYI×OLÓ”‡‡‡ªûÖ_ ù("¬ÖŸbd˜œ8–”à Ò/((0ˆ®;ÈÇjµ*(0È®nIäQùÅÀ•Q'*jr®kɱ ¿ÿ±_AAº)®E K–®de)3ó²Nœ<®Ä¯¶ê†úUdí¨R7¸ª éâhËþ|ìùÀ‘GåkWFȹq$Ö.k2MSV«Õ®cž8yL-›·VÆå Y­Y­Öì—i•Õj‘LÉÍÍM^Õ¼T¿î ªÓ@?ý²W;vnU›VíäååUåâl𦠕sœó!Aa¹A¹^¬\u¢ÒÇX»X¬ Çb}åJ– ÃPVÖ•ì†Óš½¿ÕjkH¹’uE—._ÒÙ³g¡fM›Ëß/@ßþïWjKG¹»»W½X—ò÷¿ïâ`ËUepÛÝ´c˧ùÞ£dIiO«œ«çQeÈg´€T´ªXo,oU¥&爟~þE¯N¦£ÇŽ•kÏÑXÛÛb±dÏûa½Úàaš¦Lå¼Ï9föË×ÇGûûUmZ·Uƒú7èü¹súç÷ߨMëvUjĘ éb†­ûMU’û~ªê—ííÝzhÛ§Ÿ”yíínWyäH \=ì5€+«ªõÆòäê5¹²0gîû5ü^µoÛ¶\ïÇÑšœý Y2•ÓkäjÃÇÕ¤«“¡g?Eyzz*óJvOÃ0§´Ó§””œ¤ð°p>¹x”tG{Üá#G5Ñ"íÚ³W—.]Rƒzõ4dP‚:´oïܽ§¶nÞä”cå¾gvëܽ§b¢£5oÎÛy>¦iê¾ûÇèð‘#N»‡âlݼÉ康9r=Ò{óækïO?É4MÅ6¾Q£†ß§úõê•I ìÝ.==]ËW­Ö—_­Ô”TU«VMMc›¨_ŸÞjÞ¬Y¹ç2@e䌺Uçî=ÕªEs½úâ ùŠÔÔ_œkGŸKŽÀÀšjÕ¼…ÆŒ)¿ó÷ÔºeK×ÎËÁ!°,YÙó|ä }¥œ«í¦Ì<÷öòÒæÏ>‘¯¯:ÜÚQu"ëè÷ÿ|*óbm…Gß.ÒHÓ¥G/Û{?5jØPcGTdíÚeŽ.=zé‹O>vЮ={e±XtS\œÿ€üýmçqï0­ùè#Y,VuêØAcFއ‡‡ÝësÇ©°Øæ<›·ß›«Ä_ÉÃÝ]ñýûéý mû—6)ýø`éRõéÙCñýúÚ– è×Wç/\ÐK—iâãå»Ç×ßwÎ{‹Å¢%ËWhË[uñâEÝ=d°ôÏ—ûûM“^xIƒâ¨ß>ù®mïÞ}Z¹äU¯^]’äïï¯íÛ«CûövåRa¹\_ÍÑ:Qq;FãyT͛ũNTTžuŽÔáÆ£Uk?TjZš¢"këïãÆéø‰Z¶r•RRSÕ ~==þðC¶sWKüq×n½7¾9ªÀš5u÷ÁêÞõN§ÜsYÕäœ)çœÁAAz`ôh =ƶ¬ :kYÔÓÊ3Ö÷±X²Ÿ»§GÎÜFÎ{Ã6ˆbêÆ(¦nŒ.]º(w7w%§Ü%F_nùMI‡·),úö"Ÿ…_8 ¿V¯ýÐv­ËW®ÒæÏ?ÏŽy›67zÔµÞ½[sç/°åð]ƒÙr¸¨}ïìÕÇöœ%ZG/ð:KYþtsø É0d±XlcÅöúq×nu¼µ}‘Û,]±RÒì×ghöë3ôÇZºbežqè¾ÿ÷šúêËZ½t±Zµh¡7f½%«ÕªÏ6®—$}¶q½>Û¸>Ï>»÷ìÕÌéSõé†uvŸ§ ÷k>Z§Ý{öêµ—_Ò¢¹ï*++K /)ò\׿$©Ý-·èÌ™³Ú÷ÓϲZ­Úµ{Î;¯v·´És¾^™¬Þ=zhéÂùZ2ž‚ƒƒ4oÁÂ<Çú÷?ê­7^לY3uäèQ-[¹Ê¡õöÄÖjµjÉòJJJÖ»³ßÔ[3_×»vçÙ¿°—Åb±{¼Af g žIDAT{ò(çõûÔù¶Ûò-ïÒ©“~ܽ§À{,îù®X½F{öíË~¾ï¿§äÔÔ|Û}ûÏjâ¤çôÀ˜ûÕ·w¯¯­il¬f¼9[{úI—22 ܦ¨\*,—kWæh¨¨—”=Aôø±c5yÚtef^)°.dOî»ï¿×ä_ÐÚåKu[‡zêÙçôÕ7ßèåçŸÕꥋus«VyêiÅÕ'OŸ®¡ƒêÃË4mò+úù—ÿ8åžË²&ç¬WîØ[­VYÍü5»ëë¬eQO+×XËÈ;¡y1¯œI¶†ºz.S?õŒ¶/¾Y‡ö-”arsw“»»»ÜÝÝU£†ŸBBB$ÃC?ÿxD7ü¥ší[Pày¤k 3çÎ×Ê5kU·nŒLÓÔÚuëµ{ï¾k1·diÑ’¥¶í§LŸ‘'‡ùϯ¶uEí{ýó²7&V«µÔ¿îV’칸sçÏ+(0°Èm¶íØ¡1#G(88HÁÁA3r¤¶íHÌó0s¿ÂBCåå奸~}µÿ÷ß |X¹—9"Ϲí9OAï7¶EãFRxX˜ªW¯®÷ÓÎo¾)ò\]$Å÷ï§•kÖÊ4M­X³&OϘœmßyó 5m¢jžžòõõѰ{îÖ÷?üï|ÁAA  ÒèÃõŶí­·7¶Û5jø½ TP` îqŸÝÏÞ™y”ó:{‚òÇ9((PçÏ+6' z¿å‹­;j”""ÂU½zuÝ?ü¾<Ûmøx“fÎ~[/Nú‡Ú´n]èµM|üQEEÖÖìwæ(aèÝ6r”æÎ_  ééå’#ñ¨¨–z€²P’ºHQÅÝØ&Õ46V,]V`ýÅž:ÜCŒSDD¸¼¼¼Ô¿Oo]ºtIãÇŽQDøµeÿùïí®ÿ¸»¹+5í”NŸ9£Ð=ôà8§ÝwYÕäœý\LÓTjZšÞ~w®njÖ¬È:kYÕÓÊ3ÖŽ°deIÊn8ÉiøÈ.þ›ú9ñy¿êæÎƒtxÏ,y¸{äy¹»»K†”•™ª”çv^gŽo-ô\]{÷U×Þ}•p×ÝúôóÏõô$I›?Û¢ÆÜ¯ˆðpÕ¨QC#ï»W;¿ùÖ¶Ÿ»›»ÒÒNéÌÙ³ ÕÃã°­+nߊâøX†‘§e®0~~~JMKSDxá³Î§:¥°Ð0Û±"ÂÕv*-ϱlÿíéé©ÌÌÌ<ë ºŽàà <Ëí9OAï“’“5b̸ï¿°sÄjµªómµdÙrmKLÔ5iâ“yZ?%iÿo¿kþè÷?èÂ… ’$77·<ÇÏ}áaùõöÆ6;f¡¶ÿ +4Þ×ß«½­ÍöäQ¥¤¦ªVDDžå)©© ¨PlN´>5-Uáá…^ÃÚuëÕùöNº¡Aƒ"¯ÓÛÛ[÷ ¢{†‘iš:|ä¨Ö®[§)Ó¦ë¹ÞÉjyçZýkËP…Öë#w÷«e}3û_¦¤ŒóÇTãòGªUß_ii^ «Û´Ðso^ÿ‘LÓÔɤ$MŸù¦öÿö›BCB””œ¬á£ÇóIOMÔ²U«´dù ùùÕÐè#Ô²EsÛó*jß’€¹“;8ŽžçZÑ?DÏ?ó…‡…xþ‚ÎUX¼ÜÝÝÕ»gMãMýÿ»†ÊÝÝ=_ÈäiÙÝàž|ìQU÷õUúÅ‹ú?Ãòœ/÷}?q"ß}·ÞÞØéÄÉ“¶ÉÅŸ8aW’:’ÄŽ|Ù6‹ÕÖí;t×àAy–±m»âšÄÚŽSÍÓS—.]’———$éô™3…ÞwHpˆŽ?¦˜èèÏ9ù¥4qÒ³ªîë›gî‘âÔ‰ŠÔÈ{‡iبÑvçRa¹ì¬X¸²²hqssÓ#ãÔ«S§iÆ”W󬳧WÜ/Ù^¿¬¸úOýzuõôË4Mýë‡ôú›³µxþûN½çò޵#>þpM‘×}}ÕžÚlE5€Ø#§Þgo?ëjˆ»››mÿÿ|ý|½Î*®ËJíþâo:þß­’¶jÇïæÛßÓËKqê)æ/´ûÛŠlò·Bϳ<"<\~XM˜ fM›*,4T/>ûL¾˜çlß ~==óä2MSßÿû͘5KKÌ¿ú¼ŠÞ×0 ‡4œñ à%šÄž±Ë†¨ ›>Ѻ •’šªÌÌLýúßýzåµi¶m:´o§÷æÍWJjªRRSõî¼ùêоÝÃùûùéð‘£…®/Éyr¿ïÞµ«f½=G‡Õ•+Wtàà!M™>ánV¹·IèßOëV­P|¿¾®ÏÈÈ·¼ªUSRr²f½='ߵͿ@©iiJMKÓÜù ÔñÖö­·7¶Ú·ÓÜ •–vJii§ôþ‚…vݯ£­Íöv+2h >Þ¼Yë6lÔ©Ó§uêôi­Û°QoþTƒضkР>\¿A—22t2)I³ß™Sè}wît›æÌ§'Oêüù š;Aží‚ƒ‚4ù…´å‹­Z•k" ë_O>3I;¿þZ§OŸÑ•¬,LJÒ‚ÅKtc£†vçRA¹ì¬X¸2GëDöÖâLÓT¨Hu¿óÍ™;/Ï:{êpÅÛÑZâk3^×á#G”••%Ó” 7ÃiC2•UM®,†À²w½3j³eñr´ˆCs€’áæ.77w™Ö ?¾^qŸ–5ýs5jÑAÝî™Rè«Sü$†Åéçý a ˆèhW¬CB‚Õ¸Q#mOüR=ºuÕÌ·ÞÖá#G®Æü &O›nÛvò´:t8;‡%S†áf[WܾÙõÏ#å>ܘãC`ɰëäµ""ôÒsÏjÉòåZ¾z._¾¬zuc4 o_Û¾ƒâµpñ=<á IRû¶m50~@žctžœeñýûéñ§žVzzº6¬YUè>Žž'ç}¯îÝdHz嵩JJNVíZµtÏÐÁÅ^_a×[ÜúǎѼ…‹4yÚ ªŸÞúæ»ïòìÛDl‚,YYºµ}; Ðß¡õöÆvPB¼æÎ_ q=,wõêÞM»÷îµë^왘ÆÞ<ÊQ»V„^zv’-Y¦%+V^ý!å£É/¾ ÚµjÙŽ3vÔHÍž3G«×~¨š5k*¾__ýóûxßúöQFF†&>ó¬2224x`B¾íkꕞÓ?ž{^‹Eƒâó]Û„múôS½5ç=eff*00P-›ß¤GÆ?hw.–ËΈ5€+s´NTœëÓ³{7=ÿò+yÖÙS‡+ªvVвâê?7·j©—§LUJJŠ¢¢¢ôèøñN½ç²¨É9“½5ÒΪ͖Å}ØkGz€X²,2dÈÍ0d†ÜÝýäÞE¿~û¼þÒr¨ìݦcû?+ü|†›’Óëë¦/É?âv™W‡Ç²'Ö]»tÑÂ%KõÆÔ)2 é¥É¯))9Y‘µkéž¡CmÛ·iÝJ/O™¢ääÕ‰ŠÒc]ËáÞ=º¹ïÀýõè“O)==½ÀÞ@qÆ$è†yõ N:e[¸eÛ Ž\à_lÿBqMâtùòe¾ËY߃µ~õʯ/ƒ‡ë•צ꽷f¹———vïÛ­.º¹]ió(++KOxBƒâÕ¾mÛ?e>ØkWF½±ôÊ«&ûcýù¶ÏÕ¢Y eddØuÜÅKéÉ OéBúy†!7ÃMçΞѱ]—õ3ª×¤•ìû^.×QHÃç¯NÿaÚ:<=«iæ¬;úÁìIÑ«oooý{׿uÇíw¸~åÚ•ºóö; \$©„s€X,æ¨ Μƒ£8ó} }ûèÊ•,Í[¸H7·jYìñs&ë)ër–W•ç댆:’ž˜ J›”äQŸêD¥±v­X;2 zVV–BCõwß5+°‡‰·o‘ÇØÿÛ¬+W®¨ZµjU&Öå>–¯¯¯.^º(¯j^|P÷Cmºxé¢|}}É#Š5€+£NT:Ôä\3Ö2d×pc¦i*%%E^ž^úä“MZº|‰,YY¶ÉÍMÓ¼6áyΟ¶uÙ†¡  `ÕŽˆTRR’jÕª%77·Jo«ÕZþC`E׉֡Çà o/o²6—3töÜYÅDÇG.kWF¨t¨É¹f¬é¨ nPLLÝR]Ÿ‡‡‡‚ƒƒeF•hઠá2MSGŽQRrYE׉VDxyäB±peÔ‰J‡šœkÆZ²¸1Õ®]Û)×èææÆ ¹c[’FÖŽTTd|ìýp‘GåkWF¨ô¨É¹^¬í…Q†¬*‹X4Š#<ÊúAäŠCˆXW%>>>Ì·R 9ó­øøø”ê8„ça¾•ÒqÖÈ4€àDÌ·R:Κ™œˆùVJÏC‡Ñ@`þŠÅÔò Ê¡T94€€*‡På: úʵ+‰¨”þ…œ9=r.-IEND®B`‚antimicro-2.23/other/appdata/screenshots/controller_configure02.png000066400000000000000000001612751300750276700256370ustar00rootroot00000000000000‰PNG  IHDR@„ùMý¢bKGDÿÿÿ ½§“ pHYs  šœtIMEÞ ¾83 IDATxÚìÝwxU߯ñ{B %ô„"ÍB‘¢€XPD± Ò•^¥Y@¤÷"]Š"HhÒÄQ)">*¡úHc”„yÿÀìKúîd7Ù™ý~®‹K³mÎÜçœßîædfŒ3gΘp€®{4½Ã# " à4,€Ça8 ÀqXŽÃp@€ã°‡à8,€€DUñeBüpùËÜLªN©Vö×ûN]¶Wv˜« KœŒã—%s™ìÈ©ÒXõ_NôœaÕ²om?FØ.'6ŸScާ$»Ôh_ÜmìÛ¿_õ_oªù 1ðÝ̯y›v2M3Öí¦iªYë¶~û>ÂûÎL¤­;)TýÅ—ñ 6ìjÇÎ]êݯ¿Ú¶j¡jO=E n ѯ¿ý®G+UtÝö˯ÿUÆŒ ¤@ðS7oÞԔϿÐOkÖJ’ž®ú¤Z6{[éÓ§OðñÕ_|YÚ·ÓÜ túô,_;tБ£G1wžN>­{ŠÓû]:ëî» J’9¢iÓghsd¤¢££U¾ìCêòNG…fËïõÿ·{·zõé§ú¯ÕUÚµdš¦"æÌÕò•ßëÊ•+zìÑÊêжM¢¿èðd[®ýéÐ^sæÍ×¹óçuO±bêÖ©£Š.,IIn¿ió–êÛ«§Š.$IZ¹ê=WýIÒþÕ«o?͘6Åã6nÚ¼EŸMû\RŽìÙÕ¤Q½X£F²÷ݹ°uóæMMøl²V¯ûYÁéÒéµ:¯jÊç_¸îOn¿­ôsr}•Ô6cþ:6æ¿î.ÐUñeµlö¶æ/\¤èèhU«ZUm[µPpp°ëþ¶-[èëE‹uúÌ}ÿŸ¥É¶ÓjþžösRytyÿÕzé%=]õI×ëìÕ[ë7lÐàþ}µpN„­TQ£Æs=¾ïÀAª]ó%Í™ù¥fù…rçÊ¥i_|ÿuûM=zöÖ;íÛº~·`ñmÞºUà Ԍϧ**:ZÓg~•hÛÜÝÖþظQ#† ÒÂ9ªøp;Þu_RÛ¸BymݶM’têôi›8IWÿùG’¹u«©PÁR ¡& ëkÉü¹5lˆvîúË­ûîôÕì¹:qò”¦N¯IcÇhÓæÍí·•~v§¯ÛfÌ/„V-ûÖ㣓6nÚ¤Ic?Õ” ãtèÈáxãwËÖm7j¤ë—iɵÓù»;Ë£Iƒš1;Öi^fFÌVÚµ’\üðt¹³¤òM®~¸“AÜþ‰˜;O‡Ñ” ã4aÌhýöÇF·Æ/öÝÓZw_âš3ÿkmݾ]ÃÔÌ/¦éôéÓÉî—;ÏIhß½Q“›[‰Ih>'6ÇÝÉ5¹Zeµ¾'׿”¾G$fÝúõ>úS èó‰kñ#æª7æ$=ùøc:þ¼¶ïÜyû9‘[uñâE=ñX•¾¹SRõÞ“~Oll¹“¹Õ9R ø©~Z­ö­[)OîÜÊ“;·:´m­~Zäsº½ÓQùóåSÆŒU÷•ÚºúÏ?êܱƒò…‡»nûë¯ÿ¹?yü8•-SF!2(sæÌjöfSý¾1ö/J–|û­F§}>Q•Ê•]·ÿgÅ ½Ó®­ÂÃÔ5KµnÑ\ëÖÿ’hÛÜÙV\:´WxX˜2f̨úuëh÷îÝnmÿáòåµeëVWŽé3dÐêµ·ÿÒtËÖmz¸ByKmL—.HgΜÕùó”7OuëôŽ[÷ÝéÇÕ«Õ¶e åÊ•S¹råTÛV-=Úo+ýìN_%·M+Ú·n¥Ü¹r)w®\jת•VýøSìûÛ´R®\9Ýn§7òww,&–ÇÃÊ+S¦ŒúiÍIÒ‘£GõÇÆ?õj­š‰nÏÊrg;Iå›\ýp'ƒ¸ý³êÇŸ\ÛŒyÍäøjß=­•q÷%®•«V©cÛ6ÊŸ/Ÿ²fÉ’à¼ôô9‰í»7jcrs+µÞƒRR7¼Qs¬¾G$¦ÿà¡jߪ•î»÷žX·;}®zcI’aª_·ŽæÎÿZ’4{þ|5x­® ÃHñç›;%Uï­ô»•9™sxÇhà§Îœ=«|áᮟóç˧ÓgÎ$ùœœ9ÿÿ—!!!·oË‘#Öm×oÜpýü¿¿ÿ֔ϧk÷ž=ºtù²$)((ößG|½p±ž{æ¿ÿ¾X·Ÿ]O=ù¤¾üj–¼V×Õ ±:‡’ÛNRù&W?ÜÉ nÿœ>s&Þk&ÇWûîi­Œ»/q:}Æ­ýñä9‰í»7jcrs+µÞƒRR7¼QsRZ÷âêÒ±ƒFŒ«l¡ÙT¦t這«Þ˜C1ž«þŒ¾œ¡W¯ÑÞ}ûÕ¯WO¯|¾¹SRõÞJ¿[™“©1€w°€ŸÊ•3§Ž?®Â…n_Çâè±cÊ+—W·ÑðP½Ñ¸‘z}Ø]™3gÖ•+WôjƒF±3rè`½Û½‡²fÉ¢ú¯ÕuÝž7o^ ê×Gáaa^Û–'’Ú~¦L•/_¸Ö¬[§ ªTñÍœ=[¿üú«ëÈ +m¼ïÞ{Ô§çÇ2MS¿ýþ‡†úTófÍLö¾¸ýzüø ×õ9Ž?îó±äi_Ååé/bÜ9~?oüÆ}ÝäÚéü½1­TI_ÌøJS§©;wéý®]’|¼Õ9”Üv’Ê7¹úáNqû'w®\q^3ù±ë«}÷´V&7†óäέ£ÇŽ%zý +ÏIlß½1“êû 2èúõë®_ÀŸ=w.Ù,º-5Þƒ|Yƒ¬Ô½çŸ{VÙ²eSï¾ýõ^×.ªR¹R@ÌUoÌ¡éÓ§WZ55dÄH½Ýô¯[–Üö’ÃIÕ{Oû=¡ýr'óäÞ߀ÿàXø©jOUÕøÏ&ëÔéÓ:uú´ÆO𬧫Võê6®]»¦»îºK3fÔ‰“'5r̸xÉ“;·F¢å+¿×ìyó]·×|éE3VRTT”öí߯þƒ‡¤h[žHnûT¨ ‰“§ªúÓOK’žyê)0I<\Ár ª*::Z’dnÝ·_'N™ª3gÎêÌ™³š8eªÏÇ’§}W¶lÙtðСx·Ç\861'OÑé3gtúÌMœù„š4¬ïÕmtëÜI“¦LU¿Aƒ•3GÕ¯[GëÖ¯÷¸\¹rjÄAz·û‡ŠŽŽÖëêÕZ5dêÝ€Ž?¡‚ èí¦¯§x[îJnûT(¯/fÌÔÓUŸ”$=]õIMš:M—/o¹U*WÖ'ýêÄÉ“*t÷ÝêñÞ»nÝ·_Ç6Y-Ú¶Sºà`½RóemÞéÓ±äi_ÅÕ¨~=½Óõ]]¾rÅu¡Øm;vèR¥’|^¹²eÕ¦c'EGE驪Oªqƒú)j§7ò÷ÖX Rüùõ\õgÜz¼Õ9”Ôv’Ê7¹úa%ƒ& hÂg“Õ²m{¥ Vý:¯êÏM›Ódß½]+ë×­£k×®©ëûÝuíÚ5½Þ¨¡Wž“о{c<&Õ÷]:¶×ˆOÇjö¼ùÊ‘=»Ö{M¿üúß$çsB·¥Æ{PJj/ëÞƒ¥ÐðAƒÔ£W/]¸pAõêÖqô\Mí¾Nn{Éá¤ê½§ýžÐØr'sOßß@Ú1Μ9c@ÚØ»o¿zõ맯>Ÿf«v¿ÛýC½Þ¸¡Ê–)“àýÕ_|Ùí_TÚQÏ>}õtÕªªöTUGl'3¯ÎÓ5b¦wx„S`¤¶‰“§èì¹s:qò¤&N™¢Ç}Ôvû0|ðÀD?œÌ4Mýgù ?qÒut‘·ÈŒWçãX©,,,Lí;uÑͨ(U©\IÍš¾A(6ñìK5¦^v·|qxÚN g 0^œS`ÇàXÀ±XŽÃp@€ã°'Ø­üq%I€4ñ\µç<~N°»lP· €T5wÁ\KÏãXÀqXŽÃp@€ã°‡à8,€Ça8 ÀqXŽì‹½uë–>¨ýöëò•ˤì†,™³¨Há"*T°‚‚üw]оõNß’#9’#5›šÍ!G#5›šÍ!Gr„õšm—|í<6œÖöÄDEE)r{¤N:¥›Q7™ˆ€¥N¯YÙ`¿J—*­Ðl¡ºqã½ê†Ðl¡*~_qm۱ͯ¿˜Ñ·Þé[r$Gr¤fS³™#är¤fS³™#äHް^³í’¯Ç†ÓÚž˜S§N©B¹ ÌU çgÉâ%µqÓÆTÙžO@._¹¬\9séúõëô¨›¢££•+g.¿?,–¾õNß’#9’#5›šÍ!G#5›šÍ!Gr„õšm—|í<6œÖöÄÜŒºÉ\Ò`~¦Ö)ç¸:pŸ]eÄ4M™¦IÂff—vÒ·)ï[r$Gr¤fS³™#är¤fÓ·Ìr$GX¯ÙvÉ×ÎcÃimç=¼Ïç‡à8,€ÇñÉ5@ Ã$Η‚ìü½}ômÊú–É‘©ÙÔlæ9‚©ÙÔlæ9’#¬×l»åkç±á”¶ó æçsŽŽÃp@€ãûê…MÓäÜy2³K;éÛ”÷-9’#9R³©ÙÌr9R³é[æ9’#¬×l»äkç±á´¶ó ÞçsŽŽÃpŸ,€2HÖ¡ÙÑ·ÞÉŽÉ‘©Ù´9BŽ Gj"5›9BŽäë5ÑnùÚyl8¥í¼ùù—k€øÎMX}KŽäHŽÔlj6s„AŽÔlú–9BŽäë5›ëhÐö@KŸÏ=Ç)°€ãûòÅY9u.ú–É‘Aß’#È‘Aß’#9‚É—¶3–ø3ß,€:f¹Ðúûié[ïô-9’#9R³©ÙÌr9R³©ÙÌr$GX¯Ù†ÍNÅdÐvÆ€´ø|Î)°€ã°‡à8>¹ˆ!ƒsçY`š¦ ??91}ë¾%Gr$Gj65›9BŽ Gj65›9BŽäë5ÛNùÚyl8©í¼ùùœ#@€ã°‡à8Á¾|qÎç\ô-9’#9‚¾%G#9‚¾%Gr9’/mg,ðg‡à8,€ÇñÍ5@ŒÛçÍãÜyž1MS2ü¼‘ô­wú–É‘©ÙÔlæ9‚©ÙÔlæ9’#¬×låkç±á¨¶ó äçsŽŽÃp@€ãøä † Îgiš2üüäÄô­wú–É‘©ÙÔlæ9‚©ÙÔlæ9’#¬×l;åkç±á¤¶ó æçsŽŽÃpß,€ëØìè[ïdGŽäHŽÔlÚÇ!G#5‘šÍ!Gr„õšh06h{€Ž%€Ïç öÕ sîôíÈOÇè?7ip¿¾2eªGÏÞ  Síš/Z ¾Ÿ,]¶\K–~«Î;È0nÍŸ/Ÿ^ Ð\­æÈ÷@ïæè”ï1ûi†òæÉ£ÖÍ›é±*ƺ=w®\z½qC3.Áx« ;vîR¿Áƒ¤ƒ©øý÷¥Zîo4näúN¼výz½ô| Ëûóú°·G*Tдé_ê‘òå=ÊlFÄl¿pAÚ·ÓÃÊK’®P^o¾ñºÆŒŸ _E¨[çw<~]Ÿ-€¤Å¹ó⮯øæö×Ò”ÒÆ?7©}ç®*Y¢¸*=òˆj¾ø‚2fÌxû `×®Û+U*MÏ÷g§‹HùC[ëoÌ5±‹†Ù!ÇþùG} ’ajߺ•ßÍ;äø|­W\ÿŸ7o½Û¹9z˜ã¯¿ý¦•«~И‘Õ.]_Ìoj¶wkMͺõ’AeJ?¨¶-[(wî\ÌrŒ9*ªßà!:tø°Š-ª.Û«p¡Bähazÿ=Í_¸Hë7lжí;´mûmŽŒÔ€Oz3ÚØßð^ŽQQQê;p°ö8 ÷»vQ•G+˜…W|³XW¯^Õ¢o–jfÄl 5Z#"4r=v¼úõî¥ì¡¡„ä°¾¹ýúõëZ°x‰fÌŠÐåË—5d@?Bó Ǩ›Q’¤o¿)Ó4õa¯O4bôÉi ­|†XðïÑ ëÕ‹õ… îå8rì8é­[¦©ž}új䘱ê׫'¡Ù¼o»uzG£ÆŽSï~T°@~IRúà`óÒ÷óöoÈ‘ïyiž£Ó¾>_놡p¿¾Z¿áW?qBßüç?úzá">4U÷Á[m¸ë®»tôØ1=vÌçß­îÌý&4vÂ$בÊÛwìÔÉS§”7OÆí ßù_wö›Za9räPçöíÔwÐ`-X¼D¯½úJ¼Ç\¼xQ’\‹|1b~¾pá‚¥×M¨ð>ä\>ý´šÚ«h‰m/S¦LjÚ¤±š6i¬Í["Õ£WomÛ¾ÃõøR%ŠëÏÍ[¹m{¬ÃŽá?}›’6øój®?çhš¦†þT‘Û¶©×‡=Tñá ~›¥Æc¦L™T§v-ÍŒ˜­={÷ùe–þœãù Ô±k·?¬,_²ˆ¢ì€9’!C½R«¦fÌŠÐÿvïfŽx؆°°0í?p@¥K•rÝvèðar´Ð†ƒ‡é?7©@þ|ªúÄã¼÷YhÖȭ’¤2–v=&rë6þÂÎ}[¸P!6ôßsD­ÚwPÁ¨5)ü~–W{÷í×¥K—\÷…‡…Ùê;—?~Ïó§qi§íô=ÐÝ}û}!æñË/ÔW³ç(bî<}»l¹^©ù²2gÎï5©úuë¨ê«rÅGôÁǽdš¦ªT®¬IS§ªUófŠŠŠÒü…‹Ô¶e Ÿô“•6$ôÚ#‡Qï~ýÔýãžz¿kW=–‚Å-OrŸ·`¡LÓÔõë×]·­^³VõêÖQüùµ~ïªøpý÷÷ßc½¯$¶ß¾šW|VIý¹ûhåJz®ú3š1k–*>\!^_dË–UçÎ×ù ”;W®X¿#¸}¶ëXr¯›X}`8SP ìä'ýjÇÎ]ºy󦂃ÓI’Šþÿ Z¾Õô …„„hÒ”©Ú²u«®]»¦½ûöièˆQŒ¬©_L×êµëÔ±m›Xoð̰Q£uäè1ݸqC+þ=¿s©Å ÆCË—,Šõ/©+°§›7ojÙòÿΑâ¡ÕŸ‘$mݾ]‘Û¶K’(U’`,X°h‰LÓTƒ×^SPPXPôßÏÙ‘Û¶+rÛ¶Û·q1yG¹~ýºæÌŸ/I\ÿà ž}æv ÿõ·ßôßßÿ÷¶j¾ú˜ajÒ°J–(®ó.hܤÏ|Ü7ÔgÀ@½Z¿¡ú ¢6-šK’Z6{[Y2gV‡Î]Õ¼M[ýïï¿}ÖV+mx¡ö«®1 äϧQƪøý÷kÀ¡ZüÍÒTÉú§5k$I}{}¬¾½>–$ý¸f­$©c»6š1+B¯5n¢¯fÏÕ;íÚ$»ß‰íì©MËÊè«G IDAT™3§†þ4Þ}åË–“$ýþÇÆX·ÿöÇ’¤ åËYz]ŸsØZj¯˜Å-zË/”$EGGkà°aºxñ’2¤O¯reR›Í]í»·X16TsçjÐÐáº|åŠ2ßu—î)V4ÕÏséï§YH«¾M,¯„¼øJÇEÌxH«¶ÞÙ·vÈqá’o$I£Ç×èqããÍ+rt/ÇG*TP¿Aƒtäè1…†fÓ³ÏTÓÛo¼žæçʶ[ŽÞz<5Ûk¶aÊž=TÏ<ý”š¿õ&sÄÃ_~ñ?yR‡—yë–ªT®¤¶­Z’£‡9ž;w^?®Y£ð°0=]õI¿i«ÝrìÚ©£&M¦Cn)P®ìCjÛ²5Û5ûκ#Gv½Ýô =ñXjM ¿Ÿ¼üÂó:rô¨¦|>ÝUÓ_~áù4ý.jÇýá{ rô‡ïîÖlwò]¶xa‚÷ÇÜnF¬Ó›¦ï9úôN°CBÔ¶UKµmÕ2ÙÜS:6çà8,€Ça8ŽO®"Cœ;ÏÓ4åç§&¦o½Õ·äHŽäHͦf3GÈäHͦf3GÈ‘a½fÛ(_; Gµ÷` ?ŸspŸ-€°jêÜÌè[ïdFŽäHŽÔlÚÉ!G#µ¾eŽ#9Âzfv®ï´±PëSG€Ç öÕ sîŸ{Ž#@€ãøä † Îgiš2døué[ïô-9’#9R³©ÙÌr9R³©ÙÌr$GX¯ÙvÊ×ÎcÃImç=ÌÏç'ØW/ÌÊ©µÌìÒNú6å}KŽäHŽÔlj6s„AŽÔlú–9BŽäë5ÛNG"ÐvÆ€´ù|Î Àq|sˆÁÊ©¦iÊÏOMLßz«oɑɑšMÍfŽ#È‘šMÍfŽ#9ÂzÍ6lv$‚AÛKÒâó9G€ÇñÙ«¦ÎÍŒ¾õNfäHŽäHͦÌr9R é[æ9’#¬gfçúNÛKµ>uødÄðûãËý—¿gGßz';r$Gr¤fÓ>æ9‚©‰Ôlæ9’#¬×D»åkç±á”¶ó æçß`_½0çγ–™]ÚIߦ¼oɑɑšMÍfŽ#È‘šMß2GÈ‘a½fÛêZ´± M>Ÿs à8\ÄpnâÀê[r$Gr¤fÓNæ9‚©…ô-s„ÉÖ3ã:´=ÐÆÀçsÏq ,¾ðзiøÉ‘©ÙÔlæ9‚©Ùô-s„ÉÖj6§‘¢í6–>Ÿ{ŽS`ÇáX~„Có«oɑɑšM;™#är¤Ò·Ìr$GXÏŒÓHÑö@KŸÏ=Ç Àq|²bÉ:4;úÖ;Ù‘#9’#5›ö1GÈäHM¤f3GÈ‘a½&Ú-_; §´÷` 0?ÿrpœ`_¼h¦L™tõŸ« ÉÂ9ôÜd†®þsU™2eòëvÒ·Þé[r$Gr¤fS³™#är¤fS³™#äHް^³í’¯Ç†ÓÚž˜ 20W4˜Ÿ2dH•íùd¤ÐÝ…tàà…f UÆŒôª®]¿¦ /¨p¡Â~ÝNúÖ;}KŽäHŽÔlj6s„AŽÔlj6s„ÉÖk¶]òµóØpZÛ“/<ŸŽ?¦Ùs0WTšŸçΟS¾ð|©²=Ÿ,€„‡…Ë4M:|H'Nž WÝ)S&º»ÂÃÂýºô­wú–É‘©ÙÔlæ9‚©ÙÔlæ9’#¬×l»äkç±á´¶'¦p¡ÂºeÞÒÑcGÍD|,]p:åÏ—?Õþ@É8sæL²Çv­üq¥Ômàù‹s!Øé0;úÖ;}KŽäHŽÔlj6s„AŽÔlú–9BŽäë5ÛùÚyl8±í¼öü|>wÁ\=Wí9·ß5b¦wxÄ7G€Øñ‹è[r$Gr$GúäHŽäú–AŽäH¾´=0Ç5sp¦ "NÃp@€ã°‡à8,€Ça8 ÀqXŽÃp@€ã°‡à8,€Ça8 ÀqXŽÃp@€ã°‡à8,€Ça8 ÀqXŽÃpœ`_¼è­[·tððAí?°_—¯\&e7eÉœEE Q¡‚…D–äI–d ò$Kò$K²$Kò$K²$Kò èÌc—¾°ó8rZÛí>–¨[±Ú‡¾ä“ƒ‡êÈÑ#*]ª´råÌÅ;¸›Îœ=£¿þþK’T¤P²$O²$K'Y’'Y’%Y’'Y’%Y’g@gž»ô…Ç‘ÓÚn÷±DÝ Œ} Ô>ô%Ÿ,€ì?°_¥K•Vh¶Pݸqƒwp7…f UñûŠkÛŽm®Î'Kò$K²y’%y’%Y’%y’%È’<5óÄØ¥/ì<ŽœÖv»%êV`ìc ö¡/ùdäò•ËÊ•3—®_¿Î»·¢££•+g®X‡2‘%y’%Y‚<É’<É’,É’<ÉdIžšybìÒvGNk»ÝÇu+0ö1PûЗ¸:pœ`_½°iš2M“„-äF–äI–d ò$KòY’%y’%Y’%y’9)L°»,FÙy!ÍimxX°œtdW ¹æô} Ô>ô®Ç'G€†!‰CÍRšY’'Y’%È“,ÉdI–äI– Kò äÌH ŽŽÃ5@`+v;ÇÎG9¥íG€Ça8ŽÏNeš&³˜Y’'Y’%È“,ÉdI–äI–dI–äIæ€ïÙí´^žì“S÷/ö1ÐúЗ88A€íØåh;Iä´¶<>9ÄA²^Ê,É“,ÉäI–ä ²$Kò$K%yjæ¤×ñ3œ_”<É’,AždIž K²$O²$K²$O2 å¸pŸ^„U{²$O²Y’'Y‚<É’,ÉdI–ä ÒA€­2lu1î¸×’¡í©ßöäë”…Í@8uŸÓ÷1PûÐW|³bpNÌu¾A–äI–d ò$KòY’%y’%Y’%y’9)Á °%;/FÑvð=.‚‡à8>9–.ˆäoì|q)ò$K%y’%È“,É’<É“,É’<áÍÌe£ë±ØùZ2Žj;€€Ä ÀqX &÷È5§÷}ÈÜKJ° @9éÔv í‡ÓNÝçô} Ô>ô•`§ìH b'Y’%È“,ÉdI–äI– KòîáØŠ.H÷Âî´=mÚ 0±  9ýÈ®@8r>DB¸:pßb8ïÂ,©Å4MÅ::,É“,ÉäI–äI–dI–äI– Kò ÔÌHŽ˜ ‡ï“ýF2÷’À5@`Kv>‡¶û×þ8eŸÚ§¹æô} Ô>ôŽŽã“#@ œÓ"Ó4eÜqüY’'Y’%È“,É“,É’,É“,A–䨙‡à8\öbØç¢À¦i*ÖY½h{Ú´@@ò͈!Ή€o,äI– Kò$K'Y’%y’'Y’%y«™ 2µ°iš¦Œ;V¶°Ø‡¾Ä5@€ãøl„ÃA½—Y’'Y’%È“,É“,É’,É“,A–䨙`•ONep²F¯åG–äI–d ò$KòY’%y’%È’<5ó¤c§‹qÛõt6Nj;€Àä³k€øc1üò«Yúù— 7j„BBBü¶8Û!K» O²$KòY’'Y‚,É“,É’,ÉÓÞ™`U@]ýÍ×›(**Jc'NÒ»;Ñû)P£fíX?·t ¡x!ËlY³êR%ÕºysåËN8Z¿áWÍ™ÿµöîÛ§Œ3ªh‘Âz½QC•-S†pRàêÕ«z§Û{:tø0óÝK5“SnÞ× ´héR={Ž<½<6ÉÓšM[¶è‹3uàà!IR¡»ïÖ[o4Q…råÇ‚3gÏjüg“µyËéÙjÕÔ²ÙÛ â†žŠŽŽÖgÓ>ת”$U¯VMmZ4'K •Þ_ ÃP¦L™T´pa5{«©J—*åºï§µk5xØIR÷÷ºéé'ŸŒõ:Ò̈9ŠÜºU—¯\VÖ,YU¬hQ ìûI¬íļooÚ¼E} Ôµë×Õºy3½Z»–vïÙ£OÇOÔ¾ýû¬|ááš8ft¢mͪ²•Q«fÍ”3g¯µ‘Ï€´h;Üü­7éu/ˆù°’؇xžett´V¯]§¡#Géì¹s3b8áxhÝúõú […‡…é÷õIÿ4t¸æ~5ƒp,2MSCGŽRÙ2e\ Hù|GʬY÷³¦}9C5ž­®ö­[ùíQv“?­Y«ÁÃG¨h‘ÂcÁá#uîüy=R¦)uèÒUCGŒâ=È¢‘ŸŽÑnÒà~}eÊTž½¦Ú5_&-]¶\K–~«Î;È0¤QcÆ)¾|z…,TyŸ5MS›·Dª{Ï^4l¸f}ñ¹ëþW¯Qºtén¿¯^kqa÷ž=êÖýCeËšU=ÞW%K”ÐñãÇ5{îü·µöçŸ5dÄ(©g÷ôX•G%Ýžó»÷î՘ÖW3"f'ÚÖ¨¨(}»|…&Nž¢óç/hpÿ¾^k#Ÿƒi%˜ÿ.]:•y°´$éôé3bA÷w»I’nܸ¡¨¨hIRÁ‚&¾š=G—._ÖÇÝ»ké²e¿°xéRIR£zõXüð¢¯-–$5nPŸ0,È›7Î?/Ã’ŒÛ§îÈÎÑœVmÛ±S’ô`é\·­ø~ |÷ý*IÒ£•*ºn[¹j @*Š9â*ãŸ[.^º¤?7mRù²eeÊÔÆMêâ¥KÊ–5«$iÚôºv횺¿ÛÕuD{áB…Ôý½nñ^ÿÛeË5nÒgÊš%‹úôüX¥J–pÝwèÈIR† 骎mÛ$ÚÎàà`=ÿluMœø¸—Úuê,éö)°z}Ôƒ,-º»`ý½{"·msµíØñãäiÁñ'$IY2gVL«Ž?A–|§ô›Ïìq­øf±cò¼óŒ éÓ§W—Ž]Ï[³îgEEE«ÚSUeš¦þØø§Ö®ûY/½ð¼$iÇ®]’¤Ò¥J%»­±'){h¨F ¤ùóÇz|éJi㟛ԾsW•,Q\•yD5_|A3fŒ·OQQQZ±ò{IRñûï÷jãž="©~v{¬²ÕŸc]‹›¶§MÛ$Žü@TT”ú¬}èý®]TåÑÊ„bÑŠoëêÕ«ZôÍRÍŒ˜­a£FkÄàAcÁè±ãÕ¯w/e % /ŒKIº~ýº,^¢³"tùòe Ðp¬ÔÌ›Q’¤o¿)Ó4õa¯O4bôÉ©­ZðïÑ ëÕ“að-ÑŠ‘cÇéà¡CðIoÝ2MõìÓW#ÇŒU¿^= Ç‚nÞѨ±ãÔ»ß,_’”>˜¯.)aJ‹ ^qç/ïýí—õvûlûiš¦Öþ¼^ƒ† ×ÔéÓ5jèIÒOkÖ(SÆŒªR¹’$)SÆŒúqÍ×â‚'‚‚‚táâEmÜ´IòçußGï¿§ù iý† Ú¶}‡¶mߡ͑‘ðIïxãÚ0 …f˦ªO<®VÍÞÖÀaýÖFæ ­øô[­8YÚ­¯ý©½¦ijøèO¹m›z}ØC®`«<ý±­™2eRÚµ43b¶öìÝg›<ý­ç/\PÇ®ÝüÒ¿|É"ò´ C† z¥VM͘¡ÿíÞÍØ´(,,LûˆuÑC‡“§EÒnRüùTõ‰Çy²hKäVIR™K»Ú¹uãҢ… iô°¡ÿÎï#jÕ¾ƒ (@ž„‡åÕÞ}ûuéÒ%W»ÂÃÂÈ2¿ùS[_¨ýj¢÷Ùás¦»yÆ<¦rÅÛ§ Û³w¯LÓÔÉ“§´cç.™¦©Úõ¸¿cç.8yRyóäQ©Åõçæ-ŠÜ¶=Ö)ìòA·®6r”&|6EQQQzµV­Xßš6i¬¦Mkó–HõèÕ[Û¶ïˆ×þ¸¹{»¾v®e´ uðgT@›úÅt­^»N;´WŇ+H 5Z4PžÜ¹´âßó]—*Qœ`,Šû%(拪]¾”ú£›7ojÙòÿŽÍbQêÏè³iŸkëöí®?f~ TI‚±hÁ¢ÛhmðÚk®s”ÃsE Ö_ÿ­ÈmÛeš·n߯åSìúõëš3ÿöÅt¹þ‡5Ï>óŒ>›:M¿þöÛ·U#/~F&Å4Mmøï%I… Ý~_X½nLÓÔSO>¡ºu•$ 1R«×®ÓêµëT¿n½Õô mß¹K“¦LÕ]weRñûîÓÑcÇôõÂÅz¿[—XÛxòñÇ¢C‡jò´/u3JõêÖ‘$}Ò ê×­£ûî½GÁÁ·/f^¤pòïOÞn#iÅ' †ap¾Ö|8ºóÔþšå‹¯Ô‰õsÌ/F—-^HžZ¸äIÒèqã5zÜx×ídé¹G*TP¿Aƒtäè1…†fÓ³ÏTÓÛo¼î—縶Ãé××ôò÷,»vê¨IS§iÀÛG-”+ûÚ¶lÁ¸ôBíÌ‘#»Þnú†žx¬ yZ©™/<¯#GjÊçÓ]5ôåž'K¾S"òŒùžœù®»T¶LµnÑ\¦iêÇÕk$IOW­êz§«VÕêµëôÓšµªWçUÝ[¬˜Fªˆ¹s5hèp]¾rE™ïºK÷+oÛ¦iªâÃÔçãÕgà }>c¦nFE©QýzŠŽŽÖÀaÃtñâ%eHŸ^åÊ>¤6ÿ¶#©ÏøÞncÜ£~’ú¾7sR‚#@`‰¿ýrž,!IUŸx\UŸxœ «dçpéÒ¥SëæÍÔºy3ÂH¡9²ë›¯ç„Ü]°`¼ó©ƒÚé/5³]«–jת%a~R¿&Žï¶G*”÷¼Â…îV÷Þu{;•yP çDĺ­o¯-µÕWmô&C†­.ÆmÜq5nÚž6m˜|vžþºÄ{¹‘%y’%Y‚<É’<É’,É’<ÉdIžš9àS†Ã÷É€~£™{Ià8^šµ%Iß-]ëçúuë¨ù[o&ø˜Ý{öèÓñµoÿ~+_xx‚GÈx³]‰Ý¶qÓ&EÌ™§¿wï–$Ýwï½jܰ¾*”+ïy¥(¥ƒ¹nïú~wmß¹3ÁýëÎmzºÒ¿§þ UهʨU³fÊ™3‡$i×_ÿÓ¬9s´cç.]»~]¡Ù²©hÑ"®£hÝÉÁíXá¤S&¶pë¤ÅE§ïc ö¡¯ûr'Xµg€“'Y‚,É“,É“<É’,ÉdI–䉔dîk+Wý 77R† âÝ7jÌ8íÞ»WcF WxX^͈˜&¹lÜ´Iõî£â÷ß§)o_?´ÿà¡ú¨w èÓ;Ö"ˆ$mÛ¾C{÷íS±¢Eõ÷î=®Å„XYðHêµ¢¢¢ôíòš8yŠÎŸ¿ ÁýûjûÎzÿÔ'OõëÝK÷ÞSLÖœy󽺈+ˆ¨J–(®5ë~Nð¾CGŽH’2dH¯ÐÐPulÛ&MÚ8kö\™¦©–ÍÞVXÞ¼ Ë›W­š½-Ó41'þ5ÝJ•,¡ÅK¿•$-úf©J•,‘jm ÖóÏV—$íúë/IÒô™_)**Zí[·R©’%”!CÝ[¬˜>îþW·q±Û‰9ÇÝqŸ£öË/ë›ÿ,Kð1¥(%Ijß¹«ºuï¡y êŸþ±¼í„Ú£FÍÚ®q÷÷ž=’¤bEЏn»§XQIÒÿvïŽ÷Zõ꼪ŸÖ¬Õþ´fÝ:Õ«ój¢ûçvkÔ¬íQÛÊöæÍ›Z±ò{IRñûï—išúëK’J/îvÿ$Õg‰m'¹¶<\«ìCetýúu×/éïôÑûïiþÂEZ¿aƒ¶mß¡mÛwhsd¤ëºÞ´â›Å®ÿ¾Ö+)z­Ê+*,o^õìÛOùÂÃU¹bE·¶›RÏ×zE†a(4[6U}âqµjöv¬ûÓÅÛ?+ÛOn;Ã' † VZ-2MS† ²$O²$K'Y’'È’,É“,É’,É3à3wçñV¶÷çZ/¿¨oþ³,Þc2eʤ¦M«i“ÆÚ¼%R=zõÖ¶í;¼2jGb¹÷žbÚ±s—öîÛï:Õî ¹ïÞ{|nÝWjkô¸ñêÜ¡½ÇÛµšûò%‹|ì}÷Ü£m;vh÷Þ½*]ª”–/Y¤j¿ëµ²fÉ¢K—/ëÚµk ѵk×$IÙ²f·½Ä¶qq ,´gžzJ›6oŽwû'ýjÇÎ]ºy󦂃ÓI’Š.œêíkÒ  ÃÐÔéÓuòä),PNZØ´ó¢ûØ}è+œ 8 Àq|s ,CœÓ"Ó4ãã,É“,ÉäI–äI–dI–äI– Kò ÈÌH®[±Óéã^ض§MÛ“{¬S$vý'qú>jú §ÀŽã³õ^ndIždI– O²$O²$K²$O²Y’g fîÇ2Žh;€ÀÄ)°$;ÖËv>mû¸}èKÁ¾Ü VZ­åF–äI–d ò$KòY’%y’%Y’%y’9)Ã5@`/Æÿ/FÙá_¬?t¦íiÓvªQ³¶Fëç„þ?¡ûÆ6Ùõ󸉟Å{<€”á ~†ó‹’'Y’%È“,ÉdI–äI–dI–äI怽ü÷?´gï>Ÿ·zÍZ]¹rU—.]ÖOk×$àe>YI­ów9UÜs¼<É’,AždIždI–dIžd ²$Ï@̰‹·Þh¢IS§zü¼Š<¬+WêÛåËõh¥Š x×ñ3œ_”<É’,AždIž K²$O²$K²$O2ì¥FõêúÏòï´þ— ±n7ŒÛ°¾ó¿wzµv-õ0HQQQê×»—¾ÿáG¼ˆk€@ †¡ö­[iêô/cÝ^ ~ý²áWݼyS?ÿ²Aw,ëþ{‹SXÞ¼*?¿î)VÔÖ¬^»NÍÛ´sls}{â?Ã_—'Y’%È“,ÉdI–äI–dI–äIæI3dئ/LÓŒw*5ÚžúmOî±)Ý'Ó4Uüþûô@©’:zì˜ëõÞi×Vã&}¦Á#F*_x¸:¶kk[¦ijèÀþ±ÆJÚ’–uë—_U•Ê•|¾­ÔÞÇC‡©|Ù²’¤åß­ÔŸ›7ëÃ÷ßã½'j½7 `ÉŠo»þ¿[§wÔ­Ó;®ŸË=ÞÅ Ë~ùõ¿ª\©b¼‹¼;AÌbǧã'è…Ïé…Ï9²Ÿ¯õŠëÿíz$RB|vtþÂ{¹‘%y’%Y‚<É’<É’,É’<ÉdIžš9ZcÏ›ÿž¯õJ¢·9{V]?讚uëiùw+½ºÝÔÚ¿;ÿݺuK¿þ÷7=Z©’O·“–ûhš¦–/YäèýK«mùG€À^lt:2;ŸJÍQm÷;víÒ€ÁC¤aƒ¨ø}÷ý{woUYèü»ãQä\… "JÈ •66ýÔÊ9m²2ͱìÞê6—šš•ZšÕ­4Í´L­T´º ÝÛè€!Š#“¥ví¦!rÜ¿? .£Àáì½Ï^ëý~½x•‡ûy>ÏÚkµVË?gÝ{_uueòļ6µ°ë¦]YÊyÕåH‘Â517âŹXáÕYK=µÔ=µÔSK-µÔSK´Ô³ªÍ¡l>öÉOgÛm·ÍIŸþd6ïè(Åœþûw¿Ë‹wÞ9}ûúY{zŸ6 h5­r ª•/¥V¶±¯I£ïY±É&›ä/ùKþü—¿Ôí1VœS#æ÷›ßþ./ßm׆vlô­ìókä¼êvXÎOCTïEO-ÑRO-ÑSK-õÔSK-õ¤§›C#¶»zl{kú;¿üÅ/ä„SOÍ'>sB>òÁæ/Û­!¯[õ|nûõ¯6ôùÛŒ9ö†÷ž2½>6r.ÎèaoØÿÀå¿–Ùj«æ¬Ó¿˜qc·Ïi§Ÿ‘«®ù‰PPGu=ÄQûîuÓRO-µDO-õDK-õÔRK-õÔ|ÝßÛ27ã6ö^½-ÕõW]±Ö¯m6hP¾ø¹S<ᡜTVÙ/-T¶ƒ¶eŸcU×°^ÚÊ0 O`ôÔRK=õÔRO-ÑRO-ÑRÏr6ï‰ïµ;PMÎJ§.@Š¢P¶‡úi©§–Z¢§–z¢¥–zj‰–zVµ9lŒ¾ÐJŠ-u3î"…±7yìëúÞ²\2«•o\oŽÕ^Ãz©Ëööö,|zaôàz{òæ]Yøô´··k©§–Z¢§–z¢¥–zj©¥–zV¾9lŒºéܺ3sæÎIÇàŽ 0Påõ´¨kQžxò‰Œê¥¥žZj‰žZꉖZê©¥–ZêYùæÏ§•ÎD0öÞ1v zêrdø°á©Õj™7^}ìQ•×S{{{:·îÌðaõÔSK-ÑSK=ÑRK=µÔRK=+ß6F]€´µµeÄV#2rÄH…7ЪG§µÔSK-ÑSK=µÔRK=µDK=«Ú6F]o‚îMKK=µDK=µDO-µÔ-µÔ“W´Ø¥˜ coúØJj“(›¾ÐjZåLœµÝHÜØ{ÇöQ¤h™³ZÖwÞÅ §¾”m~U˜c×°žœ”Ž @é¸-¥•. ÓÊ—³)ÓØjrPYe»·B™çW…9Vu ë¥.g€<ûì³™;nfÏ™O-ð*ºƒ6”Ñ£F§sdgÚÚÚ4n@_Ý´ÓN7íÐN7ítÓN;ítkåýenº¡ûIÜHÜØË°}õU— sçÏÍÃ~8ÆOÈÐ!CU^‹ÇÿöxfÝ7+I2ºs´Æ è«›vÚé¦Úé¦nÚi§n­¼ ÌM7f? ¬I]€Ìž3;ÆOHÇàŽ,^¼XåµèÜ‘qcÇeÆÌüÆ®q÷úê¦vºi‡vºi§›vÚi§[+ï(sÓÙOÝV¤eîk²>jµZVºõIÉæW…9Vr ë¨.@<µ C‡ MWW—Ñç±téÒ 2´[§¬jܽ¾ºi§nÚ¡nÚé¦vÚéÖÊûÊÜtC÷“´Ò͸½wŒ¨7AJ§o½þâ²–SÏN7¶¯nÚi§›vh§›vºi§vº•iÿ€f­ù¼0vÛPÎJÇ túJÐ:Ê|Y±õWQ-5¯ÇkìÍ;PMu9²ìÅŵöê÷b¬ñƽQë¦vºi‡vºi§›vh§[öù¼KQªƒŠµZ-EŠÒί s¬âÖ“3@h)íííYøô è? Wï,Š" Ÿ^˜öövcoòØjr€–Ò¹ugæÌ“ŽÁ8``¯碮EyâÉ'2ªs”±7yì@59@K>lxjµZæÍŸ—G{´×޳½½=[wfø°áÆÞä±ÕT· e¾!WOwÒ¸±}uÓN;Ý´C;Ý´ÓM;í´Ó­Lûª¨­­-#¶‘‘#F¶ÜÚ»çÐ8Π%µòNnc¨?@h)Ï>ûlæÎŸ›ÙsfgÁS zí8m:(£GNçÈδµµ{ÇT“ -¢(Š$åþ ües|>sçÏÍÃ~8ÆOÈÐ!C{í\ÿÛã™u߬$ÉèÎÑÆÞı¯}ƒ+㓨äó«Â«¶†uÔ·>c/\ãs=ÕjµÝXm»×W7í´ÓM;´ÓM;Ý´ÓN;ÝÊ´ ªfÏ™ ã'¤cpG/^ÜkÇÙ1¸#ãÆŽËŒ™3–ïˆ7öæŒ}]Ï¿²¼NUá^LeŸcU×°^œ@KYðÔ‚ 24]]]½zœK—.ÍÐ!CWº\”±7gì@5ÕõˆŸð¨?uÓN;ÝÐN;Ý´Ó í´Ó `uîTV.Uöõ²†žskSŸ3@ЏÆç†,v¡qÃúê¦vºi‡vºi§›vÚi§[™öT¼Y+l[­|=ÿ²¨g€¥ãP:}%ªªL—êkåË–™cµ×°^êr¤H៰ØE7.ò©q÷úê¦vºi‡vºi§›vÚi§[«ï(sÓõWQ´Ö SV¯±7gì@59€–ÔÊ‚Œ þܨ¬*\ªìëe =çÖÆ tJ§®÷q=ÀúÓX7í´Ó í´ÓM;ÝÐN;ÝVç&è´œZ­Ö×Öv=coüØ×¤HÑ2sZßy)J;¿*̱ŠkXO.”N}€ÂÖ½—ÆÝk¥›vÚé¦Úé¦nÚ¡n-¼ ¨@Ô†@©Û%°ÊvZN=;iÜØ¾ºi§nÚ¡nÚé¦vÚéÖÊûÊÜÔ¶@OrZJ«%²êõü½wm'e»D™çW…9Vu ëÅZމû†Ž¨žºÜĵëßKãîµÒM;ítÓítÓN7íÐN·2íÖÎ=@šÌ=@ßW7í´ÓM;´ÓM;Ý´ÓN;ÝZ}ÿ€¦­ßÁØ{‰¢„—O*Ê;¿*̱’kXGm(@h-E רm'@ÃÔçX^\êßKãj¼Qk§nh§nÚ¡›vÚéfÿkäFâÆ¾¡cªÇ=@ZøÅXãr¿Qk§nºi§nÚ¡›vÚéfÿÀjŠr7mäuáaƒŸ-ü:\…÷óóœ[—ÀJ§n@ütGý;iܽFºi§nÚ¡nÚé¦ÚéV¦ýÀšÕåX…sëÞKãîµÒM;ítÓítÓN7íÐN·2íÐÊóÂØ7n;)R”ê²rµZmµ5+ÛeóÊ>Ç*®a=¹H/XlÛW7í´ÓM;´ÓM;Ý´ë=íöÜg¿•þû†k¦i×¢Í<_›· ÊÍÜHÜØ=§€çÓ·•¿ê‡¾UÝpÍ´üêæ›ó…3¾”$ùøG>œW¿êUküóEQ¤½½=cFÊᇽ+Æ·u¬§[o¿=—\zyî»ÿþ¤(2vÛmsèÛÞš)“'‰³‡ytþòÈ#9ÿ›ßÈÈ[åòý8ç÷¢öÎCó¶CÎü‡ÿœ#Ž96/><ž÷-Á6à¹ß›þá× íÚÌèÑ£sì‘ï͸íÇŠ³ï5¬Ù 'Ÿšßýá9ù„Og×—¼$IòÛßÿ!'žrjv}ÉKrò ŸiÛÝŠÛך¾Æ†5d>Ó%»Ývyû[É.S¦ˆ³žïEQdóŽŽLž41G~x† y@ÀóuÃ[­ës «;â˜ãòη¿-{¼jw1 Zú&è7\3mù¯µ}í—7Þ”>}ú¤OŸ>ùÕ7¯õï¹nÚ•9áÏ]wßÏŸq¦-cþ¡ü©?›%K—ä¼o|=çýÇײø™gò‰NÌíÓ§ ´»ìüÜN„{ï»/IrÛÓÿù¿w¬ôõ§Lk^üƒyÃÛ}êãÍÝ÷Ü“3ÏþŠ ù^Ú{Ô{Ó¿ÿœ{þw²téÒ,Y²4ç]pAú÷ïŸãŽ>R èÍŸé¾ñõ,~æ™|êÄÏæÖÛoh=ß/~rÅòÖCίnº9§ù,Q zùËvËÿö·B@E´•yrOþã¹íöÛ³óäÉ™2yRn½ý¶<ù¬=FÛs9`ËXOßÿÁe©Õj9òð÷dØ–[fØ–[æ¨Ãß“Z­–ï_z™@k°Ë?lÜ{ß}éZ¼83fÎL¿~ý2óî{ÒÕÕ•{ÿùS—~Ú’z›2é¹³´}ôQ1¨‹žC:0ó~8×\{]®¹öÚÌøÏyË›ÊðaÂùLwÉ¥— ´žúö훽^ÿº$É=³f ½ÐËwÛ5¸õ¶,Y²D `¹²Ý[¡Ìó«Â«º†uûŒ^ÏI4caV|Ì›nùu–,Yš×ì15µZ-¼õ¶Ü|˯óƽ÷ZéϬxÚp¿~ýòÁãoØØ[ý ÷=ð@’d›Ñ£—eÛmÆ<÷{÷?ÐôñõÆkUNÚi§ôéÓ'³î½/šqWžyæ™öÎCsáÅßËô?ÍȽ÷Þ—>}údÒÄš:ÎV¼^ôõW_իߨzS»Z­¶üì£É“&öбµÒµe{Û˜zs»C:0?ÿå¯ò½ü µZòÂáÃrðôš†½}»ë­|=_Ë×îù>ÓÝ{ÿý>Ó­ç—,Y’ëöŸI’qÛoïùêùZÉv½½Û¸±c3pÀ€Ü>}z^¼óÎ-¹ŽU¸Qº›ÁÐSú–yr¿ºé¦´˜—ï¶k’ç®wÿË›nZíÈõW_•Z­–›ý_ùügæÛ^˜³Nÿ¢­cƒ>køÀšl²É&ÙaÜö¹ïþòÇ[oÍ 6ß<x@®¹öºüñ¶ÛòÀCeÜØ±Ùt“MÄZ‡ÞrÀ£íµïþI’-·Ø"8îXA¨›þýûç˜#ß›“Ný\’ä#ü·ôïß_ ”ï­EQ¤cðàLÝý•9êð÷ˆ½òŸ®EvÛõ¥ùïßþ®×Ùe¾±ü†Î«•;;@ýÕõH3Ïy챿fæÝ÷¤V«e¿ƒß²ü÷gÞ}O}ì±l¹Å«ý™Ý^úÒ$É>Ø2/äÍçvÛl“™÷Ü“z(ãwØ!Irÿ?‚p̘ѽ¶c³ÇµË”)¹kæÝùÙÏ‘=^µ{ÚÚÚòŠ—í–Ÿÿâ—Y´hQvž2Y»~àêMã½úG—ç‚‹.ÎUW_“3Ï>'§|’n%ÜözË8w}É‹—ÿÿ—¾x—–è×ì1n6hPþ±`A-Z”dÑ¢EI’Á›mÖ«ûy¾¶ðgºm·ÉÌ»ïɃÍÎøWþL7v»m}.Y×M»²¥¶?ÏWíª<Æ—íºkÎ:ç«yÿ1G§(üè”Yiïrã-·¤V«eWížë¦]™ë¦]™=^µ{jµZn¼ù–5~ûÍï~—$Õ9Ê–±žÞö–CREοð»yì¯Ícý5ß¾ð¢E‘C:H µXvƒó§.Ìî¯xE’d÷—¿,O-\øÜïOvtê«_¿~9ìÐwdðàÁ¹}úôå—Ãz×ûÄÏ~ñËtuu冟ÿ"‰ûCQ?ïxË[RE¾}á…y챕?Ó½ýCJeòIJ¨«+³î½O ÉÿUU–_eŸ_æXÅ5¬—ºœREÓïòËoJ’¼zêÔå_{õÔ©¹ñæ[ò«›nÎÁ°üÏì½ßsÿÓM6Éä‰sô{hè=@ºó'Íl¼¢]¦LÎÉŸùt.ýárÔûŽOWWWÚÚÚò‘ý[¯ø)ßUûö–nc·Ý6› ”¶¶¶LxÑøÔjµŒßqǼà›gñâg²ýØí´[Ëž»Ë\{Õ½æƒSooW«ÕÒ¿ÿ°ï>ùî÷¾Ÿ\~y¦Lš¨Û¾×ô¦ñhW®vÇ}T6Ýd“\þ£çÜó/ÈæyÃ^{æ°CßÑkî)`›+W»)“'å”?“K.»}òâ§ä¿ûÛŒÛ~l¯ml¼ÒÜdÕŸß8çìÕ¾ç%»ì¼Ò÷õ–¥­n—§d—Ÿû‰Ôó.øN®¼úšt-êæyE‘˾wÑj_ûþw.§Ïwºßî-o>(oy³³µl{Úõ6› ”÷{Œ¶¹†Úyòdg¡ÚÖšê û¨é¶¢û^¶ë®ùþ¥—å=ïz§-ûëÖ¹J­V[ùF©ÆÞœ±•T· n†TÿN½±ñaï<4·O¿3ç^ðLš¸S†ÖëúÚ6µÓN7íÐN7ítÓ®÷è­lxjµZæÍŸ—G{´¥Ÿíííéܺ3Ç /åüª0Ǫ®a=ÕçH ½¶Ê‹±ÆÕ{£ÖN;ÝtÓN;Ý´C7í´ÓÍþ ¾ÚÚÚ2b«9bdy^KJ<¿*̱ŠkXOÎ*­ìj«p Ú²&€´Š’ŸU³!g´JƒV¾7NÙÆTO›@ÙÔå "…k|®§Z­–¢ùÔ¸{}uÓN;Ý´C;Ý´ÓM;í´Ó­Lûªª•¶­V~^”iì@59(@€ÒqtJkÏ}öK’ôéÓ'ƒ6Ý4Ûm»mÞzð›3q§ «}Ϫn¸fÚJ¿¿ì¿9îuéƒÌ‡½{ã\Ÿ¹÷ôX‹¢Èæ™×S­VK·.G¨q÷úê¦vºi‡vºi§›vÚi§[™ö°Þ~zåóàC³sú—ÏÊÇ>ý™|þ”Ïfòĉ+}Oo܉¾®1ýìç¿È;ßþ¶ôïߣæÞSc]²dI~rÝõùƹçåï"_8õäÜu÷Ýùè'?•-¶Ø"§œxB¶Ûv›Ì??—^þÃnu}æ¼¾ž}öÙÌ?7³çÌ΂§”ú90hÓA=jt:Gv¦­­ÍüÍ¿)ó_Ó8êÉ ´œî\ÛfÌèóÞ#òñÏœ‹/ùA&í´Ój纳;ãܘ±¯ëûv7.7ÞrK^ÿš×<ïŸY×Ü{bìµZ-}úôÉž¯{m¾qîy¹gÖ¬Ôjµ\xñ÷²dÉÒwÔQÙq‡qI’mnjɧ>öÑnu}æ¼¾}çΟ›‡ÿüp&ŒŸ¡C†–ú9óøßϬûf%IFwŽ6óoÊü×4ŽzªÛ?ÝQÿNwÿCÚi§›vh§›vºi‡vºµâþ¢§‰Ô{ŽÛÝ.Irï}÷¯ö{{í»ÿJÿ}ýÕW5½ÇºÆ´ÿ>oÊ]¼ÒÁ€î̽§,Y²$7üçÏ“$ã¶ß>I2ëÞû’dùÁ]§ ™óºÌž3;ÆOHÇàŽ,^¼¸ÔÏ­ŽÁ7v\fÌœ±|dzù›£ç¿¦qÔ“3@ZH™/+Öˆy-{„¢Xý@Ko8ౡcšÿ¼ÜÍŠuÖ6¿çë†Ìy]<µ C‡ MWWWé_;–.]š¡C†®t©#ó7ÿFÏM㨧ºžâ§<êûÆ®q÷úê¦vºi‡vºi§›vÚi§[™öè¶aß{ï?wšÝvÛ ¾lRO®SO]«V«eß7½!WÿôÚµþ™õ™{OŒýºiW®ñ{Çn»mfÌœ™û|0ÆÏuÓ®ÌÞûÐí±®Ïœ’¤MÊ®V«åÁ‡Ê·Î??mmm9ômo-ÍÜ^»Ç¹ýŽ;zíÜßñÖ·¤(ŠœwÁwò—GÉS nôX×5ç Ý6ªôËüÍ¿Jܤ¼ùjÜØ¾ºi§nÚ¡nÚé¦ÚéV¦ýUTÅïÌÛç ƒ³é&›d›1crÌ‘ïÍÄ VûóËÎJXæÚ«®Ø ß_ÛÚ®x§ ûº³V«¥ÿþyõÔWåÇWM[ãö´>s¯íë“&î”SO:1—\zYŽ9þ_SE¶zá ³ããº5Öõ™óªcªÉ=@(­õ9H±®ïYŸ¿£Ñã^õ÷8ìÝ9â°w7eÜëó8S&MÌ”I{tÖ4g`Ã4ãÌF>^]€)\ãs»H¡qƒúê¦vºi‡vºi§›vÚi§[™ögÙY"UzZõ¬ó¯îü«À=@h9­²Ã²•/ W¶±ÕS×{€x¡©ï‹±ÆÝ£ÖM;ítÓítÓN7íÐN·²ìÖÌ=@ZEQîƒJµZ-ë{%°V* 4 IDATéÐÊË6v zês¤ðõxc׸úê¦vºi‡vºi§›vÚi§[™ö=òü«ÊëTÕÏÔ3ÿê½»P:u½õí¤q÷é¦vºi‡vºi§›vh§[™ö@wEÑ´÷ e]oîTR‘¢r—@*V¸ÞžùW{þUÐ× Gknt{QÓN;ÝÐN;Ý´ÓM7í´Ó­šûÊÜs}çÖJÛV+?/Ê4v šœTZÕÔš¿õeÕf£iÝ'—ÆÝk¤›vÚé¦Úé¦nÚ¡neÚ?¬™3@h9­rШ• –mìkT¤r÷€XéÊ`æ_íùW@ßzÆôÓ õ}³Ö¸ûoÔºi§nÚ¡nÚé¦ÚéÖŠûÊ~_÷m '9€ÖÒB?µÝÊ?q^ª±k}®4ú9ÝÈÇë[†I´ú¦qcûê¦vºi‡vºi§›vh§[™öÝWö³ªÖôZ³âYVæ_íùWA[J¦.@ŠÂùeõî¥q÷Zé¦vºi‡vºi§›vh§[™ökç  têrööö,|zaôà–Ï£(Š,|zaÚÛÛ5nP_Ý´ÓN7íÐN7ítÓN;ít+ÓþÊ6k¡ëö·ò=Ê4öõùþ*3ïQeU— [wfÎÜ9éÜ‘ª¼‹ºå‰'ŸÈ¨ÎQ7¨¯nÚi§›vh§›vºi§vº•iÿ°vu92|ØðÔjµÌ›?/>ö¨ÊkÑÞޞέ;3|ØpÔW7í´ÓM;´ÓM;Ý´ÓN;ÝÊ´ IöÜg¿ÿû»ÌèÑ£sì‘ï͸íÇ®öû+ºášiký½5}Ï ×L[í1—}m}ÇpÈAæˆÃ޽ƿ€ÆÚ³¤Zõ±ër¤­­-#¶‘‘#FÚŠÖ¡»§Wiܽ¾ºi§nÚ¡nÚé¦vÚéÖêûÖv ¢ë¯¾*¸õ¶|æ³'ç̳¿’s¿þÕÕ~Õ¿gůíµïþ«}ߊ³¦Ç\õkëÃÏ~þ‹ú¶·¦ÿþëýPWEZæ²^=öZS˜¿ù¯û=¥·¼çm¬¾e™ˆHè¦vº¡vºi§Úi§[ÕM™41IòÈ£öÊ1ì0n\núõ¯óú×¼ÆbPw}%(‡Û§ß™äÿB¬hÙˬzFH#ưÿ>oÊ]¼ñ@Zè§¶[ù'ÎK5v ’(e8¶Üb‹|à¸cWûýzðØ1Lž41]]]™uï}Œ^¡¨àQ’çlþ…m>å>S³ÍË@kYöSø+î´ºúG—gÿ}÷ÉcýkÎ<ûœÕ~Å?³¦_kû¾Í J’,Z´(µZ-O?ýt’dðf›uk û¾é ¹ú§×>ï\ Yϧ*ü2ó¯@J _¿~9ìÐwdðàÁ¹}úôÜvÇôù{wž29Iò³_ü2]]]¹áç¿H’ì2eJ·ÆðÚ=öÈíwܱÑãj•yësóxcoÌØêq $ öÝ'IòƒË¸Òïí½ß+ýZ_ï;æè¼aÏ=sù~œ7¿ýÐüèŠ+óƽöÌqG¹ÁcXöû¯ÞcªÅh¶¢üí -ìºiW®ôßo=øÍyëÁo^ëï¯ïß³ÌfƒåøãŽéÑ1¼÷°w罇½{£æÝR7ã6ö^1ö5j¡»÷X—ÂüÍ¿¹ÏéF>^]€<ûì³™;nfÏ™O-ðI¤‡ ÚtPFΑikkÓ\oÍÑ[sôÖ\sÍõÖ½KÖ|mŠ¢(õκZ­–¢(lôˆº™;nþóÙ0~B†ªr{üogÖ}³’$£;Gk®·æè­9zk®¹æzkŽÞ%k4N•îÒÊ÷u1ÛzwÔåÈì9³3aü„t îÈâÅ‹½Šö°ŽÁ7v\fÌœ±üƒ‘æzkŽÞ𣷿šk®·æè]žæ¬›‰{OlEªwÆÑŠs6ÿjÏ¿ êrdÁS 2tÈÐtuuy7®ƒ¥K—fè¡+v¬¹Þš£·æè­¹æšë­9z—§9Ð8¼¬Üžûì·Æ¯ßpÍ´†Íµ™ó¿}úô|碋3gî¼$IçÖ[ç°w¾#»L™R‰ù?þ·¿åëß:7wLŸž¶¶¶¼þ5¯É‘‡¿g—?¬çüËÎMÐh)EŠ–º÷ª?qnì{o±âŽ_Ýts¾pæ—2fô¨Êsb†–ýöy“ö:©Û2ß«·¼ˆk®·æè­9zkŽæzk®¹ÞåmÞß[æÐê~tåUI’·¿åÊÌyË-·Èÿþýï)ж¤xîùþÂáÃ+3ÿ3ïN’ì4áEË¿výþÜ:r-§•ÎD0öÞ1öÞ´-Ýqç¹ÿÒ¹õȼòå/oØã7{MOúÔ'ó±OŸãþõß’õ‰ÊÌë‘#rßýäÎ3–?æ_y¤ióoÖY]8EQ›Rù«_ËÜyóò¹“NÌ)'ž¹óæåËç|µ2óÿð¿~ ã¶›Où\¾ý “$ýú:G¡žÔ*­‘??wÞ¼üñ¶Û3b«fêî¯ìgÔ4j ÓïüS’dâN–?æšÑôzüQ9ûŒÓ“$óæ?œ£Þ÷þŒ1Âåÿê¨.@–µ´põµâÑaÍõÖ½5GoÍÑ\oÍÑ»<ÍŸO™ïDzÞó*ZìRL…±7}ìÏó¼kôœ~tåU©Õj9äÍ-üFvYõõ½‘ó3jTfÝw_îüÓŒ<ûÏÇ3zTC/ÕÌù/ÓÕÕ•K/ÿa’d¿}ÞØ´ùW3@àÿ÷ïùÕM7gø°ayÍÔ©•›ÿ‡þõø|óÛççs§Ÿ‘$™2yRŽ=ò½•jð†ýL’¼à›ç=ïzgvÅ+<1êÈZN«œ³¶›.{ïÙ>9§¼`ó\ý£Ë+»¦[™Ïtb¥·ék¯ºÂëf¹ :P:u;¤Ì×£ì Öv´Rs½5GoÍÑ[sÍ5×[sô.Gs qÏ¿ª<«þúnþµÊ½¹-¥HÑR7ã.V¸·±7gì@5¹P:Π帑¸±÷ÄöÑJgµôT—V=«Çü{~þUP— UÛp÷¡¯OVôÖ½5×Í5GoÍÑ»—5gýšµè8Ýö½é¹ÒèçK#¯Í´Ž2ïØµÓ€žäX@%)*w ¤b…ÓÍÌ¿Úó¯g€ÐRŠ¢hÙñ»íhœºœRµ#gÍPõ£•zkŽÞ𣷿h®·æšë]ææÀÆs ,€VQòÒ¯ïÍàÛÛÛ³ðé…Ð@¯nQE>½0íííÆÞä±Õä-¥sëÎÌ™;'ƒ;2pÀÀ^;ÎE]‹òÄ“OdTç(coòØ×ªäWµÚAFó¯ôü›yæa£ÛZÊðaÃS«Õ2oþ¼<úØ£½vœíííéܺ3Ç 7ö&ýùTéò~kš«ù›£4òñú–e"h®·æè­9zkŽæzkŽÞTC[[[Fl5"#GŒl¹ç±{½Ç ´¤VÞÉmì½k>•º’ù›…´y«ÊÆ ²ÜÂümëåUŸK`Õ:u¨ik¡¹Þ𣷿è­9šë­9z—²9ÐEŸx+ÎÙü Û|ɹ@‹¨ÂŽ«Â‘ Ì=0Ì¿²óoæËmƒÛ€RæuÎ2ÂsªñÏ1ó7ÿFÏ¿‘ç @éÔå "…kƒÖY­V[ízušë­9zkŽÞšk®¹Þš£w9š RTð €ÂüÍ¿:œ”Ž @eUéì¶µÝÂüÍ¿¬Ï9@€Jªâ¥çV½Ä¡ùÛæË¬o*º6hUýzuzkŽÞ𣷿h®·æšë]êæ@CŸ•º„ù›…ô @E¹’ùWuþEЦªÕj ;¥o#7&þ‘çÕ¯zÕòßÛsŸýþï^QdóŽŽLž41G~x† yAîà|åëßÈC³g§oß¾yáðáùÆ9gÛ’6Àóõ§gÙ^kÙëGŸ>}2hÓM³Ý¶Ûæ­¿9wš N›¯ê†k¦‰S'÷̺7ß¿ôÒ̼ûž,êêJÇàÁ3ft>wÒ‰âÔq_q›^Ó×hL{êßùö;¦ç³Ÿ;-‹ººrô‡ç€ýöÉö µ­ÛÎõáæo[/¯R¹ÿòá2ƒ7Û,Ÿøè¿gÇvÈ#<’\öÕ¾ï—7Þ”>}ú$I~uãÍkÜÃ5Ó²dÉ’üäºëósÏËßÿþD¾pêÉ9뜯åþÌ9_:3Çm™‹.ùw‰ ´>ýé¶×æøé•?΃ÍÎé_>+ûôgòùS>›É' SGþaÛwÝ}w>úÉOe‹-¶È)'ží¶Ý&sçÏÏ¥—ÿP`£Ýüë_ç‹_:+mmmùÌÇ?–W¼üe¢uWE¥çlþ…m¾äÚÊ4™ó/¼(‹-ÊqG™É'f@ÿþÕÙ™äÃË¿çÉü#·Ý~{vž<9S&OÊ­·ß–'ÿñ5þ}}ûöÍ^¯]’äžY³’$ó~8IÒ¿¿tttäøcñN±6¤?ÏöÚ¼7’m·“cŽ<"Ï>ûl.và‰’¸ðâïeÉ’¥yßÑGeüŽ;¤ÿþÙn›mòéL`£üäÚërÚégf“öö|ñÔSü ”öÜg¿µž½ ªÌ?Áë2kô¤ºÒŒkƒÎ¼çž$É„ñã×úØ7Ýòë,Y²4¯ÙcjjµZþxëm¹ù–_ç{ïµÚø—,Y’ëöŸI’qÛoŸZ­– /Ÿ[o»=ïû·eÇÆe×—¼$û¼aï 8°éZáz¬ëÛ¿>€µBïÞ²½V©ùŠcß~»í’$÷Þw¯w«ßlÕ ×_}•m¼fÝ{_’d‡qãZî¦eÛÆ[aç@Yn.ØJãmåæ_ýÆ7³yGG¾ôÅÏgÄV[µÔû}+oã^Ëu/{ï믾ÊsX§ööö,|zaôPúçaQYøô´··›¿ù7õý½‘×7ó«›nJûÀyùn»>·‘˜_ÞtÓj;à÷ÚwÿE‘ŽÁƒ3u÷Wæ¨Ãß“$ùÔG?’^qeþë7¿ÉŒ»ffÆ]3sÇwºöy÷§gØ^›ü˜Þ`¨ÿ?niœ>mmËß+­Aã·ñ»CY´µµå‰'ŸÌ­·ßž[m%>¯Ð0[wfÎÜ9éÜ‘–z®‹ºå‰'ŸÈ¨ÎQæoþm¯}÷o‰Ï7u=Òè#Gãw—Û;gÜ•—íúÒÕ~ÿ±Çþš™wß“Z­–ý~Ëò¯Ï¼ûž<úØcÙr‹-–íºiW®q>íííy×;Þžw½ãí¹cúùÄ 'fÆ]3{ÍÂÞ|¤rCú·ŠÞ~d¸·o¯el¾âïýçOËÝvÛ–mÞÊ?¡hïyc·Ý63fÎÌý>˜ ãÇçºiWfïýhé5hõŸÂÕÜxË2‡}øC9ãËgå?¾u^–,Y’öÝWoc­äç½oø°á©Õj™7^}ìÑRϵ½½=[wfø°áæoþ•Qª3@{×;s×Ý÷ä›ç};›lÒžqcÇæÏùK~tÅUùè‡?˜o¹%µZ-{¼j÷|ìÃJ’|ñK_Î7ß’o¾%‡tà:ã¤SOË!˜±Ûm›¾}Ÿ»‘÷èQ£ÂºõD6Œíµyÿ(|höì|ëüóÓÖÖ–CßöVQ(…w¼õ-ùä‰'å¼ ¾“ÿû‡3xð`Q€ñªW¾" Èi§ŸžsÏÿN–<³$ûlHÉ,û¡5ý°tçße=å ÖÖÖ–[ÈÈ#+óúaþæ¿1V¼*Á²ÿߛϩˢ(šòf¼Ý6Ûäì3NÏ%—]–ÏŸ~f<õT6Ýd“l»Í˜ÔjµüòÆ›’$¯ž:uùØ^=ujn¼ù–üꦛsð¬scXºtiN;ãŒ<ùä?Ò¿_¿L™<)Ǽ÷ˆ¦\'mÅËê4«ù†Øþ½ñÅ¡Õz÷¦íµJÍ“dŸƒΦ›l’mÆŒÉ1G¾7'Lh‰kõ·jïVýGR+6Ÿ4q§œzÒ‰¹äÒËrÌñÿš¢(²Õ _˜wgoÂ6®y}ß?“¤oŸ>-÷Óü­Ú¼V«å¥/Þ%Ÿýô§óÙÓ>Ÿ .º8Ï,Y’·r°Þu´l‡ü2×^u…m¼Î¯ã}Zèu¥ Ûx«>ü»ÒüÍ¿7ÎÙsì½ßËÿoîWº{€ŒêÜ:ŸøÈ¿¯ñ÷¾qÎÙ«}í%»ì¼Òýu}è?ù„O{Gè¦õéOϲ½6–mYó*˜2ib¦Lš(D·qÛ}}-Y²$?ûù/’$;ì0Noã“&î”+.½Dóß¿ý]Š¢È¿½Ì³Ï>›¹óçföœÙYðÔ‚RÏuЦƒ2zÔètŽìLÛ?ïíhþÕžÔ툟 ©¯2] \o4×[sÍõÖ¼·Øïà·dóÍ;2u÷Wæðw¿KsôÖ¼G\qÕ´þîwå5{LÕ› jÔßÜùsóðŸ΄ñ2tÈÐRÏõñ¿=žY÷ÍJ’Œîmþæ¿QZ岞}$I~zåEzÜ—¾øyèQe>Xâ@6{ÎìL?!ƒ;²xñâRϵcpGÆ—3g,ßnþÕž3/½Ø¨Ç®ë Þ´û@s½5GoÍÑ[sÍ5×[sô.Os þ<µ C‡ MWWWéçºtéÒ 2t¥K=™µç߬÷÷F>^u.öT†K`•U¥3ܪ~†ŸùWïlCg€´ˆ"…9ÐcšqP¤‘Y—3@Š® Ú€dÅšë­9zkŽÞšk®¹Þš£wyš¯ë{˺¶1z’K`•TÏx¬ÒÁ·es6󯂺]ËûúZÛõêÐ[sôÖ½5×\s½5Gïr46Ž3@ ‚šqYÅ–¿HЏ6h#6’Bs½5GoÍÑ[s4×[sô.eóu|¯{€Àº9¨¬*à]Û%Í¿ºó/»¶”Œ @éÔåXE ×­³Z­–b…‹ƒj®·æè­9zk®¹æzkŽÞåi¾VEîRØhœª½¾UýõÝü×ó½¦Dœ”Ž› •Võ3ÜÌ¿šóoÖ0<Å @5Ÿ³ùÛæK®o½"º6h}­vMLÍõÖ½5GoÍ5×\oÍÑ»<͆>ÿªtó7ÿ*q@ )ó,ÙèIu;â «ñ4×[sôÖ½5×\s½5Gïò4€2¾ÿ4ò1ݨ¤fݺYV½ù´ùW{þUзž1ýôB}7VÍõÖ½5GoÍÑ\oÍ5×»¼Íפ ;®Ê>ÇgŸ}6sçÏÍì9³³à©½vœƒ6”Ñ£F§sdgÚÚ\EhMÎh!e>U…ƒlsçÏÍÃ~8ÆOÈÐ!C{í8ÿÛã™u߬$ÉèÎÑžxPFEsÞSjµZu¬»®g€ÐØšë­9zkŽÞšk®¹Þš£wyšSN³çÌ΄ñÒ1¸#‹/îµãìÜ‘qcÇeÆÌ•8Rõç ù{ .+g€@ƒ,xjA†š®®®^=Î¥K—f衽ú2]ëR— U»yL3Tý†=zkŽÞ𣷿h®·æšë]ææÀÆs#€RæQ²ГêzoZý@ ¹Þš£·æè­¹æšë­9z—§9å^ïVXóJl—Eµ^ßV»ù´ùW{þà  têsHá'Cê­êG+õÖ½5GoÍÑ\oÍ5×»Ô͠Κu¯FÞ÷ª¯eª¨Y;€›eÕÏæ_íùWA]ïB}7VÍõÖ½5GoÍÑ\oÍÑ»¼ÍŸï{˺UØÎŠ¢0^€q4˜ƒŠõW— U;u¨Yo’U>]KoÍÑ[sôÖÍõÖ\s½ËÜh¢âs6Û|É9¨¬ªÝÂüÍ¿JÚÄ,ד½5GoÍÑ[sÍ5×[sô.GóžøÞ2wÛ×wó·­¯K[€j)ÊÿØu»–kƒÖWÕO×Ò[sôÖ½5Gs½5×\ï²7§ÜëÝ k^…í²Y÷8Z¸pa>ðádÞüùI’®™Ö°5mæ=žöÜg¿Õ¾Ö¨¹÷†ù'Éå?úq®¼æšüíoÿÛôù7ëõ¨‘ç R«Õrú—ÏÊ䉗©šFîôïMnºå×9ÿ»eÏ׿.ï;ú¨ 0À¢Îܤ…_(5×[sôÖ½5Gs½5Gïò6_“¢(Jߢ s¤Ú¾÷ƒKó rÌ‘ï£b®ºæš$ÉÛ>ØÁq@üæw¿ÏÏ~þ‹|õ¬/¥oß>•í°ïA§ÿ€þ™¸ÓN9îÈ#ó/ÿ2´ó^vÆÏ©_øbæÍŸŸmÆŒÉ?ðþŒêìlÚ˜šñ- ,GêcÅΚë­9zkŽÞš£¹Þš£wyšSâuNa¼½L#ïpöW¿–SNlxjµZæÍŸ—G{Ô+ikooOçÖ>l¸æzkŽÞ𣷿h®·æšë]ÂækSæµØP×^u…ùVHŸ>}rô‡çè#·ñ7H]€´µµeÄV#2rÄH…ëdÕ£dšë­9zkŽÞšk®¹Þš£wyš¯MÙ×¢gEÆk»ë]s5÷º)³¾‚ÚˆÑ[sôÖ\o4×½5GokAc×ÏMЭGoYSó7ÿ2¿¶´yËÊÆ tJ§¯ÐE‹ÝU¼(ù]Ћ•»ÄŠkjþæßŒù¯:ŽzrÈMÐͳ7ÍÕü«=ÿ²s , têrȳÏ>›¹óçföœÙYðÔ•`Цƒ2zÔètŽìL[[›u°ÖÁ:X¬ƒuÀZX¬ƒuÀ:´ü:@Ý©Ü%VºòùW{þP— sçÏÍÃ~8ÆOÈÐ!C½6Àã{<³î›•$Ý9Ú:Xë`¬ÖÁ:`-¬ÖÁ:`Z~¨¯fݤQêrdöœÙ™0~B:wdñâŶ¢èÜ‘qcÇeÆÌË?$Xë`¬ƒuÀ:X¬…uÀ:X¬C+¯lŒºYðÔ‚ 24]]] 7ÈÒ¥K3tÈЕN˵ÖÁ:Xë€u°X ë€u°X‡V^‡2«â͈{£¢j×ZeÎæ_ØæK®o*ªr÷€0ó_¦hâ%°t¦¯O`¬ƒuÀ:X¬ƒµ°ÖÁ:Xë`¬Co]è®6 €²q ,h”¢uÎ.jäej¬G“ÖÔü«=ÿ pTP3þ4ò1ër¤( [N“¬ØÞ:Xë`¬ÖÁ:`-¬ÖÁ:`Zy ªtÝïÈümëeÕWP6ÖÁ:`¬Öka°ÖëU~žWêHæoþâ P1EЦªÕj)t3@ AšµÃ±;¹“²Ùó¬ —€2ÿªqt têvH•®Ö[TývÖë`°Öka°ÖëP¾u€zj¥3rzê9¶âY=æ_íùW3@ ‚šqð§‘é @eUí ó7ÿ*q¥HKݽôWË)*¸¼0€Ñ› IDAT󯎾õyÝ(\'³Ip•¯ag°Öë`°Öë`°åZØÎ*«J:×v (ó¯öüÝ 4÷ñS^ıÖë`°Öë`°ÖZs»ªÂö_Å3ŽV=ÛÍü«;ÿ*pPYnnþn‚^^õ9R±›Çôª ¸°Öë`°Öka°ÖëP’u(¡Vº¿LUîÉâHæoþå}εykÊÆ%°€Êr (ów ¬òrZÀžûì—$¹ášikýÚ²ÿN’¢(²yGG&Oš˜£?Ùóu¯M’Ü3kÖF=fY5ó'à{ÜͿÚó¯@ „–,Y’þóçI’qÛo/P9î%³×¾û§(Št œ©»¿2GþQÖ ½½= Ÿ^˜ý”þŒ—¢(²ðé…ioo7óoÚü×4Žzªë×É쬃uÀ:X¬ƒuÀZX¬ƒuÀ:ÐúÛÖfƒå dÑ¢E0`@-Z”$¼Ùf«ý}×M»Òö¼:·îÌœ¹sÒ1¸# ,õ\u-ÊO>‘Q£Ìßü›6ÿ5£žœ-`ç)“sÓ-¿ÎÏ~ñËü¿×¾&7üüI’]¦L§›†žZ­–yóçåÑÇ-õ\ÛÛÛÓ¹ug†nþæß´ù¯iõä4HQݾÁøqG•M7Ù$—ÿèÇ9÷ü ²yGGްמ9ìÐw¬ö÷õÄÙµZ­ô7Lnkkˈ­Fd䈑•ØþVÝ.Ìßü›1ÿFžæ´€Í Êû=æy¿çÚ«®ªª~y0ó7ÿ²j«ËßZ„f)¬ƒuÀ:X¬ƒuÀZX¬ƒuÀ:”d`#Ôí îžÊÇÆ5·Öë`°Öka°ÖëP¦u0Oãè®6 €²qh V9»È @««Ë …‹56ÍŠí­ƒu°ÖÁ:`¬ÖÂ:`¬Ö¡•×6†{€”ˆë•Z¬ƒuÀ:X¬…uÀ:X¬CÙÖºË%°€JzöÙg3wþÜÌž3; žZPê¹ÚtPFΑikk3óoÊü×4Žzr¨¤¹óçæá??œ ã'dè¡¥žëã{<³î›•$Ý9ÚüÍ¿)ó_Ó8êÉh"EKݽì÷d™=gv&ŒŸŽÁY¼xq©çÚ1¸#ãÆŽËŒ™3–ïx6óoôü×4ŽzªÏÂu2›õ¦´Ò{’u°ÖÁ:X¬ƒuÀZX¬ƒuÀ:´ò:@-xjA†š®®®ÒÏuéÒ¥:dèJ—:2óoôü×4Žzj @ÉÔíX~B¢ñÖÔÜ:Xë`¬ÖÁ:`-¬ÖÁ:`ZyÌÓ81Ï*o{æ_óÚSbÎJ§.g€´ÒÍœzÒùß½(¿ûýrî׿ºÎï=ê}Çg·—¾$‡¿û]=öø«Þ˜ªªëÐlÖÁ:`¬ÖÁZ`¬ÖÁ:”}¿F£öm”R Ý_Æ=Y ï~=jäãõm…E¸ÿò•¯#Íž¾}ûæ…Çç眽ü÷÷Üg¿$É ×L[ë×Ööß«ºášiký½¿gUÿó?犫¦å-o>èyǵÌ+^¶[.ÿñÙ÷oÌ¿üËPÏ´Uš­owzÞ§NúlþxëmùäG?’©»¿2IrçŒùÈ'>•ï²s>wÒ‰"5ÈÜyórñ%—æÎ?ý) žZÍm–mÆŒÉi'Ÿ$Nƒýþdöœ9ùâçNÉ䉓$wÜyg>ö©ÏdÌèQùæWÏ©Áï EQ¤½½=cFÊᇽ+ƨ kqÈAæˆÃÞ½ÎÏ;Ôo &¼h|¾ô…Ï/ÿú‡>úñÜu÷ÝÖèn¼ù–\|Érþ7ÿCŒ’ì×H’ö3zôè{ä{3nû±ömPEñÜž*ì\6gó7ÿ*h‰ góµÜÿàƒ9çKgfø°-sÑ%?豿{MoúÏ÷cm~zýõY²dI&¼hývÄì4áE¹ä²ËóÓë¯Ï»}‡w›µ¬ÇӮη¾}~¶3Fœ9úˆÃsûÓsÁw/Ê+^¶[ÚÚÚòß:7}úôÉÑG!Pÿôá2ƒ7Û,Ÿøè¿gÇvÈ#<’\öCqè5{LÍÿü)¸e@~ûû?$I^=uª@Mx¨Õj¹cúùøgNÈçÏ83ßÿÎÂ4ÁÏ~þ‹¼óíoKÿþýÅh’wÍ̃=”mÆŒÉ}÷?°üà@oðß¿ým^þ²Ý„(Ñ~®™–?Üzk>}ÒÉ9óì¯ä¼ÿøš}´„–¸ȼ‡N’ôïß/9þØczÝÿ‡?&I:·Þz½¾Ù÷ýþ·Ú ×âæ_ÿ:çžA¶ÜrKg4PçÖ[ç{í™G}4Ó®ùI~ríuyhöœ¼qï½Ò¹õHäü /Ê¢E‹rÜÑGfòĉпFuvæãù°8 ôêW힢(–ôH’ßþþ÷)Š"¯žú*šõá¥í¹/ £IvÜa\nºå×B4ÑøwÈU×ü$IråÕ×düŽ;ˆô K–,Én½-/ßmW1VP†ýS&MJ’<úè£+ýû1±o€Þ«ng€ôäµÃ&¼h|n½íö¼ïß>”w—]_ò’ìó†½3pàÀ•¾oM§x®:†Uÿ{Õ?sýÕW­u>ÏgþŸÿœ$é’Ï~îó-µezN´2ë`zÚíÓ§gà€7vlË¿žëP†ý·Ý1=I2yÒÄå¿ß¨}Ð]-q ¬O}ô#ùáWæ¿~ó›Ì¸kffÜ53wÜyçjg¬ø&¿×¾û¯×ß½¶Þ ›gî¼yùì©§¥­­-'ŸðéŒ1B”[´hQ?óL’ç® X«Õ²¨kQ6Ûl8TΫ§NÍ]3ïÎïþðÇ䟯õ¯qù«¦¸þê«R«Õró¯ÿ+Ÿ?ãÌ|û sÖé_¦ &Oš˜®®®Ìº÷>1šd·—¾4öÜ2Ÿ9ù”¼pøðìöÒ—Šô ÿýÛße·]_Z¹ë‹¯K«ï×X6–-·Ø"8îX º‘Š-uô¢wA¯ÒÁÿªÿðƒùWovßVÚÞÞžw½ãíy×;Þž;¦ß™OœpbfÜ5s½Î´X×÷¬ï×õ}#¶za|hvþþ÷¿gèСëü³O<ñÄ?ÿÜVußðZiÃ~üñÇó©?›…O?>ù‰ŒÛ~ûÒ<1[ißýÞ÷³xñâú¶·¦¿~¹à¢‹sáÅßÏ¿ÿÛ¬CƒŒßa\n»czîœqW^¶kùvjµÒóa÷W¼<ß<÷¼ç.ƒU«¥oŸ>yå+^^Š×¦Vý©Ìe;zxðAëÐÄ1ïû¦7äêŸ^[ªÒ­6‡ƒöß/gíëù·÷¿¯Tÿ¨ñƒEÖÖ~¯þíï~Ÿ~àøRmC=1—V߯qõ.Ï]œ«®¾&gž}NN;ù¤†ïÛ€îh‰{€œtêi™y÷=yæ™gÒ·oŸ$ÉèQ£zÕ_¼óÎI’9óæ¯×÷/û¾—¾x[á >sò©ùëÿüO>pܱÙõ%/¤ |è¡üòÆ›²å–[äàÈûï—Ñ£:óËõͨA{×;3`À€|ó¼ogúŸþ”E‹åÁ‡Êé_:Kœ¼ÙfÙyÊä̼ûî̼çžì²ó”å§úÓœ¿ùÝï’$£:G ÒD¯ÝcÜ~ÇB4Ñž¯]®›veö|ýëÄh²½÷; {ïw€Ö¡òfÝ{_uueòÄÄXE«ï×èׯ_;ô}ùå°ìÛhmËÎØ\vL£~­øØõÖ·^ázòÔ¡¥K—æ´3ÎÈ“Oþ#ýûõ˔ɓrÌ{èU?)ñƽöÊӮΟîº+S&M\íƒøŠ®½êŠüé®»Ò·oßì½çÿëÑëd®¸áôô:4ÂC³g'IÎþÚ×sö×¾¾Z·VÐêëðí ¿›Z­–#ßsXúõë—$9þ¸cóïÿdοð»9õ¤¬Cl·Í69ûŒÓsÉe—åó§Ÿ™O=•M7Ù$Ûn3¦å®³ßê¯KI²ÇÔW-¿±ãÔWíÞ’?Y†uXö~ºé&›dòĉ9z Ÿ¬CãæÒÿÿ³wßñQTmǯÙtD ÐBS)ÒìAD:XPzW{ï_EAŠt¥K+*XP¤Yè-@ "RSçý#dͦn–ìfgæ÷ý=n)ò¾ß¯\¥n;©B®a¥Ng•"‡åžƒV’ê×­«…sfÑ9V#¡ºyà~:"´lÞ\-›7§#xm ¹b1°__ ì×—Ž ’çÏ•Òñýªd†î¹sÁë…ã­üáGõ¼¹;‘»|¯Ñý†ëÕý†ëÿ;òÝ Èù­âĹû÷é­þ}z{µí;c^HŸ3gàââ@@ˆœ‡Ùsçi@ß>ººe âÇÇá½±cˆƒÅç{ )pßmØŽ!K-‚;ýõöóþÇ®BéðÍ«ÿ7‚N‚Îd¡9%!ϨÚïìö;€_§ÀbèP)$0q  ÄÄ8€Xââ`£8ÐNŽ|Ũ4Šý|< @Yjt›3d8n $#ÇH´ßÙíw—¿N(½“6q  ÄÄ8€Xââ`‡8p:XÄF˜¯”8€8âbA@ˆˆƒÝ \t8,‚á× (ý%â@ˆq  ÄÄ‚8€8+Ç ÷h?퇯X+-ºìē؋ ód–Ö‹’Çkq Ä8âbA@ˆˆƒ•ãð›Ò,p걕F€ØžÃŠN/öÒþ¼EæÒh EЀíP¶ã—)°¬´˜“ä^˜Š8â@ˆˆq±  ÄÄÁÊq°%ÃbS`Ù>Î[t&÷¹Žö;·ýÏu›b Žå¸5 h?íw¦ÀÈ*_B2 €ÕQÀi û?v¨¿žy2/ϼŒÄ8â@@ˆˆqq  VŽào†§@2h?í÷¼.Ðíäã± † K-‚nP‘`a~›‹_H”΋q  ÄÄ8€Xââ`§8äç:ÚO®ûŠ5@€bôàáÄ.9ÛLûÝ~'ðÛXÌ“/JÄ8â@@ˆˆqq  VŽˆ¼ Tî]Û±³Çå¥ æ9ê\—³ýÑåÊé êëÖU¹r¼#ÚÿÝÊUšþñ'Úºm›"##U«f õºåf5iÔˆs¬Ÿ°@vÁ#w!ÄiíÏÈÈÐW߬Ð˯Ò߇éWG:¢ý+¾ûNÝwâ+UÒO«Wëéç_Ôˆ—GjÆ”I<9üį#@XÌWJ@ˆˆq±  ÄÄÁnq°k;­²:à!!!jt^CIÒÁƒÉŽi÷Ã÷ß'IJMMUzz†$©Zµª$„1€c•fA*Ð,Óý8qBϾ0B†aèŽ[‡ìñƒ¡ým;uqÿ»bÅ8Ý?üîRk¿!£TâošfÀÖ"ñË"èN\<&X8}ââ@@ˆˆqq  ö‰ƒ]±:œ,==]Ͼø’¶íØ¡ï½G—]z‰£Ú¿dþ\Íž>M½{Ü¢¤¤zeÔh’ÂXÝæ/žÄ8â@@ˆˆqq  VŽ`çÜ –œä„‘£_×Úõëõä£è¢ Ί>ô1DEE©[çNš<í#mÙºsŸ1G2 ÃqS`†Qjí÷á}õÍ Ý=ìv]x~3ǵä¨×Õ£ûMªP!VK–}&Iª_¯n@ P9Û~­B@ˆˆq±  ÄÄÁnq°«}ùè´/Ký­]—nù^^4w¶#Ú?gÞ|IÒëo¾¥×ß|Ë}½SÚáçë¹—^ÒžÄ½Š‰‰Vëk®VÿÞ½xbø‘ œKñU‰8ââ@@,ˆˆqq°I€dá­´¿è/¨ØKû£Eó+Ô¢ùŽÈõ`Á›Ÿ¬‰q Ä8€8 ââ@@¬»‰ŠŠÒñÇÔí5 CÇOWTT‰ À²X„ê Ú±s‡b¢c´Çy2å¤ÿ{X5jØ>&N*v:½ØKûÍb]o¡îLþ â@ˆq Ä8€Xââ`Õ8ØM|¥x™¦©]»wiÒþ =Ψ¨(%TOP|¥x€e1—Ë¥ªUªªZÕjA¬X_ † æÉ,¥%#ÇJaÄ8â@@ˆˆqq  VŽƒÝÛŠÒç´çºÓÏu´ß9çØlŒ€¥dffjçîÚ¾c»Ž;´ÇY¶LYÕ¬QS Õär¹8öR'Ä8ââ@@,ˆˆqq°rð#@`9V™¶ÆÊÓ«ÙíØócÈpÜHF޹‡h¿³Ûï~bÎêÄ`’³ï‰q Ä8€8 ââ@@¬N‡‹.vã—)°¢¢¢tüÄqE„G0wc€†¡ã'Ž+**Š8â@ˆˆq±  ÄÄÁqàtø¥’P=A;vîPLtŒ"#"éå8™rR‡ÿ=¬ 5ˆq Ä8€8 ââ@@l‡‚Xmš,+O¯f—c/x#9n % h¿£Û_šëê±ýR‰¯/Ó4µk÷.íOÚÏ+xDEE)¡z‚â+Åâ@ˆqq  ÄÄ8€8Ø"E±ò—–;í –¶Ò~Úè>äãù¥âr¹TµJUU«ZWïRLâ@ˆq  ÄÄ‚8€8+Ç€ÓêÏó¢Å›ââ@@ˆˆqq ‚ýyî¨)h?íwPx¡uûŽ—?[¸ h•Çb ÚO®_0=r¢˱ʴ5VžrÇnÇžC†ãž;9ÛLûÝþÓ‘s#@ ±íwlûO£rÚEÕž(€p, ´Ÿö›%²¯@Ü·¸(€¯µéÐÉýïeŸÎÚãôK$33S;wïÔöÛuôØQ²¥¦l™²ªY£¦ª%Èår‘Ÿ ?òä(@~‚ü$?a¡ü,ˆÕæí·òšv9öB6rÞƒöÓþÓÌÜüRÙ¹{§ö$îQà [>–Wp”šä¿“õç¦?%I5j’Ÿ ?òä(@~‚ü$?a¡ü, ‰sìÅ=vÎã—ÈöÛÕ°ACÅDÇ(55•^F©‰‰ŽQÝsêjýÆõî7Oä'ÈO€ü9 Ÿ ?ÉOX#?@pR±¤ ¢í§ýv}Îù¥rôØQÅ–UJJ gP”ªŒŒ Å–õÆM~‚üÈO£ù ò“ü„5ò³(Vþâ’cV›Ö«¤ÛLûÝ~_´éÐImÛ´Ö½wÝé¾ì¸5@À ·í§ý§éÇŸ~Ö–­[U§ví os('pbÈO€ü9 Ÿ ?ÉOk~æËj?Ú68öR?ö’È;¿Ð~g¶ßáÓ{€¾½{êíqïë•_ð©MÓ ØèF€ÀrXHœc/î±(×¶j¥…‹—ê»ïWý±RàXLEû™«x ÃзÑÿ½úZзÙÅ)x«^ÝsÕ°Aƒ ?N¿Œ1Œ¬ù»j†`‘“ä'ÈO€ü9 Ÿù ëä'¬AûÉuï-]0Ïýïû†ß¥û†ßÔmf,ŰØjÜ9—c®–±±ä¿“õç¦?%I5j:.þùµÿt,ž7Çíf ,Ž´}Çv5lÐP1Ñ1JMM¥Cl,&:FuÏ©«õ×» NŠ~í7ŒÒq¨Çök„ª=‚ù ò ?AŽä'@~¢ ëŒ\2MS³zqì¥sì8zì¨bËÇ*%%…ç•Íedd(¶|¬ÇTWNŠ~íÏ~®ú9ÈÇcðJ».Ý<./š;;hÕ?ƒùC<¬ükŸù £ ?òŽÎO @yÇ9ÐAçÇ¿$ÛÌEœ€ùZÉ9 ¤¸Å¦ÀA‰ €2,µ·‘c^/޽t޽À\2 ÷öpÈùÃ0ÿœíw¿@¬t2„ýYùÅä'@~ä(ÈO€ü„“óœNg ¬@bäË Ι•gÅ}Ì@qb`7ŒàXLè¬X;9þNÌóP:œðò ?AŽä'@~ÂR Yj1neM8öÒ9v%¦}×ë³N †¡ ±±êÑý&µiuMP+#@€×Ι¥ôŒ ­]·^/|•CS`9ˆiš2r rZüs·ÿôŸ?’LSeË” Ú6S€åXå Ë‚ÖàØÉÀʲ§Á’¤Ýo ÚãôOÄ`ñ Ù žA~‚üÈO£ù Ÿ°\~Ì=‡90 f}¬©ÓghúÇŸhÑ’¥êÜ¡½Êx9¤¤G¢ÆEzÀJr~ig…¿‚¦ÜáØwì…$œwqvüK¨Í†a¨G÷›T¯î¹úçða½õÞ¸ l.S`p,FÁ9+ÖNŽIµóÓÙŸH’\.—FŽx1¨ÛÌ`;~r:s‡%­°ášù Ÿ Gòä'ù‰àÍO_]Û±³$ié‚yÞ–[ö¶…Ý^Ðm¹÷QÜã QÙ2etv:ºùÆÔ輆Û­þõWM›>S›6o–$söÙêqóM:¿iS÷6ýߪ½ûöéƒwÞVµªU4ó“Yú`â$õëÝK·Üt£vïIÔÀÛ†ªr|¼&Œ{×ãñoº¾›öë[dßÖ—Q‘‘ªY³¦†¤º{®£ê IDATçžSà¾þøó/M>]ÿC'SR­Zµjê…§Ÿ*ð>9¯+éœwM[?&S`ÀqŠú¢<¿Û úRþt-œ3K[·m×˯ÒC?¡Ï=£&IÊ*~<öÔ3ª{î9÷öXIÒó/½¬ÇžzF/<ó”»r~³¦útÑbýµi“ªU­¢_Öü&IúeÍÝrÓúkÓ&IR³¦Mò<þ²åŸ«w[îs_þ´zµúYýºÆ½õf¾Ûmøýw=øècŠ‹‹ÓsO=©³ëÔÖÎÝ»5}æÇ>Å­$b@ØYœþ#€@.>,˜ –SØâ×…mSÔý½Ùq¶óvÍÚµjê¶A•™™©ÉÓ>ro3õ£2MSƒû÷WŸ8UŒ‹Óàý²n›>ý]³&Y…?ÿÚ¤””­ß¸QaaaY#-Nžt@ÎoÒ$Ïã׫[W_­X‘o» ë÷œ×elöíß_`M˜´ÈíC\.ûå×ß9/¢Â9sì‰)°`IV˜«°cϽ¿N ΩSÇ}ÝÙu²F{lݶÝ}ÝæS£BÎ9»ŽÇcß´©RSSµlùçºì’‹år¹tù¥—hùç_èäÉ“jÖ´ImèÔ¡æ/\”ïñÔïÙæ2S]:uTÒ9úûèœ:u$I›·n•išZ½íë‚¶õe*1öâ—ˆ!N..9s’üù Ÿ Gòä'ù k䧯r3¼½Í›Û‹»]Iì£Y“&…ŽÞp÷ahÆ”Iy®›úáx¯`¿¾د¯ÏÇßý†ëÕý†ë m_ÓÆ ](=¿ûÔO%ÖAr§¯ƒÈu–‚…_G€pâ¬&NÒ?þ¤÷ÆŽ)rÛ!wÜ©K.ºPúöqÆ›ü$gÉOwä'ÈQ€üÈO‹¾/uÒ{SòP’BéßíܵK“§M×ÚuëtôØQ•+[NµkÕÒ‹Ï>­k;v.ô¾KÌóØ&*2R5kÖÔÐÁƒT÷Üs$É}ûÒóŠ<–ƒ“5{î<*{a÷¿üÒK4sÖlujß^*ÄL‹Û¼e‹^û¶¶mß®ÐÐPUŽ×ÛoŒ.4r_—3 ÃЙ11jÒ¸‘†  òåÏ*0§ó»~ùLÎÂ_~ó^zåUIÒÃܧ«®¼Ò«œ-,7É;ú\[Ðy´°ü.ê}Ea9ïÍûÙ籆ÿk W_á¾þÞÖ†ß÷êu>÷í7]ßÍýKå‚Þ+ö|†ÆÏðíŸ÷¦yY¥Xbåiçìvì<2JåG¦il*Óø侇Ut¹rzäÁûU¿^=íÛ·OÍø¸Øo²—.˜§ŸV¯ÖãO?«‘£_׸·Þ,öñ,\²Déééjø¿^m^ÃÿiÚŒ™Z¸d‰úöêI@-nÔojóÖ­zãՑНTQ“¦}äó¾–.˜§ôôt}ºx‰Þ~oœþùç°^zþÙ<: »¿7ùLÎ"?_|õµBBB$I_~õMž/ˆóû¤86É;â\[Ðy´°ü.ê}EA¹V´~ÃFmݶMµkÕÒ¦Í[ÜÅ¢^ïó³lùçêÝã…‡‡Ó±°Ígø‚öÏ{SÀ?Jë `”ŽÜ_¼;-þ,< iï›&LÒÉ“'uû­ƒÕ¤Q#E„‡«FB‚~à>Ÿö×´qcIÒþýû}ºÿ?ý,IJ¨^Ý«í³·ûñçÕÓvíÙ#I SLLŒîzÛií/44Tm[·’$ýñçŸ~Égr¹ý{äˆ~ùõW5kÒDM›4Öê_Ñ¿GŽ”ècwÔ¹6÷y´¨ü.é÷ÌÔ¯§¹ >•$Í™¿@ ê×óy_õëÕÕ×+¾¥Sa»ÏðùíŸ÷¦yeii…?Ž=8Ž€ó°ˆ6þñ‡$©aƒ^·³ íLÓÔ/k~“$5iÜ(ÏvÞìwb¢$)&:Ú«ûG—+—u¿={lÿ‚à„ùmþ¯Vÿò«î~¯ê׫«‹/¼PÛ]§ÈÈH¯ú"÷åôôt-Yö™$©î¹çzl“{hø’ùs‹•Ïä¬óòÓ[_¯øVé麺e ™¦©ŸWÿ¢oV|«ö×µõúœXT¿‘wäg Îµ¹Ï£EåwqÞWu&Gù° ò3ØÝØ­«F¼òªºuW¬Ðc= g^‘o¿uÎëÜ¡ƒÆOš¬VW_UèûÛâ¾g ?ù _ÚŸáóÛ¿SÞ›rž”$¦À m;u‘$UŒ‹Ó]·å Ší±Ðdzç軕+µ~ÃF­ß°QkÖ®Õ O?åS>†¡˜èhµh~…† è_è‡N_ó™œEn_~ýµ¢"#uÙ%KÊš÷ø‹¯¿ÎSáÂý\›ßyôÅWF–X~;¹àÀ.¹è"UªXQO<ûœ*ÇÇë’‹.òùœ×¤q#¥¤¤èÏ¿6ѱ°Ígø’Ø?€b0èGÇÜ çíί;ÑÔ ^]ý²æ7­]¿A—^|ÑiõÇüOfjü¤Éš;FŽ~ýØiqú±j•ÊÚºm»þùçÅÆÆyÿÇŸº_Ç~!h§vGEE©OÏêÓ³‡Öü¶V<ù”ÖoØènc¹²euäèQÀ‚ü´êïâžó²ß{^ÕâJÍš;ÏcÅyL~ò>˜>ô§¼7ÍŸ~÷$ëä­iš2rÌ9ñ—αÈ÷djûÇf ÓP#¡ºyàþ"·+苉Ü×w¿ázu¿ázŸ¾Ðˆ‹« ®:jåªUêÓã–"ïÿýÊUêÖ¹“*äj kzöÉÇ ½½\Ù²6ô6ŸòÔ×Ûsç39‹Â¼ýÆè<×]x~3œ(,?¼=_’wðç¹¶ \ò&¿½y_áäB{(Îkyqß{ì×Wûõ-ö{`ð>˜?ÃçÞ?ïMÿ°RQ§$dddèÝÆkù_H’Z]}µn4P.—3& ²rQÏíϾ.Ðíäã…Ú¡ÈÒ¿OoõïÓÛ«mßóºcúÅéCÛÈYòäù r ?òÓÚïKôÞ”\ükÁ¢Åš·àS ¿s˜ CõÆ›ªR¹²ºtì@çÀ–X–c•b‰•‹Žv;vHK?[.Iºôâ‹tÉEI’–-_NÇÀ¶ü:„ ‚ùÅšüù Ÿ Gòä'ù‰àÏO%gßþý’²¦ŠÌ~ºíÝ·ŸŽá¼kÛÇd X‹!K-Æí1å>Ç^:Ç^ĶN+¾e𦔣ÍNZÃÉñwb‘™GsÊÃñ•*jë¶í:r䈻Íñ•*9~ô£Ïì‹5@ÀZ_s$iÕ?ꇟ~:uÝÕtL€]×¹«®ëÜ•Ž¿Œ1d0(‚†iš2rŒy$?A~ä'ÈQ€üùI~Âù ø›a8ëØáº¶Ú“˜¨qã'd]nw:\×ÖQS@†4ñôãænöu¥qÂXà!!!º}È`Ý>d0QŠÍM'ˆß ürÁ¢ Åò ?AŽä'ÈOòÁŸŸù±ÒÈ%+º²Ó±—DÞ×@§œcí„ ‹ik'Ç?X @ÖŸËàÄ {bä'ÈO€ü9 Ÿù Ëå'§ÁE»¡l‡5@`-šºÍÊÓÎÙêØ L%ƒiÄ4M9Ãiñ–öç>òK„xbä'ÈO€ùI~‚üN7?@åœk'Å߉¹ÎXÀv˜ –c•_2[ùçv;ö|YhZ/”P^ο·SÃÙ ¨´Ö ÿ@¨œ"ÈžÄN®ì‚üÈO£ù Ÿ°l~±­eãæØƒâØ8k€p$ÃióÁ#æNŒ¿ÓÚÌX‹QpΊµ“㟧F)N :Œ+ÉÓ‰ ?òä(@~‚ü$?üùYÛòœãØ8S`ÛñÛX C°púÐ6Ÿù r ?òVÎÏü2,µwî58öÀ{!ÉÄ9ÐiçùñäÔSÁ‚ 8Più˜¡vê8ÀÛ\$?A~ä'ÈQ€üùI~ÂùYضV‰À±.×@αöä—ˆá´q4z¹‡kä'@~‚ÈOŸä'‚??@` ,gÅÚÉñ§Â‰œØò ?AŽä'ÈO ˆòॵ®×kô”€P K1,6“Á±—ú±µ-)°R¢ÉÉÁ|b#?A~ä'ÈQ€üùI~"øó_1–c•b‰•qn·cÏOiM„ÒË‹Üë`9m §­³äŸˆÁ¯Gd/xù ò ?AŽä'@~Ârù ðÿyׯÉŽEØY±vrüY„΄ƒNlù Ÿ Gòä'ù‰àÏÏüXiÚ+O¹c§c/$™(€8íãàQNeç"í€Ýøe‹!˜8}q#Ÿù r ?òVÍÏ¢¶µJ›8öà8v«çœÓþl û ÇŽd8m> äù9oo¬Ûc~[Ÿù r ?òÖÍO yGî9û5EÐí+”´€ÕXi1nŽ=8޽$¶…õÏNް´?é× œ<À‹5@~‚üÈQŸä'ÈOàtò_1–ÃBâ{IåE`gŸ7˜ËÞ\t&œzbÈO€ü9 Ÿ ?ÉO~üÃ0 Û?¶‹0p* oÎŽµÓ×±;¿@J³r•“ä'ÈO€ü9 Ÿ ?ÉOX#?Ogžs»s ¼âya'Œ¶ã—EУ¢¢tüÄqE„G0„ ¥Ê0 ?q\QQQä'ÈO€ü9 Ÿ ?ÉOX,? b•¼µòsÎnÇnõ\¯viqžŸ%Á/„ê Ú±s‡b¢cɳ ¥ædÊIþ÷°j$Ô ?A~ä'ÈQ€üùI~ÂbùY«ä­•Ÿsv;v«çx ´Kû‹óü, ~)€ÄWŠ—išÚµ{—ö'íçÙ…R¥„ê Š¯O~‚üÈO£ù ò“ü„Åò³ VÉ[+?çìvìVÏ%ðh—öçùYŒäää"Ƕ,ûb™º_ß½ø;g!‚†o‘Ÿ ?òä(@~‚ü$?aü,ˆòÖÊÏ9;»•s ¼Ú¥ý¾L·5cÖ µ¹º×Ûß;m‹& »Ð?#@N§!@0?Ñò ?AŽä'ÈO€¼åØMr ÄŸö[‚‹ôvCØ`;@€íP¶CØ`;@€íP¶êí†3fÍ ·€%x]¹ù†›é­BLÿdºÎ®uŽŒ\×›^Ü×(h£œ;3Í|o3s=¢Ç¥ïSÈÃäºÖȾÒ6mÛ¤6W·!Ø€ J”Ã0N• Lw%!ûšœU†<ˆB YךÙe&Ì<»Íï€<.š¹®Îï¾F~Gi`)@JË0²K˜Æ•„|j•ŒB®Ís›az¹×âlQØÖ&XdFÖ`‰€Ô =*ƒQ ëð©’””¤-[¶û~fŽ5)LÓ,òrQÛ§¦fÊ*<ü÷ýé^öFíÚµU±bEë\†K¦‘µ*GÞñ†LyÎ[•ýˆyê%ù/ÝqêêüGfähMžÇùoÓVûÈqÀyÖ1$™&ã?–âSdëÖ­ºôÒKÝq+W®ÌS1\†{Â*#ë?ÿ1å®4ä®K¸ëæ©K®Ü3\™Ùë+çn³ödxllx¬tndÿ/÷óœËs‘’¬ãÏ.¤¸dPXˆ+˜®Ù%—Yê8\.— #$«â2d.¹ —\†!Wˆ!—ËË‘a¸Ü.WŽ¿¬ÿ®ÿöá2d¸ro—ý—½ßìÇqÉ0Œ¬»\ q¹â¾>Ç_ˆáþËÚGˆ —ë¿Ç qÉqÉp…ÈåÊ>¦ž-Ë` dÈáÊúWî[$©÷€AªZ¥Š^zîåœqË4M=üøSJÜ»W“Ç¿ŸcoE<ž{P†™£”å9’#Ÿkås’c˜Šqj{3ÇÍî­\; È•ÈÜ#$6oÙ¢6:jò´Õ™Y£> þ“¤ˆðp­Y»ÎcDÆ/kÖ*2""+ †áþ3ŠúË1Bä¿ýÿ‡+÷H’ÿþ\Ù÷qyî/k”Ê©ÿžúËÞVáÓÌÌÌo[»n½î{èaÝ{÷]ºîÚ6¶í¸üúÀårI«u(ÏåŽíÛiÁ¢Å:¿YÓSךútÑbuêÐ^£ß{jRZzº>š1Sßÿðƒ$鲋/Ö-ÝoTXh˜$é–¾ýõÑÄ=æ–~ÿ]·î÷š6}¦ö$&*&&Z];uÒU-®ÌÜašš»àS}ùõ7:~â„.hÖTý{÷RÄ©"Lî`5>ý¬¿ ȪÔ}?¢çŸyÊ]üÈÌÌÔûNP‡®×«eëkõôó/èĉ’¤· ÕÒÏ–{ìcß¾ýjÓ¡£Ž=*Iš8yŠZ]×^Wµi«—F¾ª´´4÷¶©ii9j´Z·ë Öí:hä¨ÑJÍqûŽ;õÀ#êª6mÕüšÖºïáGôÏ?ÿ¸oovÉešúÑt]ש‹Î¿ôrIRZZš^ze¤®jÓV­ÛuÐÄ)S½îƒ¬‘®\#5\#@.¹èBý{ä_mÞ¼E†aè÷?þÒ‘cGuñ…䨇¡¹ó?Õî=‰ñÌ3ñìÓÚ¹{·æ-X豯ܣAr^÷Ö»ãÔµSG÷m=ýØ£Ú¼e‹{dÉâeË´ñ?ôÄ#é‘/+3#SϞ뾯+÷“ €”Xäó/¿Ò3/ŒÐ˜×Fêâ /t_?mÆ ýüË/zwìÍŸý‰ÒÓÓõö{Yë\ ê×Oï}0Þcï¯Ý»«lÙ²’¤U?þ¤i“&hÆÔÉÚ±c§ÆOœäÞöƒ'hËÖmš2a¼¦L¯M›7kü„‰îÛ|ôqÝtà Z²`žÏ›£ŠqqóÖ;ǽú×_5iüûZ½ò;IÒø‰“´cç.͘:YS&Œ×÷+WzÝîà ø“¤uj×Nó.’ËåÒ¼… Õ¹}{…„„œÚGÖ¶ß­\©þ}z©B…XUˆ­ }zëÛ•+=ö•{aôœ×…„¸ôÏáÃ:zä¨*ÆÅièàAYÓ^¹\ú⫯5¨__ÅWª¤råÊ©OÏ[ôãÏ?ç=f#kñóœ €”XäáÇŸÐ÷Ü­zuëz\?{î|=|ÿýªZ¥Š¢Ë•Ó=wݩϿüR’té%ëŒ3¢Ü£@vîÚ¥•«~ÐÍ7Þà¾ÿ÷WŸ8UŒ‹Óý÷ ×ÂÅKÜ·-ZºTÜ;\•*VT¥ŠõÀ½÷jÑ’¥îÛgL™¤ Ïo¦ˆˆ•-[VÃn»U߯Zåq|Ü{â*Tp_^¸x‰û1³÷émd­áòXßÃ8UtÈ. †¡–W^©-[·êû•«´sç.µhÞ<Ç¨Ž¬ûý}èâããÝ—+ÇÇëGeäÜ6ûO’{=ï½W6nÔƒ=®»ï0kÝ‘SÇrà`²†?ðnêÕG7õê£ÁwÜ©ƒÉÉ®5’µ€u”Ø ?üž{ñ%s¦š5mâ¾~ï¾}êÖýfmsŽ&دŸÞ;V×¶n¥wƽ¯¾½{*22Ò}{µªUÝÿ®^­ª’p_>pà Çí Õ«yܾñ÷?ôúرúóÏ¿ôï‘#y[’â+Uò¸œtà@ž}æÇ4Í<׆á±xF~³F.—Â#ÂÕ¾íµóλºå¦–£o²îTþ¬³””t@Õ«eËþ¤$Å–/ï.D„……)5-MᒤÇþñ8†³k×ÒC÷Ý+Ó4õËš5zë½qúàí±’¤ bõÄÃ)..νÉÿ/¦dæl+‚,ƧŸõç·DçŽôôéÞÒ×+V¸¯¯_IŸÎ™¥_V}ïþûùûoÝ··h~…BCÃ4æ­·µvÝz]ߥ‹Ç~wïÙãñïŠqqîËqqÖÏß«/—-ÉS¼ÉÝ–Šqqûܵ{×}`„d”qeýeM!år¯½!I!†K!†KݺvÑÇÓ&ëúÎ<§µ:uŸæ—_®'MÖ¡CÿèСC?q²š_~YÖí.—êÔ®­O.Tjjª<¨wÆÏÚ¿ËPˆahÔ˜7µgO¢ÌLó¿cpeý÷ºÖ­õö¸÷•¸7Q™™Úµ;Q£ÆŒ=5…WˆŒœSa…Èe¸ÜSt`>@ Z¢EóæõÊËzúù5áBIÒ Ýºé¹_Ò¶íÛ•––¦Í[¶èáÇŸtßÇ0 êßW§LÕ þýæ±ÏWG¿®¤”tà€^ýºÚµ½Ö}[ÛÖmôÊk£µ?)Iû“’ôʨQjÛ¦µûö'OªL™2ŠŠŠÒÞ½ûôüˆ—ŠlÛu×¶ñxÌ‘£F{ÝYʼn‹‡» .I.#ëO’á’ —á.Šü·]öVY—oº¡›ªU«ªûyT÷?ò˜ªëÆë»¹ï{ûAúeÍoê7hˆž|ö9ߤñ©þÌšæêâ /Ôÿ½6J=úд™35ü®a’‘õ8Ú]§‹/¸@/¿:J=ú Ô¨1oªù嗻ɳp“=­£@ÖáÓX…}Þ´Ic½7vŒ† ¿W‡ý£Þ=n‘Ëe辇Qbb¢tû­C<îãr…(¡zuulß.Ïþ.ºàõèÓOéé麶uk è××}Ûàý4zÌX)í‘L IDATõê7@’Ôúšk4¨?÷íO=ö¨^{ýu=ôØãªP!V}zöÐç_~UhÛöï§‘£F립ªÞ={臟~ʳ]~üûÅÈš Ë”æ}2C2³¦ÆÊšAËsûyÏpÿ;"<\Côײî¬S;9¥FB‚^~ñyû_×öÚS›ºòŠËueó+²(Ïqvlw:´»N† ™9öëù0=Öd$''›Em´äóeêqãëx|ûí·ºâŠ+Jì †ßÿ Ú¶ií1z#Ø}÷ÝwºüòËÝ—§Ìœ®«.ožg»ìÒEΩ›kW>ï7ëŽ+V®P›«Ûð¬­{§mÑ„az7$éd¤Ç傦À*®ÌÌLÍ¿@‰{÷ªM«k,Õ¹û 95RaaaJOO÷¸ÞÈç_E*Á†7ûõ\’ï¡¡¡ å™°¯¾Ñþ;%ÂãrI­qÁeW¨JåÊzùÅJ¬¨(¹û ùd„Öm\§Æ +""ÂVI’’’¢M[7©QÃF©S§ŽV­ZUì3M³Äþkš¦{ª¢þ›ýï¢.G:u<ûˆ"AëÈáÔpË+VTÅŠ齜}”N'$¼*€dÊÐ3K©\T=–#'Ò”)ƒŽ H¸¼ÙèV±Ú¹ïo9‘FåräDš¶%þ­»Z–§3^iS7R±g¸ôú7õãö“ôZÕŒÔàK˪ymÖ X„z»áùÕÃ5©g,=‚ž‹.vCØ`;@€íP¶CØ`;@€íP¶CØ`;@€íP¶CØ`;@€íP¶CØN¨/w:‘rBëÿøE;·+33#ßm\®%T©©†õš)*"*(ߪ]-_ô©¥Ì}oÅþØ“OßÿZ«ÌÌL5«‰BBBòÝ&##CI‡õû_kÕ켋ééBßP4Ÿ IÉ{u^ÝóU!6N.Wþ³heff*<"\ëþ\]äþZµëPàmŒ( ïÀnRRS5kÎ\}½â[íÞ³G™™™:3&FµkÕÔ Ï<ôÇŸýݲ¯ß#ßУ—>šø¡ÂÂÂÜ×=õÜózæ‰ÇÝ—SSSuKßþÿÎ[Љ‰)öcøT UTä /t»¨È3RôCäì ¦Q¢ïÀÎŽ;¦û~TÛwìÐÀ~}uu‹*[¶Œ~ÿóO}2{®#ú A½zú~ÕjÑü IÒ‘#Gôýªtøß-Iúöû•ú_ýú>?$ áaaŠThhX¡ÛE„G*<,ÌçHKKÓ¸ñê˯¿‘$]ÕâJ Ðß]JKKÓ[ï¾§¯V|«ÐÝЭ«ÆÿÐý%~Q·çdš¦¦MŸ¡ÅË>Ó±cÇtù¥—hØÐÛTI¨¾Ï¯’óºVí:hèàAúdÎ\LNÖg H’f|2KÏž£ŒŒ ]Ý¢…†¤ÐÐP¯â N0iê4mÞ²E}zöÐݺº¯oÒ¨‘š4j侜ß(‹Ü×e_6ô6Íøä<˜õ}mA×›¦©ÅK—iÎüÚ»oŸâ*TP—NÔ©}{†á±Ïî®i3f*éÀ%T¯®»îªÿÕ¯ï1³PAÇSÔí¯mÝJ‹—.s@6üþ»LÓÔ†¿ë²K²–vX¶|¹:¶oïs?»|¹SXX¸""ÂZè_DD¸ÂÂÂ}>¸©ÓghûÎzëÑzëÑÚºm»¦Í˜é¾}ÊG3´?é€Þk¬Þó†~]³ÆãþEÝžÓ¬¹ó´fÝ:ñ¢&_éš0yJÐ=1Õ÷ÞømÝz½9ê5wñC’Vÿú«ÞóºÆ½õ¦víÙí¯¢â NðÍwßI’Z]}U‘Ûf%вióf½ÿÖXïkó»þÓE‹õÚctvíÚš1y¢®¼â yë-\¼$Ï>׬]«±¯Ò÷Ü­-[·êÕÑoHò,n,_ô©O3 ]|áúkófýóÏ?’¤õ×ÍšjÃÆ’¤ƒÉÉÚºm».¾ðŸûÙçHxx„BCà ý 8­/á?ÿò+ÝqëÅU¨ ¸ 4lè­úü˯ܷñÕW:xbcË+6¶¼†ìqÿ¢nÏiá’%ºëö¡Š¯¤reËêÖAµâ»ïƒî‰¨¾÷Æ· QllyÏën¢ ±±ª«Û‡ Ñò/¾ô:žà‡e}é_!6¶Èm½-€ ìÛGeÊ”)òú9ó³ !½zÜ¢2eÊèÆë»z\ïqß~}U¶L]yEÖ(]»wyÞDBCCÕ²ùúü«¯%I6nTŸž=µ~ãï’¤Ï>ÿB-¯lîžaÈ>Ý3,4\E>pDD„ÂB}ÿ>ùï¿U9>Þ}¹JåÊ:˜œìq{||%÷åœÛzs{NIû“ÔÈm>%V ªï½Q1..ÏužñŠÏ¯Ââ NpÖYgêÀƒ:˜œ¬*•+—È>Ë—/ïÕõ{÷í“$õä9``Obbžûfh²¿6M³DûáÚÖ­ôòk£Õ¹C{9rT ê×Ó‘#G”––¦eË?×ã?xZû÷y °°0¹\… ;­u(bË—×Þ}ûT#!A’”¸w¯GE,¶|yíÛ·_Õ«W󜷷çT±bExîÅWªÔOŒ@õ}xx¸RRR!IúûС<ÛäW ʯ½ûöå‰Wañ'h~Ùeš=o¾>ÿò+õîqKÛ†¡ÌÌL™¦)Ã0Jäå±±Yß›OŸ<±Ô¿Ÿ­S»¶$iégËU¿^]IRýzu5wÁ§ sßî+Ÿ¦ÀŠˆˆ”if¹if*"Â÷EįnÙBcß}OÔƒ5ö÷tU‹·¿=î}%'ÿ­ää¿õö¸÷óÜ¿°ÛsêØ¾^{cŒvîÚ¥ôôtmÛ¾]Ï¿ôA÷ÄTߟsöÙš9k¶Nž<©}ûökô˜7½ºßÛïÓÁädLNÖÛïÓ5Wµô:žà}zõTíZ55mÆLÍš;Oÿý·Ž9¢5k×ê‰gžuoW½ZÖû¿ùö[=vLNš|ÚÝ­sgIÒ»ï Ãÿþ«ã'NèÇŸÖÃ?Q¬ýÄDGKÊ;ð U»‹¤¥M«kôÁĉj|Þy’¤Æç§IS§ªM«V§ÝVŸF€”?+N{“U¥Rµ§bJOO×Þ¤D•?+Îçƒëysw½7þCÝ~×pIR‹+›«çÍ7yÜ>öÝ÷4hèí U—Ž´æ·µ^ßžS×Nå2 =õü Ú·o¿ªU­ªþ}zÝ#P}ÏwèÕ×Ç裙ë¬3ÏÔÍ7Þ ïWýPäýš6i¢Ûî¼[ééjÙâJõè~“×ñ'([¦ŒÆ¼öª>™=GK?ûLã'LTFf¦¢££U§V-÷v÷ ¿KoŒ}[/¿:J•+Ç놮]µô³å§õØÝ:wÒ™11š5w®z$IjØ nèÖ­Xûé×»—&L™êÞ‡/ ¡KR««ZjÜøÕ¸QV¤Ñy •––®V9~\ï+#99¹Ø“v…††èÐád=~¤À9¿ ÃPÙ3Ê鬘X¥§g$i¶nÛ®'Ÿ{NSÆàÓíV¬}@0¸wÚMv¡o#@222U¡|%UŠ«RàBá¦i*##C©©©~mÈÛïS÷oPZZšÞ7N—_zi±n·š`ê{‚•OÓ4•’’ ¨T©’î¸û¥¥§ë²K.Ö€>½‹u»ÕS߬|š eOå¢+€ÝP¶CØ`;@€íP¶CØ`;@€íP¶CØ`;@€íP¶CØN¨™™™©ýö+11Q'SOuÀ ‘ᑪR¥Š*ÅU’ËÅo§øLXëóˆ# ûìמÄ=:³L9U<³<™x!%-U{÷H’*WªL‡ð™°ÔçG@U!æ,ÅVˆShX™x!=-M¡C•˜˜H„Ï$€å>8¢r2õ¤â+WQzF†233É›0M“Nð'ÃP|å*Ús`}ÁgðYÄrŸGBÑO†""#•qü8I¤ñð à}D𾦟ùLÂyÀç€÷Vü<ê¤Î")¼yàµ|ˆç >“Àû €Ï"Î8o8cˆ N²¼Æi¾ŸŸIÀg+} %A|À9Šû ÎÑì|.hÕ®ƒ–/ú”>$¿éÂÏ#œŸ”ÄùÀUœ?ñd¾'ªVí:X¦£ø ¾?À[3?™¥6:iæ'³Šu¿ü>³ªøÁg> tkHt¹rš÷éBuéØÁZ­ä=mp‡‡À9ðóî:ëý´išš¿h‘n2X³æÎÓ×w³ÎyÓ/¯Î¹à³þ^ºX»î¸]wÞsŸÎoÒDÕ«WËw›Ý{öèƒ “´fíZedd¨Y“ƺç®;-)ë—Wwßq»fÌš¥ƒ“U­j 6L{5mÆL8xPuj×Öƒ÷ w?†išš6}†/ûLÇŽÓå—^¢aCoSdd¤ûq ¾Î|»|ˆÆé|ÞŽ~þñ§ŸU®lYuéÔQŸ}ñ…~üyµ.¾ð÷íš<í#-[þ¹Ž?®ž·Ü¬»uuþÈþoö熜Ÿ!ÒÒÒ4nü‡úòëo$IWµ¸RƒôWXXØŸc†Ý¡é3?Ö¡þQÚµußÝwªf|&ೂôóˆ«8—-SFÇݡ#_Uzzz¾Û<ûâuîØ^Ó'OÔG?T…ØX}ðáDmVýô“^~áyÍ9]W·l©GŸ|Jß­\©—žV³§OÓ¥_¤Qo¾éÞ~ÖÜyZ³nFŽxQ“Æ¿¯ôŒ M˜<…dôánþÂ…êܱ£$©Sûöšÿ©g±aúÇŸh݆ ùÒ‹šüá:xð ¤ÿ Ë}Z`bêôÚ¾s§Þzc´Þzc´¶nÛ®i3fzlóóêÕzõÿFhöôiºè‚ó5jÌX>“Aüy¤Ø‹ 7ntžš4n¤‰S¦j`¿¾ynoì…‹ˆðp èÛGo»Ýc›ûîºSåË——$]ߥ³ÆOœ¤áwSù³Îr_7õ£éîí.Y¢gŸx\ññ•$I·¨aÃïÕmƒ¹·)ù{ $OÈ `{÷íÓmÒS=*)k„Æÿ·w÷qVÕuÀ?ƒ 0 È 3¨¨=híš¶kR[Y>€ ²X«¦(jf䦵eµ«åZi›šò``Òn)Bëú”V¯vMW­×nFÖ&Âð4¬ˆ3wîþaÜš•;\;ï÷ëu^¯¹çwî½ç~ïåÜûý~9ç7kY³¶”'Üsï½ùüg>‘MMI’éÓÎ-ûñï{àÁ\ù¹+2|ذ$ÉEÓÏËweþúŒ©¥m>zÑ…¥œeÒÄ Yü­;:=†œÀëKß¹ÓÙú`.žqiþüÈ#sèÿQ§±_¬X‘Ùsçç—O?7mJ’ôéÓùD“mÍ$éß¿ÿ+ë~›Hl[·eëÖÒíuk×å¬içïô—ú¶mý€®{=ü޾ëîeyþùçsÂ):­¿sÙ²L;û¬$Éú -¥æGWµlܘ¦ÆÆÒí‘MMÙÐÒÒ9y•œEN¯¿|d§ }ûöÍe—ÎÈç¯úbnøêµÆ®¼úš|ð¯¦äŠO]žAƒ套^ÊøÉS*z ùâß>#FôøÄ ^O?v%ÀÝeëÖ­ù—{ïË‚ys:åk֬ͅ›‘3Ϙš=÷Ü3Ç ËêææNór”{¬¬¯«Kóš59`Ô¨$Éêææ «¯¯Úc6ÈG€Þ ïÎÞñ€Q£2ö„ãsÃM3;­ommMmmm µëÖeÖœyïäØOȵ_»>^F65eå³ÏfáâÛóéË/+móªJ2|QàxôØß|ÿ¡¼õCþà?D56ŽÈ!o~s|èá÷Þ÷äýï{o®¿if.½ä£ß8ž¯¯ß}+yâSÆÍ'¯øl§u¿ä£™9û–üý¯NÝС™4qBþá+zãÇMŸšš|öÊ«²fÍÚì·ï¾9ëCg” 8Ýv:áÈkû;ú»KïΙœºÝ±±'ž‹å¸÷¾'“&NHkkkf|âò´¶¶æŒ)§—¶›2é´\<ãÒlzé¥í6)¦ž>9³æÎË¿Òsì1™zú¤]C9 ì¾|¤¦¥¥¥êÏ{ôñGsÄÛH¡Pði€.Øc=J¿§‘“@OÈGfÜötæ_tdeg€ô4þ·½]W¯‹ë»@N¯E>â;ØzEÄ|'Žb¾Þuìè ×Û€ŠO#'€ž”ô>^ó°$`·q ,ð]ÐòÇg`Wè ÚÚÚlÚ´)ƒöŽЫI"€®Ú´iSjkkBNò Çå#}zCÓ¼¶9›6mò‰€.$Ík›ÓØÐ(rèqùH¯8¤®®.IòìêgÓÚÚê“e0`@šF4¥®®.…BA@ä$Уò‘^Ñ) ©¯¯Occ£Sí LÅb1mmmioo 9 ô¸|¤×L‚ÞÞÞ.qä$ÐKô Úh€UG¨: @ÕѪŽPu4@€ª£T  êh€UG¨:}ËÙè©§ž)à5qÈ!‡tù>e5@Ž:ê(Ñv»7îÔýúv烼ÌT  êh€UG¨: @ÕѪŽPu4@€ª£T  êh€U§o¹‹Å¬]¿6Íkš³ùåÍ"×EµkÓÔØ”ÃG¤¦¦F@ª˜šzevEM½ìÈÚõkÓ²±%‡zXêëêE¿‹Z6¶äç¿øy’¤±¡Q@ª˜šzevEM½ìHóšævèa²÷lݺUô»hÈÞCò–ƒß’'ö¤@•SS¯Ì®¨©—ÝÙüòæÔ ­Ë–-[D~'ttt¤nhSz5õÊ슚zÙ mר*‹"_óT?5õ]ÇÑ·+‹EoVÄ ÷PS¯<~•(ÿ Ô¤X,¦£££Û^Ì»Žû@¼ç{=îM(w¿‹Åbjâ €j·;jêåè©u÷¤òšz—.ÕÑÑÑíoÖkýaèÎýîèèp ,€^`wÕÔËÑ“ëî»íXI×N9¹}É·s˼ù9ç¬33ùÔ‰»üñ_OœÆÀÿÕݵãgV>›¹·ÞšÇŸüi^~ùå¼ñ ƒrú¤SsìèÑ»m^¯Êo€ÔtízeÅb1wÞ}w.˜vn¾ýïæ´ ãËêÔTs¤X,ưzšîŸdÕêÕ™ñ‰Ë2éÔ‰™>íÜ ÝgŸüòW¿Ê·–üSŽ9úèÒv=ºî^AM½Ës€”¨{ä‘ì5hpN{Rþõþûóïü$vä;Jãííí¹iÖì<ðÐÃé»Ç9uÂø$É /¼³¦Ÿù³oÎàÁƒKÛ¿øâ‹9ûüé™wóÌ<÷üó™{ë7òø“?M¡PÈŸ~x>vñE²÷ÞI’÷86½ð‚,¾cIþç¹çòÆ7”$p@’¤P(dÁ¢Å¹çÞû²yóæL=}réù‹Åbn»ý[Y~Ï=yé¥Í9ú¨¿ÈE矗¼ê~—Û1@õëjM}gܺ`aN76§Ž?¥´î-œ+>uy§çÝöw[[[fÏ›Ÿ¿ÿP’ä]cŽÍ¹g™~ýú%Iþãñ'2kîÜ<³òÙ ÝgŸL=}rŽÿq¥ÇxµÚyw¨´¦Þ§ì7«¦&…B¡tͲ-w.½;ãN:19é„ãóÝ¥K;/\|{V®Z•™×ÿcn¸îÚüûO~’$4hPFýÎ,]¶¼ÓöK—/ï3&µµµù»/\±'œ…óçfÁÜ9©¯¯Ëœyó;]Oí‘GË—¾xUîXøÍyÄùêõ7–Æß±$Oþìg¹æª+së-³²nÃ†ÒØ’þNžxò§¯ŒÍ¾9ííí™ÿÍ;ÜïrbR(ÌÐ tµ¦¾3Ë<þDÆ3úU·IÒ©¾ýß¿ùMn¸îÚÜpݵùÕ¯…‹o/_ý•¯dʤÓòO‹oË—¯þBþó¿~^ví¼;–Jkê}º²ñ¶nÕŽ–ÕÍkòÔŠsÌè‹ÅŒ=:O­X‘æ5kJÛÜ÷Àƒ™~î9©¯«K}}]¦Ÿ{né9N{RîZ¶<ííí)‹iooÏÝË¿—ñãÆ¦X,榯}5‡½íÐìÙ¯_jkæÌ3¦æ‘ÇëÔMûÈôóÒ0|xú÷§œœO?]¿çÞûrÁ´iil‘Aƒå¼Ÿ][þ/÷äÂó§eDCC ”sÎ:3ÿèGeíw9 ½C¹uã]^xñÅÔ ºÃšô¶¿ïð·õíúßÕ·ïðû¥ñ=úì‘ -ó?Ï=—áÆå’\Xví¼»–J” ¬.ÌX¿tÙ²<ÿü wê¤ÿ³~yÎþë%IZ6¶¤axCéñGŒHòJ'jß‘#3jÿýóð”cG‡~ðüõ-‡dX}}:::²â—Ogî7¾‘§õëlÚ´)IÒ§OŸNû6dÈÒí~ýúeëÖ­¥ÛZ6¤qÄˆí¾–µëÖåœén÷µïh¿w¤ÒëèºRSßY{íµW6´´”êÔÿŸßÕ·7þA}»ecKéög>yy}ëŽ,\´8ƒ÷œóÏùpÞñ§šdǵóîPiM½oWŸlG/fk[[î½ÿÌ™ùõŒhh(­_»v]f\vyþêôÉÙ³_¿Ô×ÕgussFí¿_’duóêNoÄÉ'˜…·ßžÑï<*ß½ki¦Ÿwniìê/¿rÎå—~<ƒjkóÒæÍ™ò¡3;íÛöösÛºaõòjõª0jÔlÓ0|X>ÿ™OwÚ÷ß¿ïŽö»œÕ¯» oÛÛòý‡Îi'ìp?’¤nh]§úöªÕ«R_W_ÃAæo/û›‹Åüä±ÇrÝ×nÈ7çÞ’dǵóîŠ_%º4HGGÇOGyèáäàƒßœ†áÃ;­ohž7½éyè?xå²XÇŒÎì¹ó²¡¥%ZZ2kμ$¿;ç퇖͛_Î]Ë–gÀ€yÖÆZ[[3pà€ôßsϬ]·.×}f§ûþþßÛ[÷žw¿+3gÏIóš5yñÅM™=w^iìø÷¿?×}fžYùlÚÚÚòëÿþMþá+×–Æw´ß¯¶8 w(·¦^É2eòi¹óîeùÎweý† ÙºukžúÅŠ|áš/o·6~ìè£3kÎܬ߰!ë7lÈÍsææØÑG—Ư¹öº<³råo§§HjúÔ”];ïŽe·RîŒõK—/SOŸ´ÝíŽ?î¸Ü¾dIþr̘œ6a|n™7?]2#{ôí›ñãÆæñ'Ÿìt¿q'gÎÊç>ý©Në?rÁôÌ™k®þòµ©:4ãÇÍ~üãíÎjÿû¶­›pò¸´¶¶æ“ŸùlZ[[3ù´SKc'ÿÔ$ùÂ5_ÊÚuë2²©)gL™\/g¿ÿ?•ÎX@ÏPnM½M¹òsŸÍ‚E‹²èŽ%Ù²eK:ð€L8ùäíÖË':1ó¿¹ ûÄeI’Ñï|gN›8¡4þçG¾#Wýײ~ýúì·ß~ùøÅ—];ï•ÖÔk§VöIDATZZZÊÚ»G4‡zx¶lÙâ“»“ú÷ïŸ'~öDŽxû‚PÅÔÔ+·³5õ·=ùÙµ9@ …‚y,*P( —PS¯<~•(ÿX»aÆújg€Þ¡»kê§LÝá6ß^´°GÇp·ÎR(ºõz^Õ®P(˜ èîšú’Ûìp›ž^ϯ´¦Þ¥K`m›±žãì€ÞCM½òøU¢ìÈÀ³ùåÍé¿goØN¨©©Éæ—7gàÀ‚PåÔÔ+³+jêe7@F6̪ի²Ï}2 ÿÑï¢Ö-­yîùç²ïÈ} Ê©©WfWÔÔËn€ Ýgh:::Ò¼¦9[¶lý.êß¿š›2tŸ¡Ï\À뛚zevEM½ìH¡PÈðaÃÓÔØ”>}úˆ~utt¤½½=mmm‚PåÔÔ+³+jê]š½­­MÊ ¦þÚÒvªŽPu4@€ª£T  êh€UG¨: @ÕѪŽPu4@€ª£Tÿr’nUPÕ†IEND®B`‚antimicro-2.23/other/appdata/screenshots/controller_mapping01.png000066400000000000000000003161031300750276700253000ustar00rootroot00000000000000‰PNG  IHDR@„ùMý¢bKGDÿÿÿ ½§“ pHYs  šœtIMEÞ o9;W IDATxÚìwXWÛÆï]Xv©Ò›]1šÄØ0vÅî÷¢h jÔWPDQ"4jb×Ä.‚bE±$ö^bâc,¨‰Ä‚¤.R¶²ß† ËîÌëó»./ugæœç<Ï}ÊÌ™9‡£P(PPP‚ ‚ ‚ ‚ ‚ ‚ ˆ·{{{—\AAAAAAÄ»M€AAAAAñÎA AAAAAA¼sÐAAAAAAï4BAAAAAÄ;M€AAAAAñÎA AAAAAA¼sÐAAAAAAï4BAAAAAÄ;‡)¹€ ‚ ‚ âíãÞ½{¸sçx< …Ús8D"\]]ѽ{wraT¤R)Nœ8SSSÈd2­ç+ øøøã‚ ‚04òÐ×{N=ü^•ùîbùÊUÈ|öŒqÙßG?½8LºaŒW¯¾mÐt=Õ'jï©"Hs5¹}ç./ÿyùùoî m;Õý7ŸÕ«W£wïÞ7n£ó% :t耵k×¢uëÖä@Âàœ?×®]ÃâÅ‹!•JQQQ¡õšŠŠ 4kÖ ·nÝ"AaÞ¨%°úzz¥×¯øÄDK7ÖÄ{ µ]äo‚´D¼YlÞ¶ Ó§†+Ç'oz¬«Ú÷¶ÙNèÇ_|ÐÐPtëÖ R©”чƒ›7oÂÕÕ$'å믿F§N0þ|ˆÅbF“ÀårñðáCLœ8æææäH‚ ‚ Ž^ )ûRÑÐ`¤ìK5ÈêÃûzÂ'Nªñ)·B¡À¸ ¡*×ÓCô·‡2ÐñÓö¬ôa r‹%˜¹û/´û?¸N¹ˆ¦‘—á†S· Þ8Ÿý•]†/âïÀcÆe¸…_DŸå¿ã‡ëyKßaÒ…·F?ëO=…óä‹Xê©ÚrTþiõ &mû¥Ò7²œïJÛUZZŠM[·á‹ñ!ø™/†úbÞ‚E¸~ã¦Jîë=ýú`ð0L˜ŽM[¶¢¨¨HçºõÚ5̘õ5¼?ó…ÿÈÑX¹vŠ‹KÞy¿Ž¶òM¶ïuø€Æï®Þ=Ê@›Ö­j›¾iTµO“íÄ»Ejj*6mÚ{{{Æ™+‘H$hÚ´)N:…S§N‘3 ƒ‹àà`ØÛÛC.—³¾^¡P %%Ó¦M#gAaptžQ(øáèQL ÆGÕºæ¬>ðù|\ùõªÊo?_ùEî-§¬¬ <ïµÚU(Fÿï®C`ÆÅž°O±ª®Îï€ÿz¹#þ|æ寇¹åðYsšÔÁùY푱ª¾ ðÀþßòÞ;íT(€-Ÿañ°¦Øzé*Ô4=Â/c¼p.ªDÒ ÌJ¹O•Έ,\¶ÅÅÅX²à[Ú—‚­ ѧ—v$'«œwúèaœ:ò#RvnÇŒˆ©K$™<Ù99:å»oÿA ÷ŠÔä$ÄG¯ƒ‰‰ –¯ZE!Bg^”–ÂÔÔ”l'Þhbccáìì ‡£ó}ÇÃ’%KÈ™„AËåh׮Κ^îÒ®];r&AAG绤_¯þk++|6اΞů¿]Sy£¿¯÷ L†Ý){ñ¼°M›4Áô©SШaCåt•WýT¿êÛjÃü°{ï>tîØAùÛî½û8|,Yª’Wåur¹;’’qòô”••!hD †ûUž<ûD¾PˆSG~„T*EB✻pÐË«‚Ç­õá|_ïA˜6 {RS‘Ÿ/D½ºî˜6y22Ÿ=CÒžäåç£i“&˜1 õë×ü™‰Í[·ãÆ­[/‡mZ#"| êØØÔH?ýþ}Ì›¿þÃüà;d0 ’vïÁ±“§PZZŠ®;arèDå$Ðõ7±qs"ž<} ;[[€÷€µÚ^ýmÀª¿iJK›ê°µùµ¶øWµ©¶ã?=¦VSºØ¸ôpü>uÆÜ!•¿ x\ øÄ>qPþö · =ÂOéÏ!“+У…Vþ¬^jÄaÒ|Ø Ñ§ž"«HŒ&NXùy3<Ê+ǪãOù\ŒOêY!zTs4sµðò!þêã±óçl—ËàÝÚË<`af¢ÖÖåG2Ò³.ÂúÖSþæÙÈ[ƒ?Rþ_,«Àü±ÿÚËI_O'|3´ ø¦\¥+F4ÃÚO‘["Á'õ¬°&è|èn©ü*¢òïª{x,Ö1§ÿFV‘ù¼´æSÚʬ./uœ¾#D S÷¬‹=ÿËÁ™;è×Ò^í¹n¶||Ð \eÔ®õõ„àqc±wÿÈårôöòBhÈxå%6mˆH$Â˜à Øº)ÖVVÊê`Ræêy©#ñâ3÷¬ ø¯—;6_4ì×:×®_GÜúµHˆ‰ÆÓÌ¿k´LÛkkkôèÖGŽW¹þȱãèÓÓKåa,$íIÁß™™Hˆ‰F̺5øõ·k*ǵé[ÛõlÊ€IÉ*7²;’’á;dpÉhݪV­‹Æí»w!–HXùÛûÿà÷ë7 »7o¢i“ÆŒÏ×Ôž°iÓjÓ†¾1U—&“¶’m¿Æ¤ÒT/jë;4µåÕ˥͆Úúvmý “zȤüšâ Ë8‚iß[É{“›‡M1·~®ß¸Á:–lÇ0LtªIÚlÒVO˜úÇõ¡zUÓa:ve:æc“¶J“íÆêCˆ×ÃÓ§OÑ¿½6+ 899‘C ƒ`bbb!ÜÝÝÉ™AA&@²²³ñgú_èýÏÛÁ½¼zàÏô¿­ºŒÉÔÉapuq@ €¿Ÿ/îßg· ‡Ã¿Ÿ/öìÝHÞ»Ãü4~Z{òôiL w77X[Y!4$XåxØÄ88üû¶ø™sç6!NŽŽprtÄäÐ 8sî¼F»¦‡O»›ü>‚²òrL›2n®®ÊßîÝKWž¿!mZµßÌ –––÷Åh\½¦zcyèða¬^%ó¿E—Nþ}Hsü8Â'…ÂÕÕÖVV˜0þ¿¸tùç*ƒM.„ÂÁÙÉ Ó§†ë1p­=-mvTG¿2A“¦ØÚ(,‘¢®_å·ªûGTrñëöèö-<.lÌM1gpcœ¹£ºGÈš ÐØÉf&˜Ø»^ˆäXýùhä(Pþv-£XyþöËYø>Ð °µ0Åß&øñz~­¶>!…[3¾Ù÷k–÷€»-î¶|,ó÷À¾«¹*ç¬Ñ ^Ú4¹o}Ü|R¢ýáœS¸VÉ›I>ê`RæêyU'#_„ë%ðûg2È×Ó×3JðX(R{~v‘³öÞGÏík,lBàèà€I!!8}öœÎmˆï!øáðå[šr¹‡‡ßÐÏj>¼:{N™we:UѦom׳)k{Ïv07àÜ…—õ óÙ3üvíw ì£69Q3Q¿^]¬‰ÅPÿ@Œ7ñ›QZZªÕ{;;—”èÝ6Üðëcâ0y⃴'º´iÕµ¡oLեɶí/“>JS½Ð¥ª^.m6hëÛ5¡­2*¿†8èÛß±ñßÙóç<öpp°¯á&ea;†a¤S úÐf“¶z¢ï8ÇXã}ê“!Ç>L1FB¼rrrзo_Ö{¨ÃÑÑ‘JSSSƒL€Ô¯_9:.JAQëXE—‹~DÚÓ(,“½| ÃUM×¥ÊC{s³—±u¶QýM$ý÷Fõ©P„ŽóU—eâjX2×Ί‡¬" 9Ö¾ÿMõãMœÌñ¬P¬ª 6ÕF=;ë|ÔÁ¤ÌÕóªÎ–‹ÏÿB ÷©—jüþíÐ&ÊÿWÆÏÑš‡^ÚaÑ0ÆSÕ­k ݲiCêׯ‡F âÒåŸÑ³Gw\üé2>úðÃi@¾PX#6m¶ëÙ–5(0 ‰[ѳGlÛ¹ Ãü”í]u,,,0fÔHŒ5 …ŸJ“Vt釪—K› ÚúvÍS4×C&å×}û;6þÀÕÕEm\˜–…톉N5éC›MÚꉾãcGô©O†û0Å}ñzÉd¨S§Äb±Þi9::¢¢¢Bo„¡¾quuÅœ9sðõ×_“S ‚ ‚0¬'@$ Nœ>ƒ[6ÃÕåß›ðìì„E|‰1#ƒ`ff¦5¦¤ñx<øöÁò•«0vô(­g;9:âYVV­ë¸WÏ×ÁÞYÙÙhØ àYV êäE˾èÏG`Þì(XZZ¢´´CF¨œ³ê»eˆŒšk++øóû÷¡‹³3–.œ¯âëª4óhŠùsç@¡Pà׫¿aÅêµHÙµCí¹fff‹ÅÊÏŸ3NK›ÕÑׯºl ÇÖÆÞÙ!é—l•=@Ô1>ñÌðnˆ-ã`cn‚âr9ïå |õe¼ØPU·YÙÙ5t˶ ñýl¶ïÚ…ž=ºcÿ¡05,TýC‡jéd³Ò·¶ëÙ–µsǎز}'6m݆»ü‰™_F0®»6À¤ !ø|ô­ç=~žmÚè¯ó/!6!óçÌA‹æ­³dÒ¦U׆¾1eÒª;ζýeÒGiÒŠ¦¾£6û«ÿ®ÍM};“þBS=dR~Myhó·>}¯º¼²³s”ûsdeg³Ž¥1úVMúÐf“¶zÂÆ?†¨úŽMØÆ@›> …1úâõ`È=œœœðâÅ ½_D >Ÿo >Ÿ½{÷ÒAA…õë>ç.\ć͛׸ruuAófÍpþâ%F騨ØàÉÓ§ŒÎ ôŽ?BàðaZÏЯ/ÖÇÆ!+;%/^ 6>Aãù½{zaÃÆxäåç#/?ââÑËËË N‰D°°°€@ @Nn.V­‹®yâèˆUË—ãØÉSHNÙ«üÝg 7V­['OŸB&“áQF-[®<¾xùwxüä‰riކÏšyx %u?D"²³s°f½ªšÒÒf‡¡ýÊFºÚ5¨v_ÉÆ¼ýž]‘´…e2œHS}3´T,‡µÀ|.žˆ‘”®·&ÆõpÇ´]éHÏ.ƒD¦ÀÝg¥¿ùn­ç5°6žËDìÙ¿ñ¬P ±¬¿g”`LÂ¿×ø¶wƬ½÷ñ¬PŒg…bÌÚ{_ë¾!*‰,yHÏ.Ózž®ù°-suö_Ë…gc›( hÓÐþÙ”]_bã/"_(Dl|úôê©WÒ¾][”••áà‡anþróïÚÒ©šwL|<+}k»žmY9‚²/AÊ ÕñåWQ¸péžB&“!;;›¶lEË?V{¾X,Æý³1ÇNžÄ£‚tŠÕ¾¿9ß/YlÔÉ]Û4}cªk[ÉÖV&}”&­hê;˜¶åÚlÐÔ·3ÉCS=dR~}´¡Oß«VS › @(,@lÂ&Ö±d jÒ‡6›´Õ6þ1D}ÐwlÂ6Úôa(ŒÑ‡¯¡P¨÷èʱŸƒ£å* B†šár¹(**"‡AaPXrèðŒ©åa•Ï@oìLNFÿ¾}´¦3Â8¿ŒÄ‹ÒR›I²ÅßÏ"‘_ÎŒ‚H$ÂÈÏ @|âL ŸðêÑAþuòôiS—° —.ƒ½üý|qéòe57!öX¹|)"£fC.—cäˆ@ ì.‡ƒo-FvvêÕ­‹±£G*¯éÒ©¾]´9¹¹hP¿>f͈¬ÕŽˆ)aX¹v=’SöÂÎÖÇáç+ÿc”–6; íW]ôÁÖÆúöœ˜ÑßÍÀе7‘_"…¹):7«ƒã‘m•ç­ÙsR`ܦ»p©c†É}ëãÇëú=lîY\0:þžä‹ÐÔÙ³7ªõü&Îæ84­5ýðßyŒr©×µBxÿúÊs"ÿÓßxˆÞË~|ÖÎ Óÿ¯c›¦h€ÿûþ:ŠÊe¿ Ð5¶e®Î¦ Ï0kúóÇöpÇŠ£ØÉEïúÚ¶MLœ2r™ =½zàó½Ûßφ`õºh,]¸@c:1ãSSøûUÙ\›¾µ]¯KY¹\.꺻kmÓG}>‡~<Œ5ë7@,‘ÀÞÞÛŠY3¦«œ××{8>ÜÝÜо];l\¿¶¶¶5Î«Žºv ¿ã&¨~Uócê>˜› ÚŽëÒ¦éS]ÛJ¶¶2é£4iESßÁ´-×fƒ¦¾iµÕC¦}´®ÚЧïU—׆ñ: &¦¦øÌgnܼe°²èÚ·jÒ‡6›´Õ6þ1D}ÐwlÂ6Úôa(ŒÑ‡¯‡{÷îlÄÞÞÅÅÅäTBo 5:t€B¡ÐiE‚ ‚ upÿŒT ÈA¼×ôõdÐ Ù·¹ó ——z÷ô"gÄÈÃG˜·p!v&n¦v“ Þ&L˜€]»väasQQnß¾6z,EIðË/¿ OŸ>zOZðx<¬]»µî=GAÁ”Ê=0iÇ;‚ B…B#ÇŽ#;'½¼zCâ "6>ÏŸ#'7± èÚ¹39… Þ#$‰ÁÞ´/))¹¹99•БH.WÿG 2™ ƒ ¢¥Ù‚ ‚0(¦äâ}ÄaÒrÂ{Ž>¥¿ëôèWÌ›EËĆ‹‹ ¦F@*“¡K§Ž7z9… Þ#>øÀp{^]»v }ûö%§zSXX.—«÷òl …õë×ÇÝ»w•olAAè -EAAñ†óâÅ ¤§§£{÷îIï›o¾A¿~ýЦMzáЉÄÄD¬X±AAAX±b$‰ÞiJ$¤§§£qãÆä`‚ ‚ ôâ­_KÝ&¹obšo›¨œï§‰wO#†´K[Zºæe,ßQ½}3t§)wÿø_Œ1z¬H ÔN¾þ!ÿ¾ûp8åCf///ƒ¥yõêU¸¸¸`ûöíHMMEdd$N:E'jåàÁƒ˜3gâããqàÀŒ5 k×®EYY™Á&Ñ þþûor6AAƒö!‚1ô…bI¡ºhâ}°zõj”––"22©©©(++£ ÈÏÏÇ®]»0cÆ XYYaÉ’%ð÷÷ÇÀѯ_?âîÝ»ËÇãá›o¾ÁºuëpíÚ5 AAzcð ú*ÊDhöéÛìç·ýa%iÜø±4dºLâõ¾Æôm¯‹e ã§í©~¿úyüú®õ¥Á„¢¢"Œ9~~~˜={6œ º1tåFê·o߯þýû¡P(››‹îÝ»cÖ¬Y0`¾úê+|¸ÊCg@€–-[B,,¯ÊôÃÃÃÕ~]"“ÉðÉ'Ÿ &&åååðôô¤½'Ìž=;wî„D"Q;ù¼œ”srr‚™™Š‹‹ –·B¡€——ÒÒÒP·n]XZZbÖ¬Y Æ (8AA°F§%°–®X‰ @Ú»«¿_Ž?þ¼§rzúèa•ÙK–bˆÏ@ìÞ± ÉÛ¶ÀÑÁ›·lSIó·k×°rùRìß„í=±zý¿ƒ›¤=)ø;3 1шY·¿þ¦º(“ôo¦ÝFôêUʇ&ÚÒd‹&û«³k÷dÊ@Òž½ìM=x7ÒÒ°bélOÜ™\Ž­;vjL³*µÅމ­Õ¹rõ*¾[¼Sv£wÏž˜=ï\þå,[´ûw'¡sÇXÍ*~på×_1kî7 …ïÁŒËÍV+Õ¹vý:âÖ¯EBL4žfþ­µüš|ªŸÙhL[9k«ÃÚŽUegòääæaSÌÄ­_‡ë7n°®lµÂ$ÞµåY›ï™ÀTÚìÓ'.lµÎF3†ˆ¥¡Óe/Mçh²W_£]Ó¦+6m¦ò2‰CUvï݇´;w°bÙìØ²ùùùzùŽIÜté_‡^E\«—“‰oئɴLµùU¼})Ûx´÷l‡´Û·yùùˆŽCYy9àVZ>ÕððX“ØøÛXö¯†+W®@&“ÁÏÏOùuF%À {rT~Ò¬Y3­ç…††âäÉ“xüø1é=`Ñ¢EˆŠŠ‚T*Õº±9ŸÏŸÏ7¸ ^^^¸pÕCü… IDATá‚òÿVVVX¼x1Ú·o_ãk%‚ ‚ mè4bbÂ…PX€ÂÂ"8;9aúÔpçÇoˆF›V­À73ƒ¥¥%Æ}1W«mh6ur\]\ àïç‹û÷ïÿ{ó{öÂ&„ÀÑÁNŽŽ˜:uúaCàà`Ï8M¶h²¿:gÎGØ„89:*ó>sî¼^ö9~á“Báêêk++Lÿ_\ºü³Æ4™ÀÄÖêLŸw77ø}6eåå˜6e2Ü\]•¿Ý»—Î*~‡ÆêõÑX2ÿ[téÔ‰U¹Ùj¥:•~wtpÀ¤œ>{Îà‘‰ŸÙhL[95Õa¦õûìùó {88Ø#4$˜u½`«&ñfã'¦0Õ€6ûô‰ [­³ñ…!bù*ÓÕ·MÖÅ—Æh×´éŠMÛ£©¼LâP•“§OcJèD¸»¹ÁÚÊJå|]|g¨6P—>ÌÐZxq­^NF¾a™¦¾ý¢.:xûR¶ñhß®n¦¥)Ïã™™áüÅ—_bÜL»öžítòË>Âø9ruêÔAçÎk<àåp8¸~ý:«¯í´Þr¹(++C›6mPþÏD˜&&L˜€ëׯãÊ•+¬wC*•2:¿¢¢±±± ò„¾´hÑ¢Fû,—Ëqüøqx{{ÃÜÜœ‚EActZkÁؙܹœŒíII°¶²FØÄth_ûf¦éý…„Ä­¸ÿàJþYÇ–ËU{±·³Sþ›ÏçC,‘(ÿŸ/ÂÍÕUùw77Öé;;9©ü_[šlÑdu„5òÎ õ²77'cC&Ö¸YÒ”&˜ØZÃöö*¾Ðæ&ñÛ·ÿ ú÷éƒæ4c]n¶Z©Žjù]µ–_˜ø™Æ´•SSfZ¿…puuQë'¦6³Õ “x³ñS˜j@›}úÄ…­ÖÙøÂ±|•éêÛ&ëäK#´kÚtŦíÑd “8T%/_XkŸ¨‹ï ÕêÒ‡Z ¯"®ÕËÉÄ7lÓÔ·_ÔEoc_Ê6m[·FtìË5êÏœ;™Ó´'Þà?ÿÄŒˆ©:ù‡¿ea\âããaoogggµo·s8ìß¿3fÌ0Xž\.ÅÅÅèСär¹Ö:¬P(ЫW/=zûöíCDDêÖ­KÁ{G8sæ ÒÓÓ‘˜˜Èª_¯¨¨€——àÞ½{h¯á™[>þøcµuáðáÃFLLL­ËsAATE§ fM1î( üzõ7¬X½)»vÔzC¶hÙwõùÌ›KKK”––bhÀÆù9:8 +; ¼\³øYV6ëô«Û¥-Mcâ`o_-ï,8:8èe¯³³3–.œW—ZóÕ6˜Uwœ‰­úÂ$~«¾[†È¨Y°¶²‚ÿ0?VåÖW‹UËŸ•­R~333ˆÅbåÑ‚çϵúôUøY[95ÕaMǪۜ£Üó +Ûøuˆm¼ÙÖ]4ÀÆ>}â¢oÙµµIƈ¥¾é2‰—.15¦/Ù´5ÚtÅTw†Žƒ“£#žee©ÝÁX¾Ó¥_|Zxq­^&¾a›&›2©»V¼})Ûx˜› àææŠ —.Ï7CÇŸbGr2~¾rEù™.þaãocÙGï¿ÿÝ»w‡‡‡G­çp¹\\¸p111÷ár¹Ê?Õµ«P(”***PQQòòr 2„±­2™ ýû÷‡¿¿?Ö¯_¬¬,k´xs©¨¨@ZZ6nÜ???Œ5J§=fÄb1œœœðàÁtêÔI©=‡‡£œÔ«¨¨P.½¦ …BúõëƒÇãÕø¥°°+W®ÄСC±aÃ8;;S0 ‚ ‚ЈNK`-^þ?y¢¼p¸ÿ°mllðäéS•óE",,, “›‹Uë¢Yå×»§bã/"_(DL|¼ÞékKøwsMCÓ»§6lŒG^~>òòó±!.½þysFW{}zcÕºõxòô)d2ed`Ѳå¬ìR;]le “ø99:bÕòå8vò’Söê\n]´RÕï±ñ èÓ«§òX3¤¤î‡H$BvvÖ¬ÖêÓWágmåÔT‡5«¡É„M  6a“Ñ,}u®Î÷Lêº& °±OŸ¸¢Žkl_ŒK}Ó­-^lÏ1´Ž Õ®iÓSÝ:úõÅúØ8deg£äÅ ÄÆ'Ýw†h_…^G\™øF­h+“:¿ê¢ƒ·±/Õ%Ÿzz"6~úöêèÓ³'ÖÇÄáÓöž:û‡¿ aŸ±Æ¿DMæÌ™ƒ   4kÖLãD%‡Ãkµ¯÷¸\.x<LLL ‘HPPP€'N`ÆŒðññ‡‡\]]áææ†¶mÛbĈ˜6m/^Œ . ¨¨”_¦¦Ìß‹+,,ĨQ£0cÆ ˜™™aÐ ÒÌÛÆƒàéé www,\¸mÚ´a5ùÁãñ@©½>ú‡ÂâÅ‹qãÆ¡cÇŽhÞ¼9Ú·oaÆ!22;vì@AAJKK¼œW÷Õ¡T*EFF,,,Ôæ_\\Œ„„̘1Ož<¡€A¡¾éÒ©¾]´9¹¹hP¿>f͈Tá?á_FâEi©rcÊéÓ¦".a.]{;;øûùâÒåËŒó @ÌÆx‡†ÁÄÔþ¾Cñûõ7qÕ%}mi“ ÀÄ'nÁ¤ði¯Ý诗½Cû€Ëáà›E‹‘ƒzuëbì葬ìR;]le Óø98Øcåò¥ˆŒš ¹\Ž‘#Y—[­´mÓ§L…\&CO¯ø<àßòGL Ãʵ둜²v¶¶> ?_ùŸFŸ¾ ?k+§¦:¬éXuMnØñ¡“`bjŠÏ|áÆÍ[F­;úê\ïoß½‹?úHg °±OŸ¸¢Žkj_ŒK}ÓU/]Î1´Ž Õ®iÓSÝ:þ~¾‰DørfD"FŽ4ºï Ѿ -¼Ž¸2ñ>ZÑV&u~ÕEoc_ªK<>õl‡-Ûw —W@/¯ˆÛ´íÛµÓÙ?lüm,ûÃððpHs8ðx<˜ššâ?ÿùRSSqàÀðx<´hÑuêÔ©©)\\\àîmÛ¢_¿~011Q~Rõ«…B±XŒ¢¢"äææâêÕ«¸~ý: ñôéSxzz¢I“&Œ¿¨ãp8°´´ÄÎ;±{÷n;v ±±±µ>´&^?¿ÿþ;Î;‡öíÛã§Ÿ~‚H$bu½¹¹9æÍ›‡ÌÌL¡N:pttDBB¬­­aii 333p8˜˜˜(5XùÕQQQrrr““ƒgÏž¡¤¤&&&HOOGFF:t耑#G¢^½z(//×hŸ\.Gll,¶mÛôë×LA„úq«âŸoR ÈAèÌÃG˜·p!v&n~«ìŽŒš‘Ÿ¢M«Vj÷õÄøa*ÅòÝÔˆ1Ц+cêŽâðnÅõ}l£âm'44³gφ¹¹yɇƒ{÷îáÚµk())Q>$îÚµ+¬œ4‘ËåËåj÷ aŠB¡—ËEFF‚ƒƒ‘’’‚ââbö7•œ1{ölxxxÀßߟ–U{ƒ¸uë.ÿ3¹=fÌ”••é”ÎÝ»w‘&Mš yóæpvvÖi J…B¡œ$©úõÑÕ«WqàÀäææ¢´´èÔ©<==aee¥vBÄÚÚñññøðÃѧO 6AAJ*÷s5%W¡+±ñ > R©± èÚ¹ó[W†Ë–P ËwA#_‚ ÂP|üñǸ|ù²Ê>H$HLLDLL Nž<‰¨¨(TTTÔØèY—}jƒÃá€Ëåâ?ÿùâââ°uëVøùù±žTQ(ÈÉÉÁÔ©S!0wî\xzzbøðá011¡À¿&$ ˆyóæaĈËå:O~ðù|¤§§#<<ÙÙÙ¸ÿ>\ôÜ—¯r¯’V­Z¡Õ?/%q¹\˜ššB&“Á××wîÜÁ‰' ‘HÀçó•-))APP®]»†'N`À€x‚ ‚ Tà’ ‚ЄM@Ø´/áæêŠq£G‘S(–¤ª«A„üüüpñâEå_.— ¬X±QQQ(++Cdd$ жm[H$’“Æ ¼¼aaaèÓ§ììì0iÒ$üòË/prrÒéë‘H„¯¿þ]ºtÁŽ;BÁÅ…BŒ3/^Ä®]»ðñÇ3Ú|¼:|>–––سgüýýáíí ±X kkkÑÔÔ\.+W®„ƒƒ:t耎;’(ŒDRR¸\.233Ž’’½–HKNN†T*…:tè \ÍÊÊ 3gÎÄ’%KôJ_*÷ùöÛo¡P(Àçó‚çÏŸÃÔÔ?ÿü3îß¿)S¦ ‚ â=§r ,ú¤úz"'ï‚xKÛ¶ù½IíVU[ i—±Ò}WûCØL~fnˆw•¼¼<`ÕªU(..F~~>&L˜€cÇŽaëÖ­X²d 5jdðe­ªî¯P¹Ç‚T*…H$‚H$‚D"ðï²F–––ÊsŠ‹‹áíí€Çãée‹L&ƒD"Á”)S‚/^ÀÇÇ·nÝ‚P($èIEErrrpöìYøûû£K—.ðññÁ˜1cP\\¬÷äDaa!.\ˆ-Z¨ì #“ÉаaCåd„B¡Pî'S©9p¹\¥ …D"X,ƬY³0þ|¡sçÎÈÌÌDYYºté‚âäÉ“$‚ ‚ Ð A¼&hã^‚ zF¾!_›w™¼¼>>Ø¿?RRRÀãñ :éÁãñÀår!—ËñðáCÜ»wGÅíÛ·ñøñcXYY¡nݺptt„™™òòòððáCØØØ`À€èÑ£G4MLLtÚ½6^¼x6mÚ`ëÖ­J¥¸}û6æÎ‹áÇ# ÎÎÎ$†Ü¿kÖ¬AVV–,Y‚-Z .. …BíFẠP(jÝ¿E$áùóçøè£ P(`ff¹\‰D‚²²2¸ºº¢qãÆhÙ²%ºvíŠzõê¡^½z°²²ðrïC,ï&‹áêêŠÛ·oC$aÈ!èÑ£&Mšsss¬\¹Ó§O'ÁAÄ{ë ³¾F×.ñ™Ï¿oêüáG\¾rß/YL7„QâA1z÷ xÔæS={ñ©š‡!ò|—uõ6”ë};P_úæò÷ßã‡~€¯¯/6oÞŒÆãñãÇH$Ê·åÙPù™Ë}ùqq1vìØK—.á£>BË–-ñìÙ3”••ÁÃÃü1Ö®]«|û¾2ÏŠŠ ÿn~njjгgϪ}ÐÍãñPXX¨ÜgÁðx<´jÕ ÇGYY~úé'<~üÖÖÖpww‡T*EFFþúë/ðù|åƒtƒä/—Ë!•JQZZ …BQã …ÊßÌÌÌ`mm]ëþÆØàýîÝ»¸téÒÓÓ!—ËѬY3Ô¯_<™™™(//GË–-±lÙ2p8儇1–¢ªüzHS¦LÁœ9sTô\]oåååxüø1ÒÓÓqìØ1”••ÁÍÍ uêÔÁÇqóæMØØØà?ÿù ¤©T ¹\Îøë@€óçÏãÎ;رc.\¸€,[¶ QQQÔ(AÄ{ ë qcFcÑÒåðñþLLL “ɰwÿÌEƒ ‚ ‚ ‚ Þo^¼x€€´k×mÛ¶Åøñã!‹ñQ¹t•T*EAA²²²PTT„k×®áîÝ»Édððð@ïÞ½àåFæ2™Lå!xyy9£üÚ·o¯öw>Ÿ¢¢"£}™QQQòòrp8tïÞÝ»wW>@733ŸÏ‡¹¹9òòòðàÁüöÛoHMME~~>8ììì`ooGGG˜˜˜ÀÒÒ<ÏŸ?GQQ222P\\ ‡SSS˜™™ÁÜÜàñxÊýIj{ÀÎårQVV¦\NL•_2H$åc•“\055…š6m ðù|”——+íÊÊÊBAA Àápàää„&Mš sçÎøüóÏakk ±X ‘H©Tª2Ù`ì=c4•»R§/^¼ÐšNƒ РAôìÙS_SSS@vv6®_¿Ž¨¨(deeA&“áƒ>À'Ÿ|WWW888ÀÅŶ¶¶àp8JÿªC,ÃÃÃGpp0rrrpóæM´nÝš'‚ ‚xOa=òaóæhÚ¤1Ξ¿€~}zãìù hÚ¤ š6iŒ˜ñ8wá" —W«\7–í›yr¹;’’qòô”••!hD †ûü™‰Í[·ãÆ­[Ëåhצ5"§ Ž2Ý©“ð;e/ž¢i“&˜>u 5lX#ŸÊ5§+ÿ®jÏGÕš†B¡@Òî=8vòJKKѵs'L¨ȱ±¡òüàqc±wÿÈårôöòBhÈxå[7}½!4x<ö8ˆ|¡§Žü¨Õ†ë7nbãæDƒþ}û2?Á¼ ±}s‚NoÀ3ѵ&}h‹‡¦x×6>cë]5ñ:t¥Í÷šòÓÖÞ¥ÿu¿Öv¸jüõŸiã};¼Ž¾”0§OŸÆ×_»wï*¿¶`ó Z,ã—_~Á·ß~‹[·náÛo¿Å´iÓ ‘HжmÛçr‰ªêX[[C(ÂÅÅå•mt]ù€¿r¯’¢¢"@£FШQ#­ì+Óx©þu„6$ rss_«½\.W©cCÆW"‘(÷¡±°°@×®]ѵk×ùóx<äææbÆŒزe °hÑ"¸¸¸€ÇãÕêÇÊ/v`bb‚ÔÔTŒ7‰‰‰ÔHAÄ{ˆN› ûb4öìKEEERRS1î‹Qص{2ž±{Ç6$oÛGlÞ²Måúß®]ÃÊåK±w:´÷ÄêõÔߤüsÓxúèá7ÖšÒH=x7ÒÒ°bélOÜ™\Ž­;vêdC%×®_GÜúµHˆ‰ÆÓÌ¿køïfÚmD¯^¥¼yÖfÃÒ+èC{÷`õ÷ËñÇŸ÷«³-K­7jâQ[Œ˜hŽM ˜¤W=ê¸rõ*¾[¼Sv£wÏž˜=ï\þå,[´ûw'¡sÇX­5_kkkôèÖGŽWIÿȱãèÓÓ ÖVVŒtÈ6–l|¦)½°‰pòÔi\¸t pþâ%œ<}a'ÔH‡ ÷ €ìHJV¹yÚ‘” ß!ƒaiiivM›fv&ïANn6Ål@Üúu¸~ã똱ÕÝhªÃÚlJÚ“‚¿33‘˜ukðëo×4úH_]²ÉϘm>Ó>ŒmZêhïÙi·oòòó‡²Þô½•–†O==:xФmñÐïÚâÃÆgl}£«&^‡®˜ô¯µå§­½cÚë;>£±Ã›Ñ—ÆaÆŒøä“Oð×_i|h\¹œŸÏÇÉ“'„U«V!)) 7oÞD‹-pòäI`Ò¤I(//¯u &c’››‹–-[¾± µ=\“í«¨¨x«üY\\¬\víuä/‘H`kk‹õë×£¬¬ ±±±H$8{ö,bcc€¢¢"Ë´Éårøùù!99{öìÁÒ¥K©±"‚ ˆ÷ F36DÓ&±bÍZx4mŠF â̹ó›'GG89:brèœ9w^gÃNž>)¡áîæk++„†+ÅoˆF›V­À73ƒ¥¥%Æ}1W¯©>`™:9 ®..ð÷óÅýû÷YÛ )#Ç#|R(\]]`me… ãÿ‹K—Öˆ° !ptp€£ƒ&…„àôÙsªÇ'†ÀÁÁž± &&\…(,,‚³“¦O gt¬:LüͶ,†€‰æØÄ€IzÕc ŽéáSàîæ@¿Ï† ¬¼Ó¦L†›««ò·{÷Òåë;d~8|DyÓ+—ËqøØqø ýŒ±ÙÆ’Ï4¥gjjй³£°e+6m݆M[·bîì(µk ³Ñ£!ãÞÞ³ÌÍ8wá óÙ3üvíw ìÃ8/mhÓÌÙóç<öpp°Wië˜ÆŒ­æ˜èFSÖfÓé³ç”×WúMúê’m~Æjó™öalÓR«Ývíp3-M©Sž™Î_|ùúÍ´ÛhïÙΨƒMúÐ]ú6>3¤oÞ„±Ûþµ¶ü´µwLÛa}Çg4vx3úR°àË/¿Tîõ¡î‹…B>Ÿ…B””¬X±3gÎDQQöíÛ‡ÈÈH >­Zµ‚ Äbñk™øx©'ØØØÀÌÌŒüãììŒÕ^ÎyH¥RˆÅbp8¸»»ÃËË &LÀÁƒ±víZ|ÿý÷ضm***ÔN†Èårp¹\„††bðàÁ4 BA了^8fÔHŒ7;7„psuUwwsC¾P¨³ayùB¸»¹©=–þ×_HHÜŠû äŸuG«¿™bog§ü7ŸÏ‡øŸOlÙ )Üœ\Œ ™¨r~õõcÙÚ ê?×þsvrRù¿6Ì‹ÉÉØž”k+k„M A‡ÖøÕtL³-‹!`¢961`’^õ¨Õ½½JžÚìДoýúõШaC\ºü3zö莋?]ÆG~¨´ƒ‰Yw´¥ggk‹~½{cGR2&Œÿ/ìlmÕ¦ÃF†Ž{P`·¢gضs†ù)ãfˆvM›f„puuQ[wÇŒ¥æ˜èFSÖfS¾PXÃošÐW—ló3V›Ï´c›–:Ú¶nèØ8/ÀÎŒ˜†¤=)ð0üù'fDL5êàA“>´ÅC—>…Ï é›7a,Á¶Õ”Ÿ¦öŽi;¬ïøŒÆoF_J–°°0üðÃÊ´Uár¹‰Dàr¹ ‚X,ÆÖ­[Áãñ ‰ÀápT–±bÛÔ†¦t˜|`ii‰¤¤$tîÜ™ü3zôhŒ7ûöíÓKwÆøê¥r­¯¾ú &&&àp82dš4i‚Å‹ÃÂÂ&&&*y‹ÅbtèÐŽŽŽX»v-¦NJA&‚ ˆ÷'@*oö*ÿv°·GVv66x¹æö³¬,8:8(Ï733ƒX,VÞh<®1}'GG<ËÊR»æò¢eßaÔç#0ov,--QZZŠ¡#ŒrƒPÎÎÎXºp>\]\ ŒªþËÊÎVñŸ:;µÙÐÌ£)æÏ…B_¯þ†«×"e×­Ç áoMeѦuñP÷›6ͱ…Iz†º)e“¯ïgC°}×.ôìÑûý€©a¡:ëÐÐuG[z>Âñ“§ð휯‡.:¡®»+­;î;vÄ–í;±ië6ÜýãOÌü2‚q^LÚ5mšq°·GvvŽrެìl£ÆŒ©n4Õam69:8Tó[¶QuÉ6¿WÑækêà ј› àææŠ —.Ï7CÇŸbGr2~¾rEù5®0ѵ&}h‹‡¶x«‹ŸéâC´í¯j,¡m¬ k{Ç´6æøì};¼Ž¾”08qâ„ÊW\.<?ÿü3-Z„ `êÔ©X»v-ÌÍÍ!—ËÕN–èÒîp¹\˜››+'Í>|ˆŒŒ dff"//EEEP(àñx°µµ…££#4h¸¸¸ ¢¢¥¥¥5P?|øýû÷k–k"Œ‡ÃA×®]•{—T¥rãyÈÌÌDzz:rrr›› ©T ™L ØÚÚÂÉÉ uëÖEãÆaõÏÞ†åååÉdÑXå—RDii)„B!F…nݺaöìÙJ¥*ËÒ5kÖLã²YAA¼[lAÏÞ=½°ac<òòó‘—Ÿ qñèååUå¦Ì)©û!‰ƒ5ë£5¦7 __¬CVv6J^¼@l|‚ò˜H$‚……rrs±j]´^¶ÛØØàÉÓ§¬®ñèUëÖãÉÓ§É+Î IDATdx”‘EË–ëeGl|ò…Bä …ˆO@Ÿ^=õ²añòïðøÉå€Ãå0:V]ü­©,Ú´ .ê~Ó¦9CkØXhË·}»¶(++ÃÁÃÜ\¦MuÖ¡¡ëަôD"–­X‰Y3#Ñ­KgL†…K—©}“– '‡ƒ À¤ìKEP`€Ê²"†n×j+OlÂ&… ›°É¨1cªMuX›M½{z©\¯³ŽûE~¯¢Í×Ô‡ªÿøÔÓ±ñ›Ð·W/@Ÿž=±>&Ÿ¶×oÿ&ºÖ¤mñÐouñaë3¶¾ÑE¯k,Áv¬À´½cÚs|ö¾Ž^G_JŽ^½zA*•‚Ï磸¸sæÌÁƱxñbÜ¿GźuëP·n]˜™™é´¤•™™lll`cc±XŒ 22sçÎEJJ ’’’0þ|L›6 IIIxöìêÕ«‡Þ½{côèÑ;v,Ñ­[78::â?þÀÚµk…íÛ·#..‘‘‘(((€ ૯¾ÂçŸN~Ï)//WN”™ššÂÆÆ?ýô¦L™‚={ö >>Ó¦MÃÆñ÷ßÃÁÁ=zô@ÿþýáíínݺ¡^½z(..Æ©S§0þ|̘1qqq8tèÖ­[‡ððpÄÄÄàÁƒJ[XX€Ë岞‘ÉdàóùpuuÅ‘#G0xð`Ì™3sæÌÁÕ«W•“r¹&L@XX™ ‚ ÞL •PP`â·`Rø4€Wî ôW˜†•k×#9e/ìlm8|~¾ò¿ZÓó÷ó…H$—3£ ‰0rD òØôiS—° —.ƒ½üý|qéòemá?á_FâEiiÍKkcè`p9|³h1²³sP¯n]Œ=R/¶mÓ§L…\&CO¯ø<À_/ºtê„o-ANn.Ô¯Y3"«Ž.þÖTmZPu¿iÓœ¡5l,˜äëûÙ¬^¥ è¥CC×Mé­Ýƒ¡ƒ}ЪeK@çŽðìÙ3¬ßƒÈˆi*é°Ñ£1âÄårQ×Ýýûö1j»V[y6lŒÇøÐI015Åg>ƒpãæ-£ÅŒ©n4Õam6 fc<‚CÃ`bj ß¡øýú £é’m~¯¢Í×Ô‡ªÿøÔ³¶lß^^=^>„óê¸M›Ñ¾~û0ѵ&}h‹‡¶x«‹[Ÿ±õ.šx]c ¶c¦íÓvؘã³÷uìð:úRÂ0ĪU«ššŠÐÐPLž<r¹\ùö½ºeˆ zcÈá ¢¢R©½{÷Æ`ii©²tñ~ÁãñpéÒ%$&&b×®]FY¸º(—Æâóù8þ<.\333,[¶ :t€@ PYvŽ)•õgÆ °µµÅ÷ßÈÈHŒ1‚‚MAï •{æš’+‚x_Q(8zü²sr•oŠ¿bã0|¤R)bЕ6%âmïâ]!55ÞÞÞpuue=ùQùÕÅýû÷ñå—_â“O> š4i‚ùóçã»ï¾Sî¡Àår•û{{?…B‡333\¿~Ä;wðé§Ÿ¢[·n(..6úpâÍ€Ãá@ `Ö¬Y6lRSSušpÐEƒ”_BÉårxyy¡_¿~^îM³mÛ6ðù|\¿~Íš5ÃôéÓQ^^©Tʨ\0mÚ4äææ¢  7nÜ@›6m(ðAñŽB A¼·ôèWÌ›õZoè]\\65R™ ]:uĸѣ(8A¼“íA¼ äääàÂ… (((@ãÆ?ÈÎÎÆ¹sçpæÌ899!!!ÖÖÖ(..V>ü-//íe,--E¿~ýàçç‡øøxÌ›7hÚ´)£ÍÄÛ‹™™Ξ=‹ãÇcÓ¦M())y%“µQQQ‘HpwwÇðáÃajjбcÇââÅ‹=z4<<<ЧOxzzB.—k]¾M&“¡¼¼^^^øàƒ°nÝ:š!‚ ˆwZ‹ ‚ ‚ ‚!+W®Dhh(FŒK—.iÝçC.—ƒËåÂÇÇ:tÀœ9s ‰ŒþE‡!155Å™3gð¿ÿý“'O¦e±ÞaæÍ›‡o¾ùuêÔy«ôùâÅ |üñÇ8|ø0Z·n §õºÂÂB"-- ÖÖÖèÖ­ € ‚ Þ!*—Àâ*Á¾ÞƒÞ¸BVµI“}o¢ío»ï ‚ ‚ â]#22}ûö…D"ŸÏ¯õ< ˆD"Œ9«W¯ÆÍ›7±{÷nÌœ9åååoÕäðòù^½zaòäɈ‰‰Arr²Æòofffxüø1Ö¬YƒÅ‹ÃÖÖö­Ó§@ ÀãÇáêêŠþŸ½;³±|8þyÎ>ûŒ1Æ(»D$kEYŠ/KMeßY •²ekùVÈε¢¯„$Q‘T4I‹Ù™fŸsæìÏïšó3–™3›×ûõò23çYï羟sÎ}=÷}ýîÝ»³iÓ&=ÓÈ]Én·£( =ôGޑР„BÜ¢4·Ú I0@!„BQZ¶lIåÊ•q¹\„……åšjÇÏÏ»ÝÎ{ï½Çüùóyûí·Y½z5/¼ðwÝuŠ¢ä;5Oiæv»ñõõeòäÉÔ­[—3f••U¤ðâߥ( ‡ƒ·Þz‹¯¿þšéÓ§c2™J,@§ªªgÛŠ¢xrÜ\ (ʾN'!!!têÔ‰-[¶ ÑhxõÕW™:u*‡" À“_þeµZq8üç?ÿaÊ”)R)„Bˆ[P¡>­¶‰ìÈÎm[Šõ@Šk›Å}\B!„B±jÕ*Ú´iãÉ1ó”|zz:íÛ·§N:¼ñÆÀß±‹¥Øö¯(J®n·‡ÃËåÂétâr¹®ê`Öjµèt:´Z-z½­VëYæòe "++‹|G}”!C†P¯^=:wî\¢ç¢xåãŽ;ÆŠ+X¹r%X­ÖBç‰Ê häUl6V«·Ûªªh4O]ÌÎÎ&)) §ÓéY?$$Ä3ZÃápx¦YËIÈn41¨ªêÙæõ¸Ýniݺ5­[·Æßߟ½{÷rçw²téRjÕªEHHZ­–ÌÌLBBBÆ`0T!„â"ë!„B!D²³³ùâ‹/xüñÇq:FvìØA³fÍxê©§èÒ¥ ëׯG¯×çêÔ-¬œÎd___t:ÇŽã·ß~cïÞ½üöÛo$$$`³Ù(W®~~~LPP¾¾¾8ÒÓÓÉÈÈ %%³ÙLbb"aaa4hЀæÍ›S¯^=jÔ¨Åb)ÐÔ\Š¢ÍìÙ³q¹\ 4ˆ‘#Gr÷ÝwK’ôRN«Õò믿2}útÖ¬YüyóòÍcs-9õS¯×søða~øá>ÿüsŽ;†N§£råÊ4nܘððpêÔ©ã Ú¹ÝnOÏ`0x¶—••EVV–çµZ-.\ >>ž¸¸8Ž?Nzz:U«V%**Š-Zp×]w‘••…ÝnϳîfeeÑ A<ˆÙlæÌ™3ôïßNÇ‚ <•áÇóí·ßÒ¦M©(B!Ä-¤ÀIЯœb*gÄE›ÈŽúø¸\.mÙ’¡Ñ=ùUUeMì:>Ûñf³™‡š>Èð¡C0™L×ÝÞ•ûºüoq?bñûË8}æ !ÁÁôêÑÈví¼Ú—ÓédAÌvý :­–.OF³l¹Œ|B!„¢„|ñÅ´jÕŠŒŒ üüüxæ™g˜ù„š5kÒµkWÏè%ohµZ‚‚‚øñÇ™;w.åË—çŽ;î >>ž4h+Б32)§ž^^/½©S€gz¬œ€HÎôU‡âàÁƒØív*W®Ì¯¿þŠÑhä•W^áŽ;î 33Ó“ßãš Š‚.—‹qãÆñÔSOQ¹reEaÚ´i¼÷Þ{Ra„Bˆ[@Nô@àúü5}¡Ñƒ â£ÿÇŸâ˜ýîÛDÎsƒ£©]«N‡ƒå«Vc·;ýüˆënórs,¤jåÊtêÉÅK—0x(±¬Â×LJÍ[¶rêôF<7¤Ð† êóòèQ¼=su﹇¾½z°á›øþÇ3r$~þ~Ì_´˜à  † X òÉù[×Þ}1t0Þ?©ii¬^³–1Ïôj_«>\ï¿ÿÎË£G¡ª*ÿ}w&?ÿò‹@„B!„(!cÇŽåå—_Æd21mÚ4Þ~ûm²³³ µ-Fƒ^¯'%%…óçÏsâÄ bccIII!22’‡zˆªU«b6›oXÂtFC`` )))|øá‡Áét2~üx233½Ø Μ9÷ß~˲eËxì±ÇèÔ©dddüë×W¯×ãïïÏ™3gذa?üð;w¦U«VT¬X‘l6[žuvðàÁLœ8EQ8|ø0ªªòÈ#HåB!nr9bM‚þüða”Çd2Ñõ©'‰÷¼3õëÕÃh0àççdzýúòãÁƒ^o»qÆ:|€/w…Þ`à«o¾àÐá_iܨa‘Ž}Øàhʆ†R64”碣ٹk·çµ­Û·3ò¹¡”/N€¿?ƒ`Ï·ûŠð!TCrr iié” ó?¼Ù×Î]»=ÇV¶,Ç–Ú,„B!D Ù·o­Zµàå—_¦{÷î… ~äLkuðàAî½÷^ºuë†^¯çî»ïfÒ¤IÌž=›víÚáïïÏÅ‹±X,7¬sÙív“––†F£¡OŸ>¼÷Þ{Ü{ï½¼üò˼öÚk^':OOOgòäÉDFFÒ¦MÒÒÒ¤ý‹´Z-±±±¬Y³†Ñ£GóüóÏ“••åuðC«ÕòÄO°zõjxàæÏŸOÇŽQUÕëB%ÍápššŠ¿¿?Ï<ó , ]»vеkW:vìHFFÆuëpzz: .¤gÏž(ŠBÓ¦MùöÛo¥ò!„·bÍR&$Äó³ÑhÄf·{~?zìK–­ þøq2ÿ™ÛS£ñ>þÒà¾û˜·pðwäåQ/°fÝz"Ûµã#GxiÔóE:öˆòå=?Wˆ(Ï¥ädÏïI‰Iôr՘š:q"¬]˪5kð`ØhîoÜØ«}]JN¾âX#¤ !„BQBvìØÁ„ HHH }ûöÔ«WÏë<~~~Øív† BHHáááÔ­[—O?ýUU=Û)Êw‹’b±X˜>&""Êóõž=¸¿ «×®eßþýTˆˆ¸n>o]HH r¥JžŸË††z^+W®oN›Bùðp¯¶e0°ÙlFRRSs½~WêL™8UUùáǼ;k6ë?\íվʆ†æ:Öó¤ !„BQBî¾ûn’’’2d[·nÅjµæ¹¼Ñh$++‹-[¶Gzz:C‡%""‚ÌÌLTUÅ~Ùƒb¥™ÓéÄÏÏnݺ‘••Å“O>I¯^½xì±Çò“MÓ¦M‰ŒŒd̘1ÒµkW‚‚‚$REA§Ó±yóf~úé'†JÍš5±Z­^ìr’‚s§Óɉ“'™þÖ¯»­»jÔ`ýƱZ­$$$òÞÜÜçúúßæÔéÓž’ŠFñz_¶j™ëXÄÄ\µÿ+“Ê !„B! nõêÕ<ôÐC,Z´ˆO>ù$Ïà‡ªªX­Vžþyž~úi~øa¢££=z4~~~¥"_Ba9ŒF#'NÄf³Ñ¹sç<“L_.55• &0qâDfÏžÍÞ½{q:¥rÔËÍHQœN'—.]¢E‹ 4ˆ7ß|“J•*嬻œÙl¦fÍštéÒ…qãÆ‘––vKåoÉÎÎÆd21iÒ$úôéÃúõëiÛ¶­'âv»¹ë®»X°`ÁÁÁT¯^·Û-L!„¸jH®]9úE²Ìf¯“oyáy-YÊ´7ߢLH]Ÿz’=—Í­éÍ6›4jÈòU«y¤e iÙ‚EKß§qÆE.ˆõë3dÄó¸œNZµlAÏn]=¯Euî„FQxmúë$$$rçwпoïënkÔˆa̘=—µë?"$8˜î]žfßþï=¯7{ðA&OƒÄ¤$*U¬È«/½èõ¾zuïÆ‚Å1 : ­NG×'£ø)îg©ÉB!„B#‡ÃÁ¶mÛHJJ¢S§N×Èd2ñý÷ßóúë¯Ó»wo¢££1™LX,–[®LTU¥víÚ¼ùæ›L˜0'žx‚GyÄ«é•ÒÓÓyûí·IKK#66–Ÿ~ú‰+Vœœ,Í… ( aaaL˜0—ËEtt4(pÞ•²eËòôÓOÓ¡C>ÿüs222nù²³ÙltëÖ¨¨(,X@@@/¼ðÙÙÙlß¾òÊ+¯päÈî¹ç©lB!ÄÍþ¹Iý籎””) !„B!ÄmOUU.]º„V«%&&†ñãÇ_ÐP…ääd¦NJ… 8p YYY·ÔSóy•Ñh$66–ÔÔTæÎKêÓþæÅ`0žžÎ¢E‹¸xñ"]ºt¡Aƒdý“+R\Ÿ¿¿?§OŸfÁ‚T¬X‘:P»ví|§$»’^¯çóÏ?góæÍôîÝ›råÊÝu÷Zå°wï^~ùåfÍšEff&Geß¾}œ?žiÓ¦I¥B!nReÊ”ùûs»@„B!„"·W^y…¿þú‹•+W¢Ñäž9X«ÕràÀæÌ™Ã¬Y³HOO¿-ËHUU ?þ8›6m¢R¥JÎÈÇÌÔ©SY¼x1ƒråÊ¡×ë=Ûº;æs¦Ë©{‰‰‰¨ªÊÈ‘#éÛ·/ ðä”)(—ËEll,.—‹¶mÛz ýV®ÇYYY¼þúë¬[·ƒÁÀ[o½Evv6}ûö¥ZµjrCB!nBB!„BˆkPU•É“'Ó£GªU«–«“Ù××—V­Zñúë¯{¾TÝîEaùòåÔªU‹>}ú8É{N—ËÅüÁرc ã±Ç£nݺT­Z•€€œN'N§—ËuË%R×h4èõzŒF#ÙÙÙœ8q‚£G²cÇ~ýõWFM‡P­V[è Ãá ]»v¬[·î–œ¦­¨õxæÌ™,[¶Œ””–-[Fxx8]ºt‘œ5B!ÄMH B!„Bq ³gÏf×®]¬_¿>×ß=ÊŒ3;v,:î¶™p=:Ž~ø={ö°bÅŠB¿Ôh4FEáÌ™3üú믜>}Úó%6 €¬¬,RRRHLL$))‰K—.a±X0èt: Æßß???|}}ñññÁ`0`2™0 ôz=F£ñº×Òd2áç燿¿?þþþÆ«F]‹ÍfÃjµb6›IMM%99™ .páÂN:ÅÅ‹±Ùl„‡‡s×]wQµjUL& Øl6î¼óNj×®MõêÕQ›ÍVè ªª”-[–Htt´'ùwi¡ª*z½­V €ÛíÆétâv»oèqž={–7²páB6mÚÄÒ¥KÙ¼y³4p!„â&$!„B!„¸†îÝ»³dÉ ðÿS^½ÿþûLŸ>ý¶ò*?ªª¢Óé4hï¼ó7Æjµ˶s:ÁEA¯×£×ëÑétž.— ³ÙLvv6ÙÙÙ˜Ífl6v»›Í†ÃáÈõ/g$ ü=*ârZ­Ö³¿ììl, ‹…¬¬,ìv»gʵ’·ç”ÉdòO‚ƒƒ $00   Ê–-K™2eÀn·cµZq8¨ªZ¬5­VËùóçyõÕW:t(¥fôŒF£A£ÑpêÔ)‰'!!·ÛMpp0UªT!""‚êÕ«ãããsÕu*©:|üøq~úé'¦NJ—.]˜0aµk×–.„BÜd$"„B!„Wøý÷ßyÿý÷yóÍ7QUEQøì³ÏHOO§Y³f×ìôWÛ¹s'¿ÿþ;3gΔ‘2ÿEQøâ‹/Ø»w/ƒ.ðÔd%}l?þø##FŒàÕW_%22›Íæ©+Š¢ ÓéHIIá™gž¡gÏžôë×ï†_rr2Š¢NTTqqq2 –Bq“É €h¤(„B!„âoC‡eܸq¨ªŠ¿¿?£GàGµmÛ–^½z1lØ0Ο?ï™nJ”>> 4¨Ô?ŒF#`úôé˜L&vïÞMëÖ­=ùH´Z-:EQ°ÛíøûûóÉ'ŸÐªU+æÌ™Ãþýû=#³JRÙ²e‰‰‰Án·Ó±cG ~!„71"„B!„ÿ˜3g#GŽÄår1räHžxâ *W®\âûÍ™ÖIUUÏK—? Ÿ“ü:gº'‡ÃQêç‘fΜI@@€'°$J†Ñh$11‘¹sç¢Ñh3f ‰‰‰¥æøüüü˜?>v»gŸ}Ö“·%++‹o¾ù† .P¦LŒF#ÉÉÉh4j×®M£F°ÛíèõzV®\I™2eèÚµk‰$ÃÂÂ9r$ ,àÿû}ûö•J&„BÜDd ,!„B!„¸Ì®]»¨S§¡¡¡<óÌ3L™2§ÓYìOç4rrJØív¶mÛÆöíÛIJJʵ +/„F£áÁ$22’:uê ( &“ Ünw© 0¨ªJhh(‘‘‘ÄÆÆî öˆ¢Ójµ¤¥¥C\\3gÎ$;;»T£¢(Lœ8‘öíÛS·n]´Z-6›… Ä;#V«õ$>Ï’’’Â#<Â[o½ÅwÞ‰ªªlÚ´‰V­ZQ±bÅ?nNGß¾}ñ÷÷gûöíRÙ„Bˆ›ˆ@„B!„â2wß}7/^¤]»v¼öÚkh4Å;c°Á`Àjµ²dÉ6lØ@«V­èܹ3<ðZ­½^V«õ$‡¾œªª¸ÝnÜn7N§‡ÃAZZÛ·ogÇŽœ8q‚лwoœN'6›­Ô•oNÐçµ×^£}ûöŒ;–ääd „²,CBBØ¿?C‡¥G´jÕ “ÉTêFiµZ¶lÙBÙ²e©]»6Š¢0gÎ}ôQ{ì1L&Sž£9E!))‰¨¨(–/_ŽÁ``úôéLœ8±Ä§ÃR…£Gz’°·k×N*ŸBq“ˆB!„BücçÎÜÿý 6ŒaÆR,#?´Z-þþþL™2…äädêÖ­KãÆéܹ3f³›Í†Ëå*ð¾r´ëõzŒF#n·› 6pìØ1þüóOL&ãÇG§Ó‘]jr¨ªJPmz=ò IDATPûöí#>>ž¿þú‹ÁƒÓ¬Y3²³³±Z­’oá &“ ›ÍÆòåËùî»ï¨S§6›~ýú‘••U*§DSU•””–.]ÊÈ‘#1¼òÊ+Lœ8‘:uê(7I@@Ï<ó ÑÑÑhµZöîÝKTTT‰Ÿ·N§ãµ×^ÃÏÏE‹IeB!nB!„Bˆ¼óÎ;ìØ±ƒyóæýýE©ˆð:Ž´´4vîÜÉÒ¥KÙ¸q#÷Ýw©©©%~.œ8q‚¾}ûRµjU DÅŠq:¥j´…¢(øùù±uëVbbbèܹ3O=õz½ž°°0‚ƒƒq»Ýž|(·êH‘œº–3úGQ233IKKó6¶mÛÆ¦M›¨V­#FŒ J•*dff–xŒ¢2 ÌŸ?Ÿ^½z¡ÑhX´h³fÍ*ô¥råÊÑ£G^xázôèÁ—_~Ifff‰ŸG@@7æÔ©Sèt:¹a !„7 €!„B!Ä?î¾ûn¶mÛV,O“FV¯^Í'Ÿ|ÂîÝ»K$ˆ· ±±±¼øâ‹lÛ¶ÐÐÐRÛiîr¹ðõõåÈ‘#¼ýöÛüõ×_<üðÃôïߟJ•*NHHˆ'(’3%XAÎ''Àpù?àš¿ç¸VàåÊ€L^Á™Ë·™³‡ÃAVV‹…””’““Ù½{7ßÿ=¿þú+tîÜ™¨¨(t:‡­V{Óµ«   ºuëÆŒ3ˆ‹‹Ãn·Ó»wï"msß¾}¨ªÊÆ‰ŽŽ&88ø†œË©S§Xµj«W¯–¦BqˆB!„B/½ô½zõÂ××·HÛÑjµ˜ÍfFŸqãhÑ¢‹å_?¿œŽó5kÖ°lÙ2–/_Ž^¯/µœ©½4 N§“'NpöìYÒÒÒ°Ùløùù„Íf#%%—Ëå \Y,–\ ãs®iN^EQ0 øøø€ËåòäLÉùùÊdò9ëå›F£ñŒÖ¸ûì3,K©~žNôîݻӧOºuëFãÆéÙ³g© ‚¨ªš+7DÅŠ©X±"@® CNâø+9?_>J#ççË“ÉçL­u½c¸–¢ŽäÉoÔHiL^_þù'Ï>û,Z­–~ýú‘––Vä2´X,,Y²„ýû÷ßБUV«•;ôôt‚‚‚äÆ)„BÜ$4RB!„BˆÛ•ÃáÀ××·ÈÁŠ!C†ªU«JUÒñËåV¯^ÍàÁƒ‰ŒŒD£¹¹¾^Àp8X,²²²ÈÌÌ$33“ŒŒ ÒÓÓIOO'##Ãó÷¬¬,Ìf3‹«ÕŠÝn¿j­Ëÿ]0¹Vð¤°ÿ.ßÖí ;;›ÐÐP6oÞL•*UŠ¥]¸Ýnj×®ÍÁƒ©^½ú ;EQ¨S§O?ý´Ü8…Bˆ›ˆ@JX›ÈŽ×ü¹4§2-­~ÿãýFKÙ ¹_”¢÷¯â>ö’.‹¢n_î?BÜz¦M›F‹- ½¾V«¥[·nLš4é¦ê5™Lìß¿Ÿ÷Þ{¯¿þ“É$•A;’““ùè£ðóó+¶íªªêÉ•r#ét:Ú·o_jFw !„"¥*RØN…ÒÖ!#¥“\—›ÿºÅ,[Æ gû³sÛ)ir¿ó–òB™Ëåâûï¿ÇÇǧPëûûû3eÊæÏŸÏ½÷Þ{ÓåkÐh4̘1ƒ‹/2sæL¤RˆbU¿~}víÚEJJJ±6ÊA}ÃN§“¶mÛòÇÈÅB!n–ϼEYyý†´íØ™õ6K'Áåšm";2`ÈsW VU•g͵~ië -í³·kMI^—’(SéH»úºýuâ$4i,å)í±ÄÛÕíz¿àâ+¿â¸ff³™¥+VÒo`4žx’¨®Ý™4u:q?ʵŸ6‘ùO‡Nt~º+ƒ‡déòW% •{¤¸]ÅÇdzdÉ’\ù&¼þ"¥Ñ0~üxzõêE:up:7Ýù+Š‚Õjå¹çž£Y³f 2䦛K”n]ºtaçÎÔ¯_‡ÃQ,Û4,]º”¶mÛþ+AG£ÑH\\œ\\!„â&QèO·ªª²yÛ6ž‹ħÛ>+‘9LF#ûø1×ßöíÿ^†g q›²X,èõz)!„¦½õ_222xcêd>Ù°žKÓú‘–¬^»6×r;·má‹­Ÿ²þƒU¼4êylv;ÑÃG˜(…(n{[¶l)ôäñññÔ¨Qƒ¦M›Þôå ( íÛ·gìØ± 8ƒÁ •C‹äädZ·nÍ«¯¾Jb1½ïèõz>þøãBÜ*Û·o/¶€ŽB!J–®°+þðãüýy¢s'¾Øµ‹Ìõdv›ÈŽ&L˜ÀäÉ“yã7ÈÊʺ-êF£‘Ó§O³sçNŽ=ŠÓéÄív£ÑhÐh4„……ñðÃÓ¬Y3ìv;ÙÙÙ¸ÝniDùp¹\<þøãtëÖ—^z‰Š+©ÜTUeñâŬ[·î_-ÿ™3g²téR†*Y!„(å =dóÖ­<þÏ—…Î:°yËÕ&dÆßäãØ5Ü߸³æÎÏõEç¶-yv´´xø!ÒÒÒøíŸù5ýr˜ŒŒ š?ÔìºëÄ~´Ã¿ýÆ»o½ÁêåïséÒ¥\¯:ü+ófÍä‹­Ÿðaì:Nž>Í‚9ï±`Î{üuâ$kÖ­¿æ¶7jÈá_àâ¥KÌ[¸Kv6¿>L“FJìB½ùî zuïÊ'­cÖ;ÿå#z^Û¸é~>|˜wß|ƒUË–ât¹X±úƒkn'¯²¿Þõ*è>rìÿñGÞ~}:›ÖÇòh«VŒ›ôß~÷oMŸÊDZkhúÀýÌš7ϳüÔ7ÞäñNˆ]½’µ+—S64”÷—¯ÌµÍƒqq,š;›% æqæÜÙ«®U~¯{{¾¬]GbÒE–.˜Ï¢¹sˆûùçën§°eš×ùzÓFzuëÆê5ks}^½f-O>Þ??¿Õí¢ÖÁüÊ>¿ú“_»½V™äwþÞ\£‚–Q^ep½ë@‹‡bëgÛsmkëgÛiݪ%þþn_Þ´•Ûµ=æuòjWW¾7Üj÷‹’~ÿ*JûÏK~m4¿zºfÝzΞ;Ç’óX0ç=~8p0×öó;¶üÖÏOA?ôžt_½zÌœ3_ÿ[;`#۷㧸Ÿå“°¸­½ÿþû 4¨Àëét:>ÿüsbcc±Ùl%ó%M£Á××»ÝÎÅ‹9uêñññüùçŸüùçŸ=z”'Npþüy2331 èõú"DœN'Mš4¡AƒÌ™3ç–žK¯×“™™É/¿ü Aƒ¨W¯;wfãÆœŽ;Æ’e+ˆ?~œÌ†Û_ùdOîkUþªk•ßëÞžorJ åˇ_s»ÅU¦Þœo~zuïÆ’e+hÕ¢+?ønO?å)ë‚Ôí¢ÖÁüÊ>¿ú“_»-Ìù{£ e”Wäu=+V¼“*•+³çÛ}´jÑœoö~Ë=µk{îGm_…©;·S{̯®zóÞp«Ý/Júý«(í¿(m4¿r¹”œ|Õú—ËïØò[¿(×´8îI¾¾¾<Ó§7Ïô骪œ:}†õ7òÆ;ïòúä×òÜWJj*×™6OˆÛ…Ùl.ðOŠ¢°lÙ2>“É„ŸŸv»ÌÌL|}} #((­V‹Íf#55•óçÏãv»ñõõeëÖ­lذÀÀ@êÖ­Ë;ï¼Chh(V«µÀß TUeäÈ‘´mÛ–E‹Ý29ÃÂÂ;v,{öì¡\¹r4nÜ·Ûí tÄÇÇséÒ%j×®M5Æf³qîÜ9âââ°ÛíÔ®]œN'5jÔÀår1`ÀÊ–-ËâÅ‹=å'®]×ÇO¿~ýX³f ‹Å«º©ÑhHJJbæÌ™ü÷¿ÿ%%%¥@uZUUŒF#>>>˜L&4 n·«ÕJvvv¡¦±S…|çž{Ž ÈÅB!J±@ìv;Ÿïü’–¿OùðÿïðIHHdبÑ<Ó»—WIó¼ýÀ¢×ëy²s'þ;c&ýûöÉwˆqXÙ²œ¿pÁ3oz~û -S† Tþçé¯ó.P64ôšëúø˜ˆˆ(Ï×{ö`4xàþ&¬^»–}û÷{ž¬.,ƒÁ€ÍfótL¦\ñ´Õ]5ª3eâTUå‡ðî¬Ù¬ÿp5åÊ•ãÍiSr]â(ûËt…1ý­·éÓ³“ƽ‚ŸŸf³™¨n=r-sùµºpÕµÊïuo…–)CBB¢'Â…„„b/ÓüÎ×›m6}à–¯ú€¥+VòûGxyô(¯ëv~uîJyÕÁüÊ>¿ú“_»-Ìù{s Òþó+ƒü®ç“O<Ϊ?¤U‹æ|üÉfž6´ÐíË›¶r;·Ç¼®ÓõÚUQžà½î%ùþUÔöŸ_ÙæÕFó+—²¡¡W¬ŸP ÷¶üÖ/j'PQïIWn¯JåJ<78šž}ŸÉwùmÛ?§QýúòIXܶ¶oßν÷Þ[àõÊ”)CRRR±tp+Š‚N§cåʕ̘1­V‹^¯'44”J•*Q£F """p»Ý¸\.\.ªªzòRèõzìv;gΜ!>>ž³gÏ’––F\\õêÕ#**Š—^z‰Ê•+xº.—ËÅÆyûí·yá…Jlº¯A£ÑœœL—.]0™LT«VÍS–/^$<<œF1jÔ(4hü—Éår¡( z½£ÑÈ©S§Ø·oûöí#..???‚ƒƒ¹ãŽ;xøá‡™>}:íÛ·'ûŸ©&EnÌš5‹!C†Ð¡CÚ·oF£¹*¡Ñhðññáܹs¬_¿ž„„ÆOfF/FÒÒÒØ³gß}÷ÇŽ#11«ÕŠÑh$<<œÚµkÓ²eKZ¶lYàœ"åË——ë,„BÜ Ÿ ºÂ¡öÝw_ÕYP¾|8wßu_}³Çë>§ÏœñjÙî]»ðù§ŸÐ½ËÓù.Ûî?m˜»pÈÌÊbaÌ’<—´UKæ/Žáâ¥K\¼t‰ù‹bx¤eËë.ߤQ#Æ,¥Í#кU+æ.XD“ÆE›?ý®5X¿ñc¬V+ ‰¼7w^®×_ÿïÛœ:}Ú3…Ž¢ùÿŽ“N"™9g.§ÏœÁétrâäI¦¿õßb)ûÂî£0¬V+¾¾¾˜L&“’˜9gÞUË,ŒYÂ¥äd.%'³0f ­iU ×½õh«–,\²”ää’“SX¸di±ÕgoÏ×›m*ŠB¯îÝX¿a#½ºwË5œ<¿º_»R^u0¿²Ï¯þ´ÝzsþÞ\£‚¶ÿ¼Ê ¿ëÙ¸a, ›>Ý‚Ï߉ˆ Û¾¼i+·s{Ìë:¦­Þ*÷‹’zÿ*jû/Ê{t~åòh«–¹ŽmALLÞÛò[¿¨@E½'û _ïÙCjZN§“„„D–._AÝ:u®¹¼Íf#þøq,Žá³;è×§—×Ç›“°]ˆ[ÅÌ™3¹ï¾û ¼Þ7ß|Ã}÷݇Óé,ÒþEáüùóT®\™¹sçb0p8Ü{l9’¨¨(6lH`` f³Ùó”ºËåÂívãt:±Ûí˜ÍfåË—çᇦgÏžŒ=“ÉDhh(ß}÷Íš5ãwÞ)ÔqúûûsòäIŽ=zÓ^kEQ8yò$‘‘‘T¨PœN':Ž“'O²iÓ&,X@¿~ý¨Zµ*iii¤¥¥a6›=#222¸xñ"¾¾¾´iÓ†I“&ñùçŸóÁ`µZ=Á”† 2cÆ ÆWìÓ£ý[e—ó/'è§ÑhŠtnŠ¢`±Xxå•W¨U«÷Þ{/3gÎ$33“ÔÔTRRRHKKãÈ‘#4iÒ„wß}—^½z] à‡ÍfcêÔ©´iÓ†7rîÜ9|||¨R¥ µjÕ¢jÕªøúúrúôi–-[ƃ>HZZZÎÅl6Ó·o_’‹0Ê^!„%¯À#@>Ù²•g®ó…¹S‡H>X»–¶mZç»]»0rô‹d™Íy&B/¨®O=‰Õjeô˯`µZéÝ£{žË÷êÞ˜eËynä ´lÑœ^Ý»æÑÔå«VóÈeùO-}ŸÆ ‹6ú¨Ø1{.k×DHp0Ý»<;ýß{^oöàƒLžþ‰IITªX‘W_zÑóZTçNh…צ¿NBB"wÞqýûö.Ö²/è> cÌ Ï³hÉR¦½ùeBBèúÔ“ìùöÛ\Ë4¨_Ÿ!#žÇåtÒªe zvëZ ×½Õ«{7æ/ŽaàÐçÐêt<Ñ©#?ú¥XË4¿óõv›†;*T¸ªÝåW·ó«sWÊ«æWöùÕŸ‚¶[oÎß›kTÐöŸWxSŸ|âqf͙ǛӦ©}y³¯Û¹=æuJâ½çf¹_”ÔûWQÛQÞ£ó+—^Ý»±`q ƒ†C«ÓÑõɨ\‰¿ó;¶üÖ/Šâ¸'õéÙƒO>ÝÂ{sçc³Û)S&„7áÕ—ÆäZ®MdGEÁd2R!"‚Æ ²xƒ¯ZîJÅùMˆÒ"##ƒaÆa±X ¼îâÅ‹™7¯høûû3}útV®\IDDçÏŸ'22’Zµj¡Õj±Z­W­sy‡s^£OÜn7‹…îÝ»c³Ùؽ{7™™™|øá‡ÄÆÆ²gÏžu`»Ýn>úè#zöìÉ;ï¼sSŽùí·ß=z4÷ß?ªªb08wî~ø!F£±PÓžú³téR&L˜Àùóçñññ¡jÕªÄÇÇ3uêTÞzë-¯ò2•6Z­–   ,XÀþýû=SNåL%U­Z5 @õêÕ ”¸œªªèt:vìØÕjåܹs8Ün7:£ÑHll,¦@û0™L¬[·Ž+VB:u<Û´Z­$''{ê±Éd¢\¹rFêÔ©Ã!CxôÑG5j”××-$$„Ю];¹¹ !„¥”¢þó :%%EJC”jm";æÙ“ßëEñ׉“Lš6–½_êÊe┩<Ò²%¶jYj¯Í­~þÒ¥=ÞLÇ'„·»C‡àããSàu À?ü@RRR×UUFŒÁÖ­[ ÂÇLJ:àïïïÉE¡×ëQU•sçÎqüøq233s8ÑjµF*W®L5Ðjµžé±®d0ˆgóæÍ”)S§ÓɪU«¨Q£FžâŸ={6M›6¥r§+ý·ét:Ú·oO5p»Ýž„æ“'O&((¨Xö¡ª*þþþ,Y²„­[·R¦LÏõ6l­[·.ðÔJÿFCBBK–,áÛo¿%,,Œ€€ÏyæÔ—ËÅ™3g¨Y³&>ø ýúõó:ŸG~e™h)̶‚ƒƒ?~<{öì!""UUq¹\$&&R¦Lôz=eÊ”Á`0 ª*6›Í±X,”/_ž .зo_ž~úi¯ö©Õj2d»víºfB!Ä¿''®NŠBˆk[³„n]žÆáp°pÉjÚ´TŸªªlÛþ9 ‰Iž'ºo'·ûùK{l*Ç'„¢Pú÷ïϺuë •Ç㡇*pâôz½žgŸ}–ü´Z-=zôð7233ILLdïÞ½Øl6êÖ­K³fÍ E§Óy:„N'V«•°páBÜn75¢fÍš¢Ñh<çf·Û©T©Æ #&&žzê)8€Ñhôº FŽI›6mX³fÍMsõz=7ö$:8{ö,;vì(ÖQŠ¢`6›éÝûï„[·n%88˜ *0nÜ8vìØá "”f:ޝ¿þš)S¦P³fMO°ëòàMN}Q…Š+bµZÙµk{öìaÖ¬YyNGëmY^þAh4† ™3gÇív“œœŒN§£I“&ל¶Î××___EÁjµrèÐ!*W®ÌªU«èÕ«—W#ž\.£Fb÷îÝ´h!ßI„BˆRù9GŠ@ˆk gØó£p84{ðžíÛ§Tß:t¢|x8“ƽrKÌ1,ç/næöXÚO!ÄßΟ?Ï«¯¾Zèõ+UªT¨i ôz=3fÌàçŸF§ÓQ¾|yÚ¶m‹Ûí&33“eË–Q¯^=žxâ š4i‚çÏŸçìÙ³|ýõ×$%%aµZÑétQ¥JªU«F³fÍÐjµ8p€˜˜:vìÈ}÷Ý—kj'EQ:t(111sß}÷qàÀüüü¼:~£ÑH—.]p¹\žý•v_~ù% 4@Q4'™vIMIåv»éÕ«gΜáüùó8Nš6mÊèÑ£Yºti¡n7ŠÉdbòäÉ=z”êÕ«{®³Åb!))É3z&ç<µZ-ááá˜L&TUÅívÓ»wo6mÚtÍ)ÜJšV«å³Ï>ãĉ¢( ñññ<üð誚oΞœ©½î¿ÿ~âââ cøðáÌš5Ë«Ñ;õêÕ#..Nn°B!D)%S` !„B!n K–,¡]»v…ê¤u¹\|÷ÝwtéÒ¥@S©ªÊÆ™8q"eÊ”!,,ŒN:amVšK IDAT6›‰¥I“&´hѳÙÌš5k ¤fÍš ‚ƒƒ)W®èt:Ün7ÙÙÙ$''“””„Åb!99™£GR¿~}{ì1öîÝË÷ßODDÍš5ÃápxŽÅív³xñbˆˆˆ`ûöí^h9|ø0.—‹ *{g¾¢(øûû£( /^D«Õâëë‹N§C«Õ¢Ñhp8^çm)_¾<7¦Zµj$%%1iÒ$êÕ«Wâ???š7oNõêÕ¿ƒn+V¬Àßßßë²ðññA¯×çJ>žsý¬V+v»½ØR…ýû÷³`ÁO™;vŒš5kb2™(_¾üUõ]Q°Z­ÄÇÇ{‚&¬\¹²È#A BUU²²²èÚµ++VÄívsîÜ97n\¨íY,þúë/, _|ñ…×m}Þ¼yÌ™3Gn²B!D)’3–@„B!„·…e˖ѼyóBu‚;vìØAãÆiÒ¤ ûöíãèÑ£DFFzFm¨ªJrr27nD£ÑðꫯҥK¯Ï?**Š?ü°XŸòWU•Ý»w³ÿ~êׯOÅŠq¹\˜ÍfOn“'N‘‘Á£>Jƒ ò͵°{÷nÞ{ï=*W®ŒF£ÁÇLJ÷Þ{¯Ð Ï z>gΜ᭷ÞBQYYY¬]»6Ï‘‹ÅÂÏ?ÿÌþýûÉÎÎF«Õât:Ñh4¸\.E¡FÜ{ï½Ô«W§ÓY䀎Ýnç‘G¡^½zØív233=Áƒü¶­( .—‹‚Ñh¤]»vDEEݰ|ƒ7ß|“?ÿüEQ¸páMš4)ôµÖh49r—ËÅÚµkÑëõ^­wøða6lHÕªUåF+„B”’D!„BqÛHJJâܹs…î0Öh4ùN¥s%­V˘1cÈÊÊÂårÑ¿–.]J×®]iÙ²%ãǧÿþŒ5ÊT)hŽ‘œŽÞœÀ‡ÑhdðàÁ 4ˆ¶mÛ2vìX† æI,NÕªU¹pá³gÏ&::šÔÔÔ|÷ãããÉ'ÈÎÎ.¶Ñn·›=zpêÔ)222ò\6gŸuêÔaݺuyÃW_}åÉaár¹hffl ~äg¹rå8yò$ÕªUÃd2qôèQGžÇ|âÄ ^ýu8À€®[Os‚!ÕªUcݺu^,¹ž×_ÝS>.—‹&MšxàSUFCÓ¦Mùí·ß˜5k={ö,t®œ‚2™Llذºuë’’’ÂwÜQ¤kív» ò´Yo M›6eàÀlÛ¶Mn¶B!D)£‘"B!„BÜê^{í5ú÷ï_èõµZ-6›­@ÿ—.]bË–-øøø`4Yµj£GæèÑ£ÄÅÅñî»ïR¯^½|;œ ƒW±ªªbµZ™?>z½žiÓ¦1qâDvîÜé™ ËårÑ®];ÏÔA“'Oöúœxà’““‹åzøùùÑ¿~ûí·|ƒ9禪*üñï¾ûîu;¹µZ­'ù5Àï¿ÿN‡nh] ¤B… (Š‚ÛíæÎ;ïäÂ… ×]>++‹ßÿü«ÕšgÎív£( çÏŸçàÁƒŠrkàøoʶì¦AºT)^@@á R¥WfÐ+ˆx-Xð**±" ¨XP@T:""ňÒBHïÙ¾;ïÜì5J(ðžïýð‘»;;;óÌì2ûœ9çðÛo¿…öyÅŠDDD”ÊÛív^zé¥P#ðÌÌLFŽyÚòLŸ}öwÝu×YocáX 2„œW¹©®]»RµjU222Î+°¥ª*‡æ?ÿùÏygb”D0¤K—.¤¦¦â÷ûϺGÏ_™L&öïßÏ´iÓ¨Q£ÆyoÓ /¼ÀóÏ?/_¾B!ÄeB B!„Bˆ+ÒÂ… éÚµë]g“&MX³fÍi'´EaË–-4hЀ=z\Ù…êÖ­Ë÷ßÏ–-[ÈËËÃ0 n¸á†³*¶wïÞS–r:‡ƒ§Ÿ~šîÝ»³bÅ ÒÒÒB“ù…ýS.—‹-[¶0|øp|>:t8íø[,ºtéÊŒ¸êª«èÚµëyõ9[ß~û-ÇŽ íƒËåbôèѧ-Qåt:yä‘G¸å–[øúë¯ñz½8ìv;6›-ô',, MÓØºu+}úôaàÀçr»ÝL›67ž2£æLE!++‹FQ½zõR?§ Ã`õêÕ”+WŽ#GŽ““sVÁEQp¹\>|˜§Ÿ~šúõë_>"f³ùœzˆ!„ââPŒÿ^afffÊh!„B!®3gÎdøðáç]Òæïrrrصkýúõ+6p`2™˜4i;vì`âĉ¤dÔ…¢ª*›6mâÃ?DÓ4l6sçÎ¥qãÆ§¤ÏÉÉáùçŸçÁÄëõ^Ø¥Š‚ÕjeΜ9,_¾·Û*[fMš4áµ×^ÃçóõuFF½zõ¢I“&†×ë¥oß¾tîÜù‚LrÇn·sûí·‡‚yyy4mÚ”qãÆõ:bbbèÕ«Á`J•*…²‡ 'ë7oÞÌâÅ‹±ÙlçÔ÷£8†aNÓ¦MéÒ¥K‰ËHù|> Ã`Ú´i—ôܶX,,X°€×_J•*Q³fÍb÷Å0 999T¯^§žzŠÜÜÜ ¶†aðã?2hÐ ùB!.¡råÊ¸Ž’ˆB!„âJôüóÏÓ£Gó*TEQ¸ûî»yçw¨\¹òIÏGDD0jÔ(Ö®]˳Ï>{ÁßÿBlÿܹsÙµk&“‰o¾ùæ´™Š¢°~ýú"òƒªªÅ6D/œ°. MÓX¿~=o½õQQQ0lØ0nºé¦ ºÝ†aP®\9z÷îêý ë:>Ÿ·Þz«Ä=h4M 7þ~îhšvÑ8~¿Ÿ™3gòÃ?о}{ü~ÿ)Ï]EQÐ4%K–0{ölš7o~Yd:©ªŠÏçc÷îÝlݺ•ï¿ÿž?þø‹ÅB Àd2ѹsgÚ·oÏ5×\ƒÝn¿(ã™””ÄÎ;™0a‚| !„—ˆ@„B!„W¬ß~ûP·nÝ‹²~MÓxüñÇy÷ÝwOêyP¾|yúõë‡ÛífàÀEžÓuý¬ÊM]LŠ¢°zõj¾þúk¬V+7nÄd2rùèèhºwïγÏ>[¦ÎEQxàÈÊÊ n¼^/­[·æ¾ûîÃívŸwpÊn·³víZ{ì1êÔ©zü—_~aùòå„……]V@gâp8ؾ};k×®eË–-(ŠBdd$ÑÑÑÎäææR±bEZ´hÁÀñz½ç•¢ë:Š¢`Æûl(Š‚ÉdÂjµb6›ÉÎÎF×uìv;x<ž‹˜t8ÄÇÇóå—_Ê—±Bq‰@t !„B!Ä•fàÀ,[¶ §ÓyQÖï÷û©U«óæÍ£oß¾EžSU•¼¼¼"⊢——Çž={hÖ¬º^:?Å û^üõ.wÃ0p:øý~š5k†Ùl>ídðš5k/sç€aÌ›7!C†àñx°X,˜ÍfvìØA£FøðéY³&š¦•h2\QTU%%%…x€ÔÔÔб6 ƒ½{÷²iÓ&<O™ ~äççS¯^=êիǃ>H0äøñãüúë¯Øívn¸á†ÐxýµTYIÆNÓ4222p:x<¶oßN^^åÊ•ãºë®CUU"""ˆŒŒ<ç€HaÙ³¿–kóûý%ÞÞsUPPÀرcIII¡B… ò…,„B\BÒ]!„BqEñx<üóŸÿ¼¨%yEaèСìÝ»—¼¼¼"Ïùý~TU-ÒÀl6óÊ+¯Ð¯_?¾ùæ›R«ÕÊ‹/¾Èœ9sNz.33—ËÅÂ… O;ù¯ë: ¼øâ‹eò\ÈÎÎfΜ9Ô¬Y“´´4TU% Ò¼ys^xáºuëÆçŸŽÃáe"œòÇó'æ>̈#˜8q">Ÿ/twa0dÿþý¬_¿¯×[æ‚çt:q»ÝDGGsÓM7qÝu×áóùp»ÝçܱX,9r„Î;óàƒòÅ_°uëVü~?6› —ËÅÆùä“O9r$C‡=ã1¹\†A… .xÿ!!„BœÃu»”ÀB!„B\IÒÒÒ8|ø0¥ò~£F"!!Š+¢( 6›øøx 0`@(ÀX¿~=;v,•í²Z­Ì›7EQèß¿ÿÿ~* /¼ðMš49mEQX·n»wï¦OŸ>eúœÐu5kÖðÄOP·n], Á`MÓÈÍÍ%''‡Faš¦qÕUWA àСCäææb±X8zô(™™™T®\Ã0BËÿôÓO 0€áÇ—ÙIû‹EUU\.&L |ùò4iÒUU 躎¦i¡ñ*SÃ0ÈÍÍeÇŽ”/_ž—^z‰ôôô2µß…'Íš5““@!„¸¤ˆB!„⊔œœLfff©•™²ÛíôîÝ›/¾ø›Í†¦iLš4‰õë×óä“O^²&è…ïk2™Š”R…øøx’’’N[ÈçóÑ¥K>ÿüó“úœ”E†a`µZ‰çرcDGGãp8BÏ–g ƒx½ÞPÙ0‹Å‚®ëEš±«ªŠÛí&33EQxùå—©R¥ÊEkP^VY,V­ZÅÌ™35j“ÉDZZ999üùçŸ Y,j×®M¹r刉‰áðáÃìÞ½›ùóç)iu¹S…_|‘„„9„BˆK@z€!„B!®Hûöí#22²Ô |ýõ×tìØ‘ï¾ûŸÏG½zõؾ};Á`ð’e¾ï_ƒªªòÝwßqíµ×†úƒÇn·së­·2gΜ+"øQ8‡W^y›ÍÆôéÓYºt)5kÖ$**ªHƒz]׋œ?~¿?4žN§“ýû÷SµjUÞ{ï=, €?Šñî»ï²yóf†  ^,\¸þóŸ 6ì¤òq…ÂÃÃy÷Ýwùþûï¹ãŽ;ˆŠŠ¢k×®,Y²ä‚5J/ üñ‡œB!Ä¥¾” !„B!Ä•dÔ¨QL˜0¡HŽ‹­°lϤI“˜5kQQQ4hЀwÞy粚° ãþûïçÃ?¤~ýúÅ.ÎÈ‘#3e]AA'N¤sçÎø|>6oÞL¹rå¸óÎ;1™Lg išFAAÿùÏhݺ5iiiÜvÛm4jÔ¨Lì¿¢(,\¸Q£FQ©R%9!„BˆR&%°„B!„W¤îÝ»3kÖ,‚Á`©¿·ÕjeôèÑ 2„?þ‹ÅBÿþý/›‰ò¤¤$f̘ÁÏ?ÿLxxøIÏÛl6¦L™BõêÕéÒ¥ËY­S×u¬V+¹¹¹ddd””D~~>^¯7TJª0ˆ`2™Ðu›ÍFll,qqqÄÄÄ`ç’• S‹ÅBXX^¯—œœœPÖ‡Ãá ""·ÛÓé¼$çUY ¹ñÆ™Ÿ@ Pä*Š‚ªªèºŽÉdBQ”ÐØ—öç!%%…Ñ£GãóùHNNæÚk¯å†n8§rj999<ðÀŒ9›ÍvÚ¾5—›ˆˆ’’’äKY!„¸”×Q’"„B!„¸RlÙ²…ÜÜ\jÔ¨qI·CUU²³³0`Mš4aÈ!—¼ó‘#GHHHà×_Åãñ„/lÞ¶m[fÍšEÅŠ‹0×4¨¨(}ôQ222¸ë®»hÖ¬ááá˜ÍfTU% žõd{a NôÏÈÏÏ'))‰Õ«WóÅ_ðÌ3ÏP¯^½2s·ÿý¡®(X­V"""X»v-_}õ»ví"..ŽJ•*Q§N"""°Z­hšjÐît:ÉÌÌäÀ$''“››K‹-èÚµ+M›6%;;ŸÏwQ"‹…É“'Ó AÊ•+ÇÇÌc=v^ï©( þù'sæÌá‰'žàšk®)DZ° üÈ‘#åËY!„(e’"„B!„¸âlÙ²…®]»^ò†ÔÁ`ˆˆV®\É7ÞH:u¸îºë.Yï ‡ÃÁSO=Å‚ BÁÃ0°Ûí¼ñÆ|ûí·¼üòË”/_¾ÈDµa„‡‡³fÍ~ùåjժŃ>HýúõÉÏÏ•‰*œ€/‰Â¾)pb‚;<<œúõëÓ¸qc¦NÊüùóÙ½{7?ÿü3=ô&“éŠî¹a³Ù|òÉ'ìÙ³‡fÍšá÷û‰‹‹cüøñÔ¯_Ã0ðûýx½Þ"ãW8†p"PU˜â÷ûÙµk;wîä×_ÅçóñË/¿pã7Ò©S'àDÖÒ…>žÖ­[óâ‹/âr¹Š¼NÓ43f /½ôƒ •0ÊÉÉŠ–fRU5ôÇëõâv»ñûýTUEÓ4Ìf36› 8$*ìR¨°ˆÇã¡[·n¡× <˜æÍ›Ó¢E *T¨pÅôáÐ4ÜÜ\ÒÓÓ™7o@€—^z‰råÊát:C& Ôœýlι¿føÔ¨Q#”e6›±X,>|˜rã7Ò¹sg*T¨€Ùl¾ CEQp:(ŠBVVíÛ·¿`AŸÏGýúõËÌñõûý—¬ŸB!NˆB!„âŠQ·nÝË®G@»víxùå—™0aÏ>û,%z½¦i¨ªzNÙV«•ÿûßÔ­[—iÓ¦…ʵk׎fÍšñÜsÏáõzO ~äååqï½÷²råJ>ÿüsE)¶ƒ®ë„……ñÓO?±zõjV®\ɱcǰZ­ÄÄÄÅb!àr¹ÈÈÈ 55•ððpZ´hA§Nh×®‡—ËuÒdqáëÞzë-L&o¼ñ)))Œ9ò’—;_f³™ÿûß^|ñEš4i*gUXöëBg 6¦/W®Ë–-# ’ŸŸÏÈ‘#iß¾=C‡=§>?f±±±†AíÚµ/h0²qãÆDEE]6Î3)ÌlB!Ä%ü÷Xz€!„B!®o½õ7ÝtÓe·]º®³bÅ ¦NÊèÑ£¹þúëñûýg|×ëeË–-´mÛ¶Dïép8¸ï¾ûhÑ¢_}õ=ô›7o¦cÇŽ´mÛ–¸¸¸“‚ÑÑÑŒ3†aÆѥK—“úo˜L&¢¢¢˜;w.óçϧC‡84M£~ýúÔ¨Q“É„aƒÁ"™ÍQ…´´4öîÝKRRááá¬[·‹ÅÂK/½Dxx8ùùù'í“ÉdâðáÃÌ;—:uêЮ]»2• ¢( Œ9’»îº‹–-[[$cãR°Z­ìÚµ‹~ø•+Wòæ›o;þg{®¿óÎ;X­V0`À V8@çÎËÔ1?pàUªT¡qãÆò-„B”¢Â B!„B\1&L˜ÀèÑ£/ËmS…M›6ñÐCѦMúõëÊŽ8•`0È|€Åb¡ÿþg5ñ«ë:{öìaÖ¬Y4hЀV­Z±yófî¹çn¾ùæbïð7™Lì±ÇÎ{¾AUU8@ƒ ¨X±â%ë¥s.<³gÏæ­·Þ’/h!„¢ID!„BqEIMMåwÞ¡wïÞ—õvšÍf:uêDFFcÇŽ¥aƧ]^QE9«à‡ÛífæÌ™dffÒ§OÆêÉqºõoذßÿéÓ§ŸÔXûèÑ£ôèуiӦѾ}û³š¸ÿ{)+Ã0ŠTÎDUUl6½zõ¢{÷îÜwß}¨>Òg[ IDATªzÒ:M&wÜqo¼ñÆ%o|:>Ÿ{ï½—Í›7“’’R&>O)))Œ1‚¹sç¢iZ‰^«iÆ ÃãñpÏ=÷P­ZµóÚÃ01bß}÷]™výUxx8ýû÷gÆ ò%-„B”" €!„B!®(ëׯÇårQ»víË~[5Mc×®]L™2…¼¼<6lȘ1cÐ4 ÇC 8«@Éd"<<œ%K–°víZ’’’˜9s&íÚµCUÕ3L&ñññ<ùä“4iÒ$ÔgÄb±°ÿ~¦M›Æ AƒhÒ¤ÉI Ë —‹ˆˆ`Ó¦M|üñÇ$''ãr¹B½&|>@MÓÐu=Ô„ÛjµMÏž=éÒ¥ ÙÙÙÅf’èºNzz:6làçŸfÉ’%=z´ÈØ(ŠÂ˜1c˜>}ú9õI¹˜ìv;/¿ü2õêÕ£wïÞ—uæïEÁï÷óá‡R©R%®»îºm¿ÉdâÞ{怒 €iÓ¦óvØl6æÎË”)SJˆ¹\ΧžzŠ×^{­Le®!„e@„B!„W”iÓ¦…&\ËŠˆˆV¯^ÍÒ¥KY³f QQQ4kÖŒ5jP¥JbbbÐuUU1 ƒ@ @^^Ç'11‘_ý•ýû÷S»vmúöíË€ðx#Ivv6õêÕãÑG¥V­Z¡c[XVkÖ¬YLž<™¸¸¸Ð$¹ßïgÒ¤IL™2å¬J]Hv»éÓ§óØcáp8.ÊÄ}á¾›ÍæPy´Â PaFŽÏç»(å–EaÛ¶mìܹ“^½z•xÿÂÂÂX¾|9YYYlß¾œœœP€ÃívÓ¤I¢££iÙ²%õë×?©ZYuðàA6lH•*Uä H!„(%B!„B\1|>Ÿ|ò -Z´(õIï²$0zôhV­Z…ÇãAUUú÷ïÏÃ?L\\\‘Ió72eÊ*T¨@AA‹…øøxêÔ©S¤a¹¦i?~<4‰ŸŸÛí•åòûýX­V¢¢¢ˆŒŒ$,, ŸÏGll,aaaøýþÐ13 »ÝÎêÕ«Y¾|9Á`«ÕJjj*#FŒ`øðáEöG×uÌo¼AõêÕC˜°gÏš7o^ªÙK–,¡M›6\}õÕt½…½UÉÏÏ'33“o¿ý–]»v‘œœŒÏçÃápP³fMš7oÎõ×_Åb!66–¸¸8<ÏÃ0X°`Íš5£råÊç´UU±Ûí¡€Ma@Ççó9·®…YJ­[·–/!!„¢”HD!„BqÅðxpà3gÎ$66–`0ˆÙlæÝwßÅáp„ú X,&OžÌ|@~~~èxì±ÇxðÁ)((¸¨c«ª*ãÇçý÷ßí÷¹2 ƒ¨¨(æÏŸÏÇÌž={°ÙldffR®\9Z·n*e³ÙBˆ@ €ÛíÆçóضm‰‰‰ÄÆÆâõz±Z­Ô©S‡wÞy“ÉtÞÛét:yæ™g˜£GòöÛoóôÓO“••ÅÔ©S™Ÿ[n¹%”S’ÀÒéÖïóù5jiii¼ûî»T®\™nݺϨQ£Î)Äçó…Êl%''ˇí4ã_«V-²²²ˆŽŽ–B!JóZø\^tçwÊÈý?¾p“²B!„eó:nïÞ½%~]ƒ ÊD¿À-[¶`2™Î¹œÏ•¬  €Áƒc±Xعs'±±±”+W¿ß¢(lÙ²…7b±XBÍÌUUeíÚµ?~œaÆáñxŠÛÌÌÌPŠ’Œ½aÔ¨Qƒ?þMÓN €À‰ ƒ*Uª0zôh^xá @LL /¿ü2ãÇÇjµâv»ùꫯèÚµk¨û+¯¼Â¸qãHHH`äȑ̞=›!C†\”óc÷îÝL˜0áœ?'@€Ûn»-è3f 6›í¢lk0¤|ùòLš4‰>ú³ÙLBBÙÙÙ<òÈ#çT«OŸ>¼ùæ›tëÖM>l§9߯¹æRSS%"„B”2)%J|q.„B!ä:îrãóùÐuiqXœýû÷Ó§O6oÞÌĉC¿ßÏc=Fxx8@€)S¦ ª*Ë–-#бcÇÓfNddduÎÇ,..î´ ´ oÀ:t(óçÏÇétâr¹7n©©©(ŠÂã?^¤É¹Ïç£Q£F˜L&bbbøòË//H&ÅßY­VRRRÈÍÍ=çÏe‡ðù|øý~† †Õj½è<Ã04hÑÑÑØív–-[ÆŠ+Îé3Ô¹sg6oÞ,´3ŒwýúõËD0Y!„¸ÒHD”øÂM!„BÈuÜå¦zõêr­Z MÓðù|DFFâóùøê«¯B¥¯4McÅŠ˜ÍfÒÒҸ뮻ðx<|ðÁDFFÒ°aÃ3Ž©Ëå"..-77÷¬&ÏÝn7#FŒàÓO?Åb±P¹reºv튪ªT®\™¹sç†zYƒA:uê*ƒåt:™;wîi-窰ü—Ïç;§×vêÔ EQƒŒ1¢DJEQÐu³Ùú£ëúYgìû|>úôéC•*UPU•I“&±|ùòïGNN·ÜrË9÷ùÿ¢víÚ8N!„¢”ÉŠ(‘@P2@„B!ä:îòs6“õÿ9–.]Š¢(L›6Ù³g‡žóx<̘1MÓ¸ú꫹á†Ø»w/åÊ•£^½zg\·¢((Š‚Åb9§±W…:uêp8g\Þï÷sÇwð¯ý ŸÏÇ­·ÞJRRÁ`ùóçÉð(_¾<¹¹¹¡¦áåË—G×õ ~ŽèºNTTT‰Ë«ªÊâÅ‹q»Ý$''3pàÀÓ?TUÅjµ’žžÎÒ¥KùøãÙºu+{÷îåèÑ£?~œÃ‡³{÷n6lØÀG}ĪU«X­ÖSnŸßï§C‡äææÁŒ3/Ѿx<‡4B?ù~B!. €ˆ’]´å¢M!„âJºŽs»ÝlÚ²§³ Ìî›Çãáꫯ– ÆSŒÍáÇQU•ãLJ †a°jÕ**V¬HAA=zô --E‹Ѽyób{rü•¢(üùçŸ$''SµjÕs;' ƒvíÚðÑGU! 2aÂ-Z„Ãá >>ž@ @ll,Ï<óLh‡W_}•?ÿü3ôÚmÛ¶]ðIú£GR±bÅ¿Îçó1~üx‚Á wß}÷)·K×uRRRøé§ŸX°`p¢çFß¾}©_¿>±±±øýþPVOåÊ•iÖ¬  sçÎìÛ·÷Þ{½{÷’••Uìû¨ªÊý÷ßÇãAUUú÷ï_¢€Ža¸\. €œßï•eB!D鑈(ÉB!„¸r®ãÜ7›6GzzßoÞˆËU6˳äääРA €ãèÑ£´iÓ»ÝN§NB½2, +W®DQrssùÇ?þÁºuëxàÎXÎIQŽ=J•*U £iÓ¦ç¼}V«—ËE×®]9pàÀY•QòxŠ¢àr9Ù´ec™Ü·ŒŒ bbb$RŒ´´4Z´hÁñãÇ‹L¾šL&¶oߎßïgâĉüþûïdddüÐ4 ‹Å‚Ýn'''‡ùóçS£F ¾ûî;ÚµkwNý/þêöÛoçÛo¿¥V­ZlÞ¼™9sæðæ›o²sçNTUÅn·cµZ‹/Ú´iÃÞ½{ +€øë2š¦±}ûvl6‹…C‡]ð>QQQE°Ÿ¸¸8¶mÛFAAÆ +2~†a`±XX°`@€Î;³bÅ ¹îºëxã7˜4iMš4Áëõât:ñxû ‡ÃªªDGGÉØ±c™7oû÷ï§V­Z´lÙ’o¼‘Š+òÛo¿±zõjTU¥aÆôèÑã‚NxƒAn»í6®¿þzj×®Mýúõ¹öÚk lذmÛ¶ÇM7ÝDëÖ­IIIaíÚµLŸ>k¯½—Ë…®ë|øá‡¡,Ã0{.F‰¦@ @VVÖY_ŸhšÆ[o½Exxx‘æñŠ¢˜˜ˆaT«VuëÖ1~üxZµj…Óé<ïëŸ@ €Çã¡GŒ?ž/¾ø‚N:ñå—_†Žc  ..Ž@ @tt4»ví:«u[­VrssÏØ7F®m 222d „BˆR& â¼8 !ÄÅp{çÛX¼d)#† ¥\t4™™|¾t)=ºuåÓÅŸŸ´ü-â…—^MäÜtã?™ðÀ8ìÿ½#¸0³ä‰Ç¦1ï½÷ILL¤råÊ ¾ëNzvëZOI—+ ‚þÿǧ=ÊÜy HNN¦fÍ<<é!®mÔ(ôº/–.ã½>䨱cT­Z•¡ƒñØÿ.².!„(­ë¸Žío ýÝl¶Ðþ¦ŽerßÜn·@N!,,Œ””²³³CY2Š¢°yófÌf3^¯—?þøƒÌÌL&OžÌï¿ÿNxx8iii¡ B5>|x(€——wѶ÷ï“è­Zµ¢U«V¡s833“üü|<ÈàÁƒ™9s&ÑÑÑ¡2L[·n-r.T¨PãǃÕj½à7R¸Ýn ÃÀd2UÀï÷sèÐ!4M£S§N¡ÇwíÚEµjÕøðÙ4i]ºt eÞü¢(¨åL¨uòNRÝé¤ú28–}œÜ=¸“ÄùÊó ¨[UQ‹¼677—iÓ¦qðàA*T¨Àž={hܸ1†aP©R%¾ýö[¢¢¢Ø½{7õë×?ã>…‡‡³fÍn¾ùfùÀANNŽ ‚BQÊäW‚8ïÎBq1 ¿{>Ÿ÷>ø€÷?ø#dÄл‹]>¿ €O?\Ȧõk¹ÿÞQ,^²”Wæ$œ´Üª5kHxåe–±˜jU«ðï§g²tùòs^îï¶mßÁ{sßaúÔGùý}<ñÔ3¡ç–._ÎO?CåJ•Xöùg$¼ò2_— l†BÈu\ñü~¿4`>…ØØX¶lÙj'îDÏÎÎFUUl6óçϧoß¾¬X±‚fÍšQ»vmâââ Ãl6‡ÆÖ0ŒRÏÄ,|OÃ0P«ÕJLL wÞy';wîdРAäç烢('õX(l²îõz©U«Öÿ¸Ýn*V¬HxxøY-Ÿ››‹®ë¸\.*W® œhT°jÕ*ž|òI*T¨Pìv*Š‚­¦oKŸ+þ3ÜM€ éî 2ó2ðx<˜#­¨Cɇùú·U¼òÍëlܽ¹Øq­Y³&mÚ´!--¯¾ú ŸÏG… p¹\¡@Í™|ùå—´mÛV>lg¡pl…BQz$"䇳â²T­jUn»å>ýl1Gùä³Åôêу qqÅ.?b8µjÖÄl6Óõö.lØxr3ß ãÆCùòå™0np"¸r®ËýÝý£ï%<ÜÁ-;pøÈ‘Ðs…¯pü‰uÇÆÄðàøä` !ä:îHñªV­Ê¦M›0›Í¡RG+]×IOOgãÆ <˜@ P&šYçååE³fÍÈÉÉ õ±øûyàñx°Ùl8NZµjuQÊ45lعsçžÕ9èõzQU•`0ˆ¢((ŠÂÈÍÍåÉ'Ÿ,Rëï|-uŽD§à xðÞþ¦ƒà øÉÏË#ëx`€º×ÕgP‹þ¤µËbåÂoH:vœÿ,{•QF`3[‹ŒÁÕW_M~~>aaalݺµDßf³™jÕªIo‹³$Z!„¢ôIˆ(‘²p7˜âÊQ³F :¶oGJJ }{õ"&¦|±Ë=<õ1~øñGfL}”-Ö³qÝšSþpOJ:þ¿¿O j•Êç¼\I¾>999ôXâ±cr …r'ûwÑpë­·Ò©S'ÒÒþwcÀ7ÞˆÏç •Œr:e®Ja))Ã0ÈÊÊ"ЦM›"ÍÙóóó‰%11ñ¢•J+((à©§žbß¾}g\Öd2…Êy¥¤¤P£F êÖ­K½zõN½þkƒw§ñgÁa^Õ›?~ÈÇ?ãWÿƒ*WU…k­X®'¦Cê øõ4Âíðñúó |ò̇\3èZ¬Uì(ŠÂ›«NÎT ƒ4mÚ”µk×¢iZè&ŽÂ`Ù©hšÆÔ©S¹ù曋Œ¹8ý9+„BˆÒ%Q"ra+„(mÏ>õ$;¶lbâcÏøÝäp8ðx½¼:çõS.ûŸÙ³IOÏ ##ƒÿ¼ò w pÎ˕Ġwðò«¯‘‘‘AZz:³^ž-Y!×qç©pRYÜu]§[·n¤§§‡ïÑ£ùùùü~?.—ë¬ú=\NE @œN'@€¾}û†Ê\†AíÚµQ…±cÇb6›/Ú¶”/_žÇüŒÜ‡¿ßOXXûöí###ƒ-ZàóùŠÝ¿À &<7™Þ,î®ßŸ»â¹¥vÖp–íÿ†,wf‡“ÝŒfBw˜Ðí&5©=ª![WeÓ”5˜£,˜cN”×ziÙk¢7‰ƒA~$É-ø IDATøa6n܈Åb J•*§-–““CXX±ÿÍ~gf·Ûe„BˆR&Q"¿PBˆËÁS3§îÕu¸wì8ú¼‹š5«ŸrÙ›;tàþ èÖ§GåÑ)“éÞõŽs^®$ºÝ~;Óþõ0¦kフ0‘ŽíÛŸøY•’…rw®ìv»Ü¨s…ýþ:Fv»UUCÙe±‘|a$##]×±Ùl”/ÿ¿lÑ@ Àõ×_Obb"Ý»w¿¨ÿÖƒA>øàN;ŽV«•råÊa³Ùøå—_ˆŠŠ*vYo• Ç\ÇÉõç3±Î½Œ}y"·õì̪´oÉõæa±›qXÉ4‡i 'ÒC·c·„a¶YÐìQÊS}`=26'è  Y5P`Ë?žô~‡ƒ:àõz Ô¯_ÿ”E›ÍƬY³2dH±ÁQüùú×óS!„¥Cò/E‰/ì…âbÚ±eS‰—iÖ´ ½· Èc}{õ*öµ]oïj’~:gZîïÛPÜv÷XÏnÝèÙ­[èÿï?ð'WU«*_Qê×q^¯—ÃGŽ’››KTTWU«ŠÉd*sû…ßï—ò2§`³Ùxÿý÷‰ŠŠ¢cÇŽàñxèСÛ¶m#66¯×[& n·›íÛ·êR¸ªªÒ²eKfÏžÍðáÃq¹\u{ÒÓÓq8lÙ²…–-[žòsxûí·3wî\š4iÂÈ‘#‹Í²00H,—ІF£èܵìútîÅš#ßa1™±™Ã°hLªŽþ—ŸõÕOÀ¢+: *^Ń­ªª}j“´ô ¦p3Š[÷mㆺÍQ•ÿ…|>š¦Ñ°aCvîÜIÓ¦M‹=' ÃàÕW_åÎ;ï,sYC—ú|•l!„¢ôÉí¦¢DŒ ”BˆóñÐÃÿâ·½{ñú|:|„çf½Àð»ï–ÁB”êuœ×çãÇí;HMKÃíñœ’ÂÖmÛñz½enßâââHKK“çà÷ûy÷ÝwIKK#??81Ùݶm[ü~?†apèÐ!’’’ÊÔ~¢¢¢HKKÃï÷sûí·‡&ä- #FŒàúë¯' âñxJe›zôèÁêÕ«q¹\ÅžÁ`G}—ËEåÊ•OyƒYš#›ŸîâóîãN"‚álKÿ³nÂb²aÓ­XT ÕŒY3aÕ-Xt fÕŒI1aÖÌØ4 fÝ‚jV±WÀ^=WŠ ÕªaSô¾7æèÑ£4nܘˆˆˆ“žW…mÛ¶¡i111òá*]׋S!„B\\%û‘”ÒBq>:ßÚ‰'g>Çí;2xøf=;“;ºt–ÁB”êuÜÁƒ‡Š]îÏS<~9‹‹‹cÆ RNð4|>ÕªUã_ÿúpb"ûÖ[o%#ãD¿+EQX´hÑe;†Š¢ ( ªª¢ª*Š¢ðû￳|ùr"##ÉÎÎf̘1¡’MéééT©R…9sæÐ AƒRËdw:Œ7ŽÎ;Ÿ2èRPP@ûöíÙ½{÷)·kOÎïøò=´ŠnÎg¿.£cëöäèf6í¿AUǬš1«ftEäèX5+VÍŒŽŽ¦j˜T M×PL q·^…)Ò„óh>Š¢ðËá]'½ïUW]…ËåbÞ¼y'ęªJbb"k×®¥OŸ>Òw§„Ìfs©â„Bñ?’#.JD2@„eÕÙ”Ö*ÉrçªcûvtlßNˆâ’_Çedf»\fVV™Ü¿o¾ù†¡C‡J/SÃ`òäÉtïÞˆˆrssñù|Ìž=›§žzŠ””ÆϬY³˜2eJ¨¯Ã¥˜äVU“É„¦ihšFZZ‡bÿþý$%%¡ë:QQQ(ŠB0Äd2éE¡ª*+V¬àÝwßå‰'žàÞ{ï-Õ‰g¯×ËçŸÎ!CX¸páIe¢ ÃÀápœòõ‡ƒÃ¿ÆZÅε±ÿ`Îî×ðÕ4ÐÍ'&ÍŒ¦hhŠŽIÑO”»RU0 `PT¿@ j(¨(((šŠnÕqÔŠ$ã‡d‹Êá´£'½·ßïÇápœô92 ƒíÛ·³zõjâããe"ÿœ®¡¼B!. €ˆ‘ !„Bˆ+ã:îTÛeõ®îììl ~œATTýúõãµ×^cذaøý~Z¶l‰Óé$,,Œ%K–0aÂ~þùgÒÓÓIOOÇét†J9)Š‚®ë”/_ž«¯¾šÚµkãóù.Ø9cµZÙ°aÙÙÙÔ­[·ÛËåÂd2N»v툊ŠBUUìv;<òaaa¤¦¦2lذÐv˜ÍföíÛÇã?΀.Éd}0dÁ‚<÷Üs´nÝšŽ;™/Ìhù+EQX¾|95"õ` ±¾8Ödo$˜â·v0):*ª¢ «º¢£«'þøƒ~‚𢡢¢)**ŠÄl•íhVUS1TƒP¿~ý"/“ÉT䘚ÍffÍšELL cÆŒ¹è½T®DŠ¢ðÝwßѤI !„¢”ID”ˆ¤9 !„B”Ýë8…+·GÆý÷ßÓéÄjµÊÁ>ŸÏÇ=÷ÜÃ-·ÜBïÞ½ à“O>¡wïÞìܹ“îÝ»S¯^=6lˆ®ë(ŠRä7@0Äï÷“Í+¯¼BÛ¶miԨѹ»}Μ9ôèу *œ2hQØ£æË/¿$??Ÿ¨¨(0›Í¡èãÇ硇âÇ$<<¼ÔÊ_ý]^^cÇŽåóÏ?ç“O>¡gÏž¡çŠË²ˆ%11_®_ž‡m;OôÛP5õ¿A“MÎOüOWuLŠ 0TÝÐQ ßÿ>û €˜Ë[1E˜Á0HMK%+.‹;wÒ°aCàÄD½Ëå ¥ßïgöìÙ4oÞœzõêIð㩪Ê×_Mß¾}e0„BˆRvN]{vÉÈý?&Ç_!„¢lÒíŠÝ·{ï½—üQ g ( ß|ó S¦Láõ×_ÇårMß¾}Y²d ÿþ÷¿yüñÇñù|¡¬€â„‡‡sÏ=÷àõzIHHàž{î9¯mÚ½{7C† AUÕ3fl(ŠÂúõ뉥råÊ4mÚ4äp¹\ôíÛ—_|‘'Ÿ|ò’? y<ºtéBXX½zõbñâÅ´mÛ–­[·YÖ0 š7oÀÖ?ásúÉ<†¢þ/pip" á7ü˜0…W Ÿ3N¬§0h0‚ÿ}PÀiF³é`@xD[¶laÊ”)œXª’‘‘¦i$%%1|øp-Z„Ïç»äcY–©ªJrr2&“IC!„(eçixMC¹ÿ§ ïB!„eËæÍ›‰ŠŠºb÷/ âv»å@ŸÍ@]§ÿþ$$$p÷Ýw£( cÇŽÅãñðÕW_ñÉ'Ÿ0pàÀ³O‹ÅB÷îÝIMM¥B… ç”1n2™Øºu+µk×>cvÃ0xòÉ'‰‹‹£R¥JÌ›7/”â÷û™2e 4àÉ'Ÿ¼¬ÆÜétòöÛo³hÑ">ÿüs–-[ƤI“0™LÅš‚^?†OÇ›ã%èû_à! T € ¨O”½RN:|Á~#€ßð pbþûzqáøò}XcmØÂÂ?þþPð`ïÞ½˜Ífâãã9r$‹/Æétʇæ<Я_?!„âPeDIX !„Bq¹Ñu~ø³Ù,ƒqZ·nM~~>þùg¨ÔÑ„ ¨Q£;vìà믿>«±4 ƒòåË3{öìs{³Ù̱cÇÐuýŒïõúë¯c6› ãwÞ ?Ìf33fÌàšk®¡OŸ>—eé^Ã0èÔ©¯¿þ:'N$??ŸÌÌÌb—UPðøñezú}ø ãDÃôá1¼ü{÷Eµÿqü³»é’@Pi‚QQxE)Š4‰ R¥‰HU.z"‘Þ‹¡—PÄ BâUP M¤I º»¿?Õ@"Y °Þ¯çÙ'»gfÎÎ|Ï&™ÙïœsÒÍéÊ´d*Üyõ§%C™–le›³d•Uf«EVËÕ^!^žJ‹K•Ád¸Ú“亡ˎ=ª'Ÿ|RsçÎÕã?Nò£€ÄÅÅé…^ Ü$@`÷I;àhL&“öìÙÃXù”­hÆŒJJJ²Íõ1kÖ,U©RE_ýµ6lدÞßF£QF£ñ–{àÄÇÇËÝÝýo{X­VM™2EIIIrqqѲeËlsh˜L& 8P=ôzöì©€€‡íµn±Xd6›õî»ïjΜ9úüóÏsMü” .%K¦YY3e¾œ­Œ¤ Y³-ʲf*Ó’¥,K¦2,™ÊÈÎPº%CWÌiºbIWš9]æ e[³”e5+Óšuuî‹UFWƒ’S$³$£A¥ƒîËñžZ³fF­ÔÔT~I ¸ÝK”(A ¸ H€Àî7À5oÞ\GŽ!ù”’’¢aÆ©_¿~Š·Mp>}út½ýöÛÚ¶m›&Nœ(OOÏ›ÞU½zu%$$ÜÒ~ìß¿_U«VÍõ= ƒÌf³†ªsçΩFŠŽŽ¶%?ŒF£zõê¥ÄÄD½ú꫺råŠÓ Ù[®\9;vLqqq7,{´t¸ ƒŒ&Y2Í:¿#N–,«ÌÙfeZ2m=@Ò­J3§ëJvšÒ²Ó”fISº9ýÞ Y¶ù@,™Y³¥Ëÿ½ ¿‡üåè¦ð°‡s¼çž={T¹re™L&~9 §§§¶oßÎüÜ%$@`‹•Ók¯½¦•+W;X­V-Y²D3gÎTll¬ŒF£²³³Õ£GM˜0AÉÉÉ4hŽ;–çWV«UõêÕÓ‰'ni’““õÐCÝPîî¿þZƒVVV– ¤ñãÇËb±ÈjµÊÕÕU}úô‘ÉdÒˆ#äîîîT±7™Lš2eЦOŸ.OOÏË,vÿÕë¯+Ù2º¹(;9Ség¯\íbÉV†9Siæ ¥e_ÑóÕ¤Gš9]iÙéJÿc¬lköÕH¦Yr“ê>ü¼Ž|{PnÁžºüûe•)þ€íýÜÜÜ4~üx 0À–\BÁÈÌÌÔîÝ»™K€»„ì»@²0ô\ÕjUåÊ•o:‘6rJJJÒǬãÇë»ï¾“Á`PZZšž~úiíß¿_=ö˜fÏž­™3gêÒ¥K¹ÞÉn4uæÌ»{ ]ºtI¥J•²½–¤„„õïß_Û·oW¥J•´gϽøâ‹ºté’mÿZ·n-7777NÞÞÞruu•‹‹K®WW×¼ÖÉmÝülw³u®=L&“L&“ŒF£,‹*W®¬ÐÐP­Zµ*ÇçÖh0ê©rUeµH®EÜtådªcÏ*3)S2[”iÍT¦5S–,e˜3uåHº%]™Ö,e[ÌW¯ÝÌ™V•õ~PÚŒ–oIÉ E>ÕÌk“ɤñãÇkÈ! ⢀íÚµKË–-#Ü%.„ö ÙÙ³gåååÅvºråŠ"##uþüyµmÛVË–-ÓÅ‹•˜˜¨qãÆ)--MÝ»w׈#ª·ß~[¾¾¾¶Þ‹E)))òôô´+öJJJ²=ÿþûïµråJeffªtéÒš©ûï¿_*T°ÕQþIýïвZ¬ò.å«ÔÃÉò,á#¿‡äà&‹«UV“QÒŸ×hV«õêœVI‹Ìf‹*RV;¶ì«¯«Ü‹y)+!]EŸ²÷öíÛe4U¯^½&EÇ?c0tôèQùúú î ° “ À‘EFFjÍš5zþùç9w½…sý   ;V#FŒPVV–¨K—.ÉÓÓS‹-Òþýû£aÆÉßß_¥J•RíÚµ¦   %$$ÈËË+ß‘¡äädMŸ>]‡–ÅbQëÖ­U«V-=õÔSJKK»záê⢄„õìÙS;vT‹-äáá¡É“'ç94—#»xñ¢&Nœ¨êÕ««dÉ’Z¿~½ž{î9õíÛW=ô²²²d4õn£®·v²¬’ÜŠzêôŠc*2¨ªÒϧË-Ð]F£UÙYÙJIIQ`` ¬ºšl1ºeδ¨Ù#/kx‡!2¹™äûP€®œ¾¬žu»Hº:ìÕŠ+ôóÏ?+**J™™™ü0???-Z”@p¬\\¸p!_DGG+22’ÈÝ£.]ºÄÝ+N(&&Fþþþ¶×;cbó\·FµÛóŠ+æûZÁQ4mÚTǧÑÿ777ýþûï>|¸Þ~ûm=ù䓲X,²X,2™LòððÐŽ;4sæL>}ZgΜ‘«««|ðAµoß^f³9Ï”Á`ÑhTVV–FŽ)___/^\Íš5Sƒ ”™™ië…áéé©£Gjûöí:pà€zö쩨¨(uïÞ]%J”pú8Ϙ1CÙÙÙzúé§åã㣗^zIµjÕRÆ m½GÒ2Ó5mó,ŒYÍ]9•ªbO”PpÃûT¾dy;/‹§AI)‰*|¿BüŠêÄ¥SJØtJû7ÿ,ïP_¹‡y)ã\š:üë-yº{Êh4jêÔ©²X,Z¼x±­ Ö¾}ûtÿý÷ë‰'ž ÜaWÏ=I€À)STįp2÷RäÀÊÎÎvºI±ÕñãÇÕ£G}òÉ'ªR¥Šm˜§kŒF£|}}µÿ~­Y³F[¶lQDD„xàeeeÉl6Ël6Ûéé銋‹Ó‰'´zõj™Íæ\‡^JKKÓСCe45jÔ(õë×OõêÕSëÖ­ ]Œ;uꤚ5kê…^PÛ¶mõ믿jèСrqq± ¡µtW”â.œ‘ÁÅ(«Ù¢‹’$w©è3ÅZ©¸|<}tò÷S:}\–älù•G o¬RÆù õ¬×EV«U)))êׯŸzôè¡6mÚ(##ƒùm`0Ô®];íØ±ƒ`pܶÈÜ 5ñó)êþN½Õº‘.d’““s\8À9ÜK ÔÔTM›6M7fNƒpmÎŒ_~ùEÇ×_|¡Aƒ©nݺJMMµ}n4msçÎéìÙ³¶‰¿]]]åááa›Ü××WnnnÊÊÊ’Õj•Éd’§§§Ìf³zôè!ƒÁ 7ß|SƒAÓ¦MÓ€ôøãÛ5¼–³9qâ„~ùåM™2E={öT‹-TªT) 4H...ÊÌÌÔ΃±úþÈnݯN˜nt3É`”,ÙVY²-rñt¹ºÌ`›¿‡R¤èÍj-ª”ä=Z~~~2dˆî»ï¾’Y(8ºxñ¢jÔ¨A0¸ nKÄb±è•f-Ô*ò5-\ò¥V}µTF£‘h"’.(0 @8™{)"IÍš5ÓèÑ£™× €¹ººÊÅÅE;vìÐÖ­[•™™©Ê•+«hÑ¢*[¶¬Š+&???eggËb±Ø&I—þL¤¸¸¸(;;[çÏŸ×ï¿ÿ®£G*!!Añññ*]º´mŒ#GލzõêªS§Î=cMœ8Qf³Y7nÔÞ½{¬^xA*TPpH°Ÿ>¢ûY¿'ž’d•ÑÝtuˆ¬l‹¬’(ZZ……ËSúõ×_µvíZªW¯^ªW¯ž~øá=üðúråJŽ6BÁ0™LúöÛoõòË/+ €€p\K€è$è;cbåëë«–Í›k݆Úûž©^h"Ü!g°lÙ2Mœ8Q/¾ø"Á( F£Q—/_Vbb¢öï߯“'O*<<\¡¡¡²Z­>|¸~ùåF…‡‡«T©R •§§§²²²téÒ%ýþûï:räˆÎž=«âÅ‹ëµ×^S£F”œœ¬ääd |XeÊ”QTT”L&Ó•.. Uhh¨$é™gžÉó:âZö P@@€xàÕ®]»@bìå奲eËjöìÙúõ×_µbÅ 8p@:u’««+sèÜíÛ·@à ,òUT”’’“Q³VŽòeQ+Ô³[W"]ˆ.„gиqc½ûî»$@ì`0äêêªC‡)**J]ºtQóæÍ ¤^Üþ¶û'*T¨  *Ø~w^~ùe•)SF%K–$b‡={ö¨Q£FQ 3”gffjͺõZ»b¹öÄî²=ÖD-Óêµë˜x°a8“fÍšÉÃÃ@äƒÉdÒéÓ§Õ£GU®\YS¦LÑc=F`îA+W®T»v픚šªÁƒËÅÅ… äÓŽ;T³fM€ƒ(ÈÆÍ›þ°ÂŠÏQ^",L•*VTôæ-Dº œÉ¿þõ/Õ«WO®®®#>>>Ú¼y³Æ/WWW­^½Z!!!ôÚ€4h 3fèÌ™36l˜\\\H†äÁ`0èÌ™3jÙ²%×Í8I€,]¶\-š6ÉuYó¦¯jéòåDº œ‰ÕjUll¬ú¨._¾Ì9½Å¢Ã‡kâĉڴi“Þxã >$È—÷ß_’´aÃuèÐAÆ “§§'‘´wï^­ZµŠ@à`Œ„ö°ZèÊ çÓ»woÍž=ûžŽApp°Æ¯={ö¨råÊÚ´i Ü’—^zIk×®•ÑhÔàÁƒuüøq¹¹¹Ý³ñðóóÓÔ©Sù`à€¼va,S8£°°0yyyÉÏÏO/^¼gŽÛÝÝ])))Z·n²³³5tèPùûûóÀ?f0ôÈ#hñâÅÚºu«–,Y¢Õ­[WW®\¹§b1iÒ$Š8( ° C`ÀYõêÕKíÛ·×€ ýÜv&“IgΜÑ?þ¨ØØX-\¸n›Úµk«víÚJIIQ³fÍ4pà@/^\...…úwÍ`0(>>^ÿú׿dµZ™ûÄX° C`ÀY Mž}äíí](ŽÉjµÊÇÇG±±±Z¾|¹Nž<©Í›7«V­Zrq¡Ó?î¼€€ 6LíÛ·×úõë5bÄeggËÝݽPŸ§§§Ö­['£Ñ¨gžy†Àq6 û.®è'g04gÎ5nÜX}úôQhh¨SÓãâ⢋/*..N .Ô¨Q£FÃa”,YR­[·VëÖ­Õ£G=ðÀzàôøã+33Ó)ç˜tuuÕÂ… ¡gŸ}–FÀÑÏ™ ìA+W®T§Nét‰Í™3Gééé9r¤êׯOƒÂ¡M˜0A’´oß>µmÛVƒ RÉ’%*ùèââ¢Þ½{kúôé ¢Qp »öÉ"po™:uª\]]5{öl™L&‡ÝO«Õ*///%''«ÿþJLLT=4räHNå‘GÑ×_­   ýïÿÓ'Ÿ|"???§øýëÙ³§æÏŸOò'B÷´5jÈ××WQQQjÒ¤‰Ìf³Ãì››››.^¼¨ŸþYÔ³Ï>«¨¨( NïÑGÕ£>ª–-[ê£>RXX˜‚‚‚T­Z5¥¥¥9ÌðX...Љ‰Ñ/¿ü¢5kÖÐp8ƒõ³Š .äkƒèèh=òØ#Dîv)åApBþþþ¶ç;cbó\¯FµÛóŠ+æûZ¡0hذ¡7n4Ì IDAT† "Ÿ»ö¬Á`$%''kçÎúî»ï´dɧœ/°ÇÔ½{wõíÛW%J”››Û]ýÜ[­V­_¿^uëÖÕÃ?LàD¯ž[ßJ$22’Þ£¬V«í‚ Î#&&†ˆ±6l˜¾øâ ]¾|ù޽¯Ñh”¿¿¿ÆŒ#³Ù¬N:©D‰rwwçŒ{ÊÙ³gõË/¿hèС5j”‚ƒƒ•––vG®E­V«ÜÜÜ´oß>ÅÆÆêÃ?”——€“¹–a,ØÅb±8ôجÀ?U­Z5-X°@K–,Ñ™3g¡Ê•++--MYYYú^îîî²X,Úºu«¦îÝ»«xñâ4îYÅŠS±bÅT»vmmܸQ;vìPRR’žþy•/_^—.쨃A>>>:wmÛf{¯aÆÑ89 ° Ýîp/(R¤ˆ:uê$IÚ¾}»^{í5uìØQ2™L*V¬˜|}}eµZe±XdµZoz®l0d4e4uæÌ?^Çך5k´yóf‚ä¢^½zªW¯ž$iæÌ™1b„úöí«´´4ÝÿýòððÙl–Åb¹éïßµ‡Ñh”ÙlÖÙ³g•˜˜(oooÍœ9SÁÁÁš0aA a,Ø%33SnnnÀÉ0Ö?g±Xd6›uèÐ!íÝ»W+V¬PRR’Ê—/¯§žzJááá*]º´íËX«Õ*£Ñ(ƒÁ ÌÌL}ûí·Z³f®\¹¢ž={*""Bîîî2°ƒÙlV\\œ–-[¦åË—«V­Zjذ¡Ê–-›#b0d2™”œœ¬ƒê§Ÿ~ÒÞ½{•””¤ˆˆ5iÒDááá2™LŒt@!à ¸%ééòp÷ N†È퓚šªÓ§OëÂ… JKK³%>ŒF£-iâêꪠ  U¨PA®®® (@ñññúí·ßtùòåŠÙÙÙrww—ŸŸŸBCCÆÈܘ·ÄjáDø+U¨P@wIhh¨BCCówMKò€{ }­a‹ÕBìÂÝ2g@va,€3 »0ÀØ$èU"ªÛž ¨êUôn÷n !Ò…Dn=@ ¢í«DTמØ]7-+h»bc5wÁBý¼wŸüü|õLõêêÙõ)R„Æ'V =@öÄîÒžØ]ú~ç-š7G!ÁÁ0h0Q.Dòêâ¬m¿`ѽÙêu}½AKæÏ“ÉdÒ¿ÿ3„†'w[†À2 .ZTÚµÕƒ‰r!b±Xn©íÿÚKäú²¿þü»2IÊÌÊÒè±ãT§~CÕ©ßP£ÇŽSfVVŽ:—E­PƒÆMQ³–ÞjßAGŽËs?Ÿ0N5ªU“—§§ôn÷nÚóÓÏ448¹Û’±X,JLLÔ¬¹ó^©Q.D¬Vk·ýµa®®õ"É«L’fΞ££Ç~Ó‚9³´`Î,>rD³æÌÍQ_Ìwßiú”ÉÚ½A5ªUÓ°#ó}|ßÿ°[åË•¥¡Àɹde×ßåïçë«™S¿ Ê…H^ ;Õö룣5~ô(ÛÜ"}Þ{Oïõí§ÎÚÛÖØ·‚‚‚$Io¶z]³çÍÏWÝ҈џiÜèQ448¹M€üõNý¤äd-Z²T#ÇŒÑÔI‰t!‘WäNµý¹sçu_‰¶×¥JÞ§„sçr¬s-ù!IÊÈȸi½?ìÙ£AýGC?þHÊ—£¡ÀÉoWÅþþjófkíÝ·Ÿ("7›$¯¶wssSzzºíubbbŽm à õäV\T§NŸ¶½>qò”B‚ƒÿÑ1mÚ²Eüû#út˜ª<^™F€Bà¶%@RRR4oÁBæS(dn6H^m_顇4oá"¥¥¥ét\œ>ù4ç¼þEŠè·ãÇoZV¯N]3Nñ ŠOHШ±cU¯n[>ž‹kܤÉúbÒæ«€Bä¶ÍRÄÏO•{LC?þˆ("yõ¹YÛì×WC†׬¹ó¨6o¶Öwì°-oûÖjÓ¡£.]Jµ §•[Y‡vm4nâdµnÓN’T§vmµoÛæ–gÌø«Ct5mùzŽòo·m•—§' NÊ`ýã–þ .äkƒèèhEFF¹{Ô‰S'Tê¾RÀÉÄÄÄÈßßßözgLlžëÖ¨a{^±bÅ|_+€# ”t‡ÀBádµX Àá‘]ò3w ØÅbµ€Ã#»0À]èp$@`z€œ Ø… g@v±XH€ Pè¸ÜÊFûÿo?‘»‡ÅÄÄ€C»¥Hx¥p"w²Z­2 ÀÉp €{ C`Á.Ìp$@`«ÕJìB€3 »X¬$@Žìbµ0Àñ‘]èp$@`&A8 ° C`œ Ø…!°ÎÀ¥ *ùhÈP¹º¹êƒ~}s”òéeggë£? Ò…Dn=@ªDT·=7 PÕ'ªèÝîÝ’¯z«DTמØ]7-+hßîŠÑœùóµÿ/ò+â§jO?­]ßQP` N¬@z€ôïÓ[?ïÝ«›6ÛÊ6DoÒÞ}û5 ÏûD¹É«ÈžØ]Ú»KßïÜ¡Eóæ($8X vøã™¿p¡Z½öš6¯_§K¿T‰°0 ü÷`wÌ õà6(ˆ‡‡‡FªÏÆOÐñßOèøï'4vâD>TîîîD¹±Xþ~,£Ñ¨à¢EÕ¡][8xÐVþ×^"×—ýõçß•IRfV–F§:õªNý†=vœ2³²rÔ¹,j…4n¢ˆšµôVû:rôXžû;uò$=WëYùúúÈÛËK­_Ô¾ý¿ÐÐNæv%ì©wé²åªÛðe-]¶Ü®÷ز~í-ï[ngŽ7P\ ª¢ûK—V¯ÝÔwàÕá®Þ·§J—*E„ «õï'A·X,JJJÒÂ%_*¼R¥|Õ¹'v× Ã]åV&I3gÏÑÑc¿iÁœY’¤üÍš3W;´·­óÝwš>e²üý5Ñb 1R³¦}qÓýHKKÓ—_-Ó“OT¡¡`÷yòêõëõNÇZ¾r•š7m"ƒÁpÛß÷V“'À½ @'A¯ÿâ‹ruu•‡‡‡ê¾ðÑ-¤v¹¹ÖS£jõgT§A#E­\¥þ·aø³õÑÑêóÞ» QhHˆú¼÷žÖoŒÎ±ÎÀ¾}V¼¸<==õf«×uà×_oZo•ˆêªñ\m-\¼Dï÷z—†(DN>­‡׫¯Eêåf-ôÑ'C•rñ¢mù?ý¬ÎÝ{ª~ã&jÕ¦ÖG_=¿¼ÖË!?=+þ÷ýòõñQã—ÉÏÏWÿûa·mÙøI“µqó–ëoÜ´Yã'MÎñ>·/ö¸té’š¶|]—RSo(oözk]JM•ÕjÕÂÅKÔºíÛzµEK;Nééé¶u_¨ßPkÖoP«6íT¿quï}ÿý÷›Æ…ž!p$šY½n¬V«²³³oéDŽ/¯ȵ9@öÄîÒÖëÕ¼iS3¦Àßÿܹóº¯D ÛëR%ïS¹s9Ö ²=÷ððPFFÆMëÝ»K;¶nVó¦MôÑ'Cih€Bä?Æë•F ´dþ\-ž;[Eƒ‚4sö\Ûòá£?S«–-´ê«/5vÔ8xõšk½+¶¬_{Óž«×­Ó+I’^nÐ@«×þ¹~×δióýwÇIÒ7ÛwhÓ–­êÚ¹Ó õäµ/öðõõUÍgjh݆9Ê×mبڵž•¯–¯\¥ŸöíÓèáÃ4oÖ e›Íš3AŽõؽ[Ÿ®¨%‹ôTÕ'4vâd»ãÜM–9öÛošÑø‰“mw¡ð¸Ù ’àï¯6o¶ÖÞ}ûmennn9î(KLḺMnÃäV\T§NŸ¶½>qò”B‚ƒ 䨼½½Õ:²¥þzˆ†(D¦Mž¤Ê>*w77y{{«Ý[oêûÝöÐ0™ŒJL¼ ää…«wÏvÕæìYLp*’>j´ª=¡çþ¸ãI’j?WK{~üQÃG޶}Y ç—W*ÕmÏ‹øù©òcièÇÙÊöë«!ÇkÖÜy T›7[Û†¤¶o½¡6:êÒ¥TÛÄ繕uh×Fã&NVë6í$Iuj×Vû¶mnùxj>óŒúøoÿýwê™êÕôŸÁÿ¦¡ ‘O>©7^Ô¿ö—···._¾¬W_‹´-/W¶Œ>ô¡¬V«þ÷ý=v¼–.œ/I7È<33SÑ[¶jÁì™*j+?{6^]{½§6­[ÉÍÍMGý¦›6ë£?Ф)_¨zD„J„¿¡¾¿Û{5iüŠæ-\¨Z5ÿ¥¨U«Õ³kÛ² òqŽ}¶Ç˜àø§ $òñ s-ïó^/"\ÈX¬7&@®%'þNÙ2jîŒé9Êš7ùó¹Ö‘‘j™cynennnêÛ»—úöÎý³•Û¾üÝþÕ©ý¼êÔ~ž†(ÄÒÓÓååå%Å'$hÚÌÙ9–1R­#[ªDØÕÞìãŸ_îûùùéÄÉ“*U²d®uoûïvU¬Pá†DB±b¡ªP®œ¾Ù¾C5Ÿ©¡OG¦}ß×£áá2™L2üSÿl”ÜÝÜò½/öªZåq}1}ºV®Y+OO•-Sƶ¬Qƒú3a¢ºuâÅuòÔ)-\ò¥>ìß/_uç—ê7d,8 B{X-V‚‡tmþ‹¿Ú²~­z¿ÛS_LŸ¡!Ã?U`@€Z4m¢;wÚÖ©¡>¦ø„•*YRú¼o[Ù¢¹z¼÷¾R/_Îõ‹ýUkשÍ­rÝŸF êkÁâÅúñçŸõêËôhx¸$©ÚÓO)..N'®÷{½›c›¿Û{Žùš&_ÑØ “4|Èr¬óêËd44ø“¡:{6^÷•(¡¶o¶Îw¬oÀ¬LêpáÂ…|m­ÈëîÊǽãøïÇuéû €“‰‰‰‘ÿ_æØ›çº5ªEØžW¬X1ß× à%IFB{ä6ކìÂXg@v¡À]èp$@`z€œ ØÅb!p|$@@¡ãr+íÿ¿ýDîCí– ᕉÜ=ÊjµÊ`0'ÃM,î5 »0À]¬V+A8< ° =@΀ìb±’8> °‹ÕÂXÇGv¡À]˜à H€À. p$@`†À8ƒI€têÖ]_~µ,GÙ’¯¾Rçî=ˆp!C€3(H÷.5oá"™ÍfIRvv¶æ/\¬n]:áB† gP ð‡Vùrå´!z“$iCô&U(_Ná•*áBÆb!p|6H×Î4oáBY,Í[¸PïtêDt !«•!°Ž¯À eË<¨òeËéã¡ÃT¡|y•-ó Ñ-„H€œKAVÖ¥c5jÚLk–/#²… 8"‹Å¢øsñŠ‹‹Szf: 7………)48TFcþûuh¤D‰°?Q8/,G.^§ãNËßÛW!þ(D2²2u:î´$©xhñ|oçBè`z€ÀÅÅÅ©h‘ –‹«+ ‘ì¬,¹œwQ\\ Ü>ô€#JÏLW±âaÊ6›9gÀmÅMâwÁ bÅÃtúÜY»6+ðÈžØ]4F!f±r1 G¼2ÈÝÃCæ+W†µÀ¹ñ%08Á>ß·7öô}ÿØ,üc€ã^q1 Àýß Ü‹Hþ9Ïß à—Î1$Ã-_v{rÎy×Ïûó‹ìÂX¸W.B5m®5Ë¿"¸NÔf€;ËÞeùÛàNŸC’}ÿØ NvA´|å*Í]°Poµn¥¦_Éw]k£–ÝÒ>ìþñGE­\­ÊÇÇGUŸ¨¢¶o´–¯¯o¾¶ÿaÏ-‹Z©_–¯¯ü˜Ú¾ÑZþþþùª¿a“f7Ôéåå©¥ æÛ^ÿvü¸fÍ›¯ÊËË[oD¶TÚÏç{{À]臔Ç`V«U룣ա]­Z³NM^yù¶ß}ºrõZ½úÊË4 ŸÒ32´pñ™0Iƒ?¯í£V®Ö+èÑðpF­\³V£ÆŽ×Ðç«þë7+׬Յ l¯OÇÅéãaŸªMëVê÷Þ{JKOÓœù l ›m_`MÆ]Ààüÿ~ù[Ž{Ó8Þy^ŒD výrÓyôç }ìþñGùxûèå äçë«Ý?þd[öùÔéÚòõ¶ëoþz›>Ÿ:]ƒA ›4³•ÿ¼o¿z¾ßGM^‹T»N]´iËÖÞëÚã“þ­'Ÿ¨"OOOøûëí6oé—ÿ—c¿Ö}ýcøU="B>>>òòòÒ«¯¼¬ƒ‡ÙUÿµ‡ÙlÖšõëÕ¸Q#[Ù¢/—ªy“ÆzîÙšòõõQHp°ú¾×+ßÛÔÀiÏ= ø¼ˆGþÏí„ìB8êEhnÖmبFõ_’$5x©žÖmØ`[Ö©};mÙ¶M;vî’$mÿv§¶nÛ¦NÞ¾¡žÏÆ×kÍšiéÂù9ô¢ýúJ’jþëÍš;Oññ ‘‹‹‹¼ß[ïõ £ÇŽiûÎóép¹˜L7Ôe2™táÂ%§¤(8¸¨zv}'_ûpôØoš2mÆ Ã_­[±ü¦Û6xµ©$É¿H>Ì®ú¥«C3,_¹JƒôËQ~ñâE×ıŸI’¦Î˜¥i³f«W÷nùÚÀ?G/(î  œž­Kü_¾T\¿1Z)/êÕ-s¬»>:ZíÞzS’ ÚµjiÑ—KÕ¾mäZï ýµxéWZôåRùøú¨sû·UµJ•¿Ý§½û÷kôØñêû^/•yðA»iýÊ(]¹rE+V¯ÑøI“5rØ'vÕ¿cç.ÝW¢„J•,™£ÜÃÃCßn§"~~’¤ÎÞVçî=oøB6¯í€»}ÞŸ_·”Ùÿû‰ô=,&&† À¡/ˆ23³´eÛ6Í™>U¡!!¶ågããõnŸ¾zãõ×åææªc¿צ-[5h@?}>m†ª=ý”Š¿¡¾reËèßûËjµêûÝ{4vâ$-š3;ÏýØþí·š6s¶ ì¯ åÊÝòñx{{«É+/kùÊU9.öòSÿÒåQêÚ©ã ‰Ü_:׋Çë_çµ= ðÿuL4 àŸº¥Hx¥p"w²Z­\8¡Â~Ëõç¨ÿݱC•/Ÿ#ù!IÅBCU®lYmÿö[=S½šF§~½{)üá‡e2™4läh1\nnn9¶ûtôgzýµ¶äˆÑ÷tŠQ«VkÕšµ>äc•¼ï¾\×yé•WµaÕŠ\—7^¯5kªâÅ‹+))IË¢VèÑð‡íªÿûÝ»åáî®JºaYÝÚµ5mæ,u|»$iꌙŠxòÉ|o»Ú þW(è¿ »X,™r¸«BÊ9ÖÚõôF«×s½@jøÒKZôåRý¼oŸ^iØ@ü1ÁxÄSO)îÌYMž:Mïõ螣¾jOkÈðJ8wN%ï»O}{÷Êóâkú¬«=C:v힣|ÅÒ%òôð¸éÅ[ÄSOjø¨ÏtòÔ)øûëɪO¨O¯?ß/?õ¹l¹š7}5×÷x±Î J8wNºõÅbÑÓOVUÇöír¬ûwÛwû¼?ßë[ÿèKváÂ…|m­ÈÈH"}ÊÎΖ‹ y3g#Ûë1±y®[£Z„íyÅŠó}­p7íþi·ž¨ü„Ìf3 B&“ÉvÞ3’è;Y,‚‡Eî{çèàÿ4€;ìb±’€ãá øÿ €¿;×#»X-V‚Ç»ºn…÷¼?¿H€À.ôP ¯$«Àé1GG·õp'xyy)55U>>>€;„„€;)55U^^^vmct–ƒ«Qv GT,¤˜ÎÄŸQjj*Á ™ÔÔT‰?£b!ÅìÚŽ ° C`ÀJ’NÅRzz: -®ÀÀ@™Íæ|oW` ¿öÐ0 PÕ'ªèÝîÝB ô€#2›Í R±bÅŽ(d¬V«²²²”m×vÚdOì.I’ÅbQâ… Z°h± ¬YS§ÐB…=@ਲ³³í¾ PxÝ–9@ŒF£‚‹U‡vmuààA[ùï'N¨Ï€z®n=ý«võî?@ÉÉɶåf³YS¦MWýƯêÙ:u5Ñâ\ë?pð ê5zE‹¾\J Þa €ã»- ‹Å¢ÄÄDÍš;Oá•*ÙÊûüP-š5ÓÆ5«´aÕ …kâç_Ø–Ï™?_?þô³¦Mž¤5QËŸpCÝ;¾Ý©nï¾§þ}Þ×믵 ï0«•!°Ž¯@‡Àúë< ’äçë«™SÿLp|¹`ží¹»»»ºuî¤f‘­le«×®×g#>Õ}%JH’Þ·gŽú–.[®™sæj˜Ïôp¥Š´Þ]@à nË ’””œ¬EK–jä˜1š:i¢$éÿÔøÉ“õ믇tñÒ%IW‡Ëº&>!A¥JÞ—gýó/V£õI~ÜE$@ÎÀx»*ð÷W›7[kï¾ý¶²þR£úõµjùWúa×·Ú¶icŽ9%Š…†êÄÉSyÖ9cÊçÚ¼õkÍ]°–»K˜à n[$%%Eó,Tùremeiééòöö–§§§Îœ9«O†šc›F êkägctútœ.^º¤ÑãÆçX¢_|®UkÖhÖÜy´Þ]@€3¸ms€ñóSåÇÓÐ?²• þ` ÆŒ¯~|¨¢Eƒôf«×µuÛ7¶åoµn¥ôôtµïòŽÒÒÒÔ¡]ÛÞ#¸hQMÿ|²:ví.³Ùœë:¸}èpë·ô_¸p!_DGG+22’ÈÝ£Nœ:¡R÷•"N&&&Fþþþ¶×;cbó\·FµÛóŠ+æûZA`` ¤Û8 '«…!°Žì g@v±X™ïÐÝ IDATàøH€À. p$@`z€œ Ø… g@v¡À], ÇG:.·²ÑþÿÛOäîa111àÐn)^)œÈÝ£¬V« p2ÜÄà^ÃX° s€œ ØÅjµ¸M^¨ß  ° =@Çw/|‰N¢7ãB`‹•ÓÉ“§4sÞ<ý¼wŸÒÒÒôà¨eófªùL ‡ÚÏê7Ô–õkóµîÒeË5cÎ\µoó–Z4kšï÷Èoý¹í›$ yzzªx±bzò‰*jÞäU)Rä¶ã­ÖWõß®8´: Éd2Éd2ÉÅÅE&“Q.&Œ%'§(zÍ*þü ØÅja,8žÓqqz¯_µhÖTïtì 9vLK—E9\$ßçÞV«V¯_¯w:vÐò•«Ô¼i †Ûþ¾× ééé:uú´¢·lUÇnÝ5~ô( ½g>SއÍëÖäú9ùlü=öè#ü!¸ Ø… pDs,Rã—©y“Wme+TÐàØ^çÖ‹à¯e/Ôo¨.ÚkÙŠ•:Ÿ˜¨ÍëÖäZfµZµhÉ—Ú°i³._¾¬Õ"Ô­KgyxxØêéÙ­«–,ýJIÉÉ*óàƒêݳ»î/]ÚÖ³àÚÏ¿ëÅð¿ï¯¿ÜH›¿þZÿûa·ž~²ª$iü¤ÉªP¡‚êÕyÁ¶þÆM›õë¡CêÙ­kŽãúñ§Ÿ5uæ,8yRþþjùšê¿øâMcêáᡲeʨl™2òöòÒœù ÔÿýÞ’ô·1Èëo7³Ù¬ù‹kÓ–­ºråŠZE¶Tó&¯æYß_1++KÓgÍÖ¶ÿn—$=÷lMuh×V®®®7m“ÛI:uú´fΙ§Ÿöî•ÙlV•Ê©Wî*âç'IÊÎÎÖçÓ¦kÛ·ËÅdÊñùͯIS¦ªÌ¨ÎóÏÛÊþi8æ]˜ŽèÇŸ~ÒóµžýÇõü¼o¿&“ãNûëË–¯\¥ŸöíÓèáÃ4oÖ e›Íš3AŽz~ؽ[Ÿ®¨%‹ôTÕ'4vâdI~y¿eýÚ›~y¼zÝ:½Ò¨‘$éå ´zíŸëwíÜI›6oÑwì$}³}‡6mÙª®;ÝPÏðÑŸ©UËZõÕ—;j„üÕî¸Ô¯÷¢öüø“íõßÅ ¯c¼YÜ–|µLû~ùE£?¦ù³gêüùóùŽÙÂ%_êø‰ú|Â8}>aœŽýv\‹¾\š¯6¹]q¤ÿ ®W5Ð’ùsµxîl ÒÌÙsmË}¹T§NŸÖôÏ'éó ãô¿vÛµ?3fÏQ‘"~zõ•— 4ùùŒ8 ° C`À]¼tIAÿ¸ž®;*((ðoËÖmܨïtQ±b¡òõñQ§öokÇÎ]9¶éÙ­«Š…†ÊÃÃC-š6Ñ‘#GìÚ3gÏêà¡ÃzþÙš’®ÞÁðÐa=/IrqqÑ ý5}ö͘3W3æÌÑ ýåârc'“ɨÄÄ JNNQHp°z÷ìaw\tñÒ%»bp½›m³iËuïÒYaÅ‹Ë×ÇG]:vÈ÷þmÝöºvê¨à¢E\´¨ºu餭۾)Ð6¹•8L›úðMšò…ªGD¨DØ_ —+[FúPV«Uÿûþ;^KηkŸ×oŒÖ•+ç;¹ãͶ .ZTqgÎä:/ÇÍb¨3gϪt©R’¤¸3gT4(¨À?göÆá“OGê×#õïýåíí­Ë—/ëÕ×"mË‹]·ßgóµ?ïݧÁ È3.ÿ4ÿô3à( l¬~RJJŠ&Œ­í[6iÅW_ê¥ëjú¬ÙD¹É«ÈžØ]Ú»KßïÜ¡Eóæ($8X vŠcº¶ïp^oµ~]+V­Öò+uîüyeeeéேôñÐá¶uÊ•-«¥Ë£”žž®³gã5nâ¤[z¯F êkÌ„‰:qò¤²³³õÛñãúäÓùÞÞÏÏO'NžÌsù¶ÿnWÅ nøò¹X±PU(WNßlß¡ôôt}:ú3 èû¾ž©^M=»uÕáŸæÚ«a舑úýÄ ™ÍfI’Á˜¿;ù322täèQ}>uš6lÚ¤·Þh•ïävŒ7ÛæÅ:/hâ”/tæìY]JMÕ”iÓó³çk=«ÉS§éÜùó:wþ¼&1MÏ=ûl|¶þIÒÓÓååå%Å'$hÌ„I7ì÷”iÓu>1Qçõù´i»/[·}£mÛ·ëÃþ}e2™n[<òó¿6)=€#+° {~üI›×­‘¤?ºc×®­:µkKúó.ûk?¯}áüû‰š4å ý°{²Íf=õdU êßOþtß®Q]½{öЂÅK”pîœmîëëÁa±üýXF£QÁE‹ªC»¶ªÓ ‘­üïzxäöÙÈëó’™•¥ “&+zóÛERn]åæêj[`ß>š=o¾/\P…òå4hÀ•-ó Pˆ• ÓèO‡iÖÜyš¿h±Ò32TæÁôZ³f¶uzuïªÏÆOÔâ¥_)Àß_-›7Ó®ØïþŸ½;‹²Üÿ?þ„EPÚKÌ_ §s.¹EMóT*)®hbiš¸›ZŠ{.¡ ¸”Y¹†Ë±ó-ÅN†e¶»e‚ © 8óûÜ@dp^ÏÇÃÇÌ}ß×ý¹ïûºnçqŸ¹®Ëêc½ðïr04aê4;w^u|}Õ§Wbïòb°^6B¿ÿ^è< nÛ®Ð<dÏ«CûvZ»~½õ•^øw=Ö $©á?ÿ¡ääd-\¼D#††çÛ§Q` &N®ó))ò«[W¯Qäùµj÷¬ ƒœ+ËÇÛ[OhÙÂæïhÅ©ƒÂ®ñfû¼Ø©£²²²4lÔeee©GH×b×Y÷®]´¡æ^!…Ù¸6Öü¾råÊôÊËê’ÿ×N#‡ 5'?pg]ïs£¼óhH×&¡|{Ù[%~üññš9Û<·ÈÈaÃ4lÔhsD’ÆŽ©šŽoÛ«{7­Š]CÃ@Sb *Uªh@ÿ0 è&“ɤ'O)6.Nã&LÔü9‘÷ûö»ï5ñbýðútù²¤kÃ(åÅÄk¶ÃR$oω ¿ý¦uÞѬ¹sµlÑÂ=~jꯪãëk^ö«[G)©©ùÊÔÌ3¹Ÿ³³³²³³i8¨`J#¨Á`Ð÷ß§ááùÆ/5 N¶7füêЮ>|ï]:ð©öíú¨À<7îWX”›Í"]›ÿ%´Wùú¨y“““²²²ÌËiii7mÓÂÖyzzèLR’yùô/gTËÓ“†äSb °¯j÷Þ½JKOWnn®’’“µ`É=ñøãæ2nÕ«ëä©SùöËÌÊR•*Uäâ⢳gÏiꌈ›«°8(–z€äuñâEÅ®ÓÃ=h^W¿^=ÅÆ­Sff¦’’“55bÖMÛ´°umƒZköÜ(OIÑù”Íž7Om[Ñ0€|Jl¬þ/õÕ†M›4-b–²²³åéá¡Æjê¤ æ2}z÷ThX]¾œa2i¸±š;¾F/šêÕ½›öîû¸ÈceÃR¼s€T¯VMO<þ¸¦Mšh^7vô(M™1CÑ1±ªéî®Ð^=ôßO>)²M [Ö7TQ «Gh_IRPË–ê×'ô¶®)ï¹_Ï}öÍ`úó'ýéééÅÚ!>>^!!!Ô\uúÌiùÕñ£"ìLBB‚ÜÜÜÌËûZ,Û¸a ù½¿¿±¿+€-pww—TJs€ ü2MTÀæ‘UŠ3w XÅh2R ›GVa,€= «Ð`H€À*ôØ ° =@ö€¬b4’Ø>  Ü©t+;ýö(5W%$$P ›vK õPs”Éd’Á` "ì ?bPÑ0¬Â {@V1™LTÀæ‘Uè°$@`£‰Àö‘ULF†ÀØ> ° =@ö Uk0 :lõ9õ|êy=wVdþA…åÈÝ.wË»¶·¼<½d0нŸÝ%@)ñàZüN}±d,Ø ó©ç•–ž¦Ç<¦šî5© IKOÓ÷?~/Iª]«v±÷³¹ ÛVC`Ñæ¸]gÏÕc SõjÕuåÊ*(GªW«®z×Ó‘£Gî\$--M+¢WéÓ JIMÕÝ..jðè£êúb°š4jX¬ü!ܶÕ$fmœ.YªÁ¨wîÅŽy;m؈{ú#ó¹×pWvv6•Ø „„5lØð–ö5r¯ánõp·%–IIMUŸ°—Õê_-´pÞùx{+++KG¾>ªõï¼Sìl›¥ F£Q›6¿¯C‡(nÃFõì"‡R?ŸëI¼‰T<ƒA&“‰9ëu»Ïë&“ɪù?¤L€,]¾BÏ´i­A^1¯«\¹²žnÒXO7il^WØpGy×å}Ÿ““£9Qó¿{*Uª¤ÝBòíg4«¶lUFF†š7kªÑÇÉÅÅ…»©”…'@ö'”«««ºkûÎtààgæ¤×ôY³Õ ~}ýûÙöæònݦo¾ûNcGÌ׿ÿûü¢.Ò‰S§TÓÝ]ýú†ê…ÿ›Š@‘ º–±ô¼ àÎ2·õ¼n2™dÐJ€ìOHЊ%‹K´B¢cbõóé_´1nL&“Þœ49ßöu7êPb¢–-^(WWWÍš3WK—¯Ô°!ƒ¹›J‰¥ ݻァ®Á%IÁ:êM›Ì ‘CÃ5àµ!rqqVPË–Úµg¶îØ¡·.(gü¤I=|¸žnÒXéiéZM7g¸ö…êêÕ«æUÿ;ô…6nÚ¤o¾ýN®U«êŸÿ»ú¿ÔGÕªU3?Û®ˆ^¥m;wÊ ƒžmßNýB{›UVÚÛ€ŠäÆçõ[ÙßÊüGÉ%@.\øMµ½¼ò­»Ýù¶ïüHQ‘³TËÓS’4rØ0½Ø½‡yûæ¶hòõñ‘$ }m°zõíG¤–IJJÖ7ß~§Èˆ’¤¶AAš¿p±’’“åëã#GGGÍœ6U¡ýúëû~Ô®={µzårUªTðö»ë®JJý5UÒÓU»¶—Þû:•€›ºþK°¼Ï«ïnÞ¬;uÔÿ{óQeggkÕšµŠˆœ£i“&J’¶íØ©/Ö²… %I§M“OíÚj×¶M™l*’’²öŽõqssÓ¹óçuŸŸyÝíÎÏ’šª:¾¾æe¿ºuòm?{îœ:véšo]YÌ;QÑoÒ½»y³.üö››6Ï·~Óæ÷5dЫ’¤šîîjÿL[-;ZC_¬šîî…ÆŸ7+B+¢WiÙÊhU¯VM#‡…«qCæÀM¿ èR1å¯ä•+WVXß> éj.¿{B{öT­Z×~pÚ³§Ömܨ¶­ƒÊd;P‘ä²veô2yzxªU«6ªrws™ÌÌLíÞ¯””óê×÷å|ûßÑ ÿ©-Û¶kðÀE–srrRVV–œ%IiiiËÖòôÔ™¤$Ýß}’¤_Î$åÛî]ÛK‹¢æÉÇÛ›»§ŒÜ8FÛ•+W´uûm{ÿ½|픜¬^}ûi@ÿ0999éÇŸŽéíÛ4'b†fΙ«æMŸVÝ:u į÷È#š33B&“IŸHÐĩӵ{ûV*E2 2Eþ¢ìð—_éþûî3—9uú´~èAóòÃ> Ÿ>]fÛ€Š$o¯Z^:Ÿr^ÛwlUûg:èî»ïVvv–v|´M.¤«V-¯ÏÍF£ñÎM‚þJX?…öë¯ÜÜ\=ÿïòñöVö•+úê«#ùÊÕ¯WO±qëÔ³[ˆÒ/\Pä¼ùc>Ó¦µæDÍׄñã$I‘ó¢òmïܱ£¦LШáCUÇ×W?Ÿ>­•«b1u2wS)Þ¤y}´{·4x´@Ê×ÇGõýý¿{Zý«…ÆOœ¤i“&*àÉ'tW¥»4zìx­Z±L•+Wηßëo¼©°¾}ÌÉÆG@1d(rRÅã'NhÑ[oiÒøñæ2™™™rqq1/»Ü}·þÈÌ,³í@E’·È¿ZiçGÛôÛÅß´ã£múWó–úï'ûtáBºªU«®Í[xn6wn,ïÚµ³r…–½ý¶^ôšÒ/\PÕªUðäZ½b¹¹ÜØÑ£4eÆ EÇΦ»»B{õÐ?ù¤Ð˜/õ Uä¼(½Ø­‡*Uª¤žÝ»é³Ï?7oïÜY ýº’““åçç§/÷çN*E7ÞtïlzOú‡Z6¸Ó Z½JŸñ…º¾¬€'Ÿ$5mÒD¿ürF3fGjâŸÉ­ëš7mªc^WòÙsºÿÞ{5õÏñ™-É;¼Úõ÷·2ß ìÛõ …MªøõÑo5_#‡†ëÞ{üÌe\\œuùÒ%ó¤è—.]’‹‹K™m*’«W¯šŸ…Ôª­víÞ©‹Ó[6Ëd2ÉÕÕU­[µUe§Êž›ïhIª]ÛKÆ-²Ìƒܯ˜•+ò­ îØÑü>ï¯5vÔH5Ò¼®wîæ÷ꬮÁÁÜ=eÄhÊŸY»*ÚbÙ¦Mš¨i“&…nëÒµÐ6oÔJm‚Zû|Hv@ºÖäêÕ«z,²¿V¬ŠÑøÑ£ò G%I~uëꇟŽé©€'%I?þtL÷Ô­k.SÚÛ€Š&ï³°³³³‚‚Új×®ºtù’ªT©ª –mäââRè3óÕ«Wï\TÔÈ—5Ø B&Aÿ`ë6mݾCSÞ|CuëøèÍÜ¢Y3­Y·N¾>׆s]³nžiÓÚ\®´·IaCÖVvª¬V-ÛhÂ'jøÏFrq¹Ûâóò¿V€-*lôè˜XIÒ«áCó•ݸ&FÎÎÎjÓª¥Î;¯ð‘£%ImƒZ©U‹æ¥½¨HòN‚ž—³³³Z¶2—±äV†À2˜þŒ˜žž^¬âããBkUP'NÐý÷ÞOEØ™„„¹¹¹™—÷'´X¶qÃ@ó{ÿbW¸“¿LÔ£þêÊ•+46`ƒ:¤§žzê–÷wrrÒ7ß}£€'nZÖÝÝ]=@`%†À€M2H¹¹¹L0Ø(£Ñx[Ïë¹¹¹ …R¾IMŒW Ûcit¶ÁÒXÅÅ$è(ý›” °A...ú#óUvªL°A·ü¬n0ôGærqq±j? ° =@`‹|¼}””œ$·ênr®ìL…åHVv–~»ø›|}|­Ú¬b4’€í©áVCF£QgÏUvv6”#•+W–wmoÕp«aÕ<"$@ؽ«W¯ÊÓÃSÞµ½åàà@…åˆÑhTnn®rrr¬Úï– G¿=JW` TlNNNŽÕ_ˆ”_·”iP¿5WA™L& *ÀÎð# }ÃaæØ °ŠÉd¢6¬B€= «M$@¶¬b22Àö‘Uè°$@`&AØ›H€ùú¨žÀF%·¤ãY¿´'0ÀØD$jÑb yu  El\i UE€;«Ä ·óG쟎SãÆ¬Š•‘‘¡…K–êùà.jج…šµÑ°Q£õ¿ÏѪ¥¨¨ 1kãôT£&ŠYgUÌ[M|8xP/¬À¦ÍÕúÙš<}†.^¼H#l£Èï¿ÿ.'GG«ö=þ ]¼xQ æFêÿöìÒûïnÔ3mZkEô*ZµYêb4µióû1tˆ6½ÿ¾ŒÆÒŸ,}íº êÕ½›þ¿SÖÄê®»îÒ›“§ÐH€²I€F­\µZϾÐI̓ÚhâÔiÊÌÌ”ôWo€ÀFæy—-I<ü¥Â’_ݺrttT 77µl©Kç+·ióûjÿ|G6m®ÞýÂtìø ó¶+99Šœ¥ vÏ*¨Ý³Šœ¥+99æí…ßÒ9åää(bv¤Z´n« vÏèQT\·~ƒžù÷óú[ÃÆ6{ÃXJlìO8(WWWu –[õê:pð3ó¶é³fk˶íùʸu›¦Ïš] Nÿ÷ù!uëªÀ¦ÍÕþùŽzË‹ç²dA”7l¨»]\ä^£†ÂRâ—_ñ¿P6 u7êPb¢–-^¨-›7)77WK—¯”ô×ðG‰˜ÿå]¶ä©€M™1S_9¢ììl‹å>ûL+–.Ö¾øjܰ¡¦ÏœeÞööªÕ:~â¤Ö®ŽÖÚÕÑúéØ1E¯Ž¹¥kŒŽ‰ÕϧÑÆ¸5Z»:ZŠ]×}qø°b£Wê‹„ý6{ØL…õî{ï©kpgIRp§ŽzgÓ&ó¶‘CõeûvíÞ»W’´kÏmݱC£† -gü¤Iz©O¨þoïn½ýÖR}}ô›bŸÛ燾ÐÃ=Èÿj@Ù$@6°EcFŒ¯ª¹ºjèkƒµwß¾ÛŠ1u²î½ÇO³#Õ,¨:tꬨ…‹”‘‘‘¯ÜØQ#åãí-õêÞMßýðƒyÛŽøx.¯ZµäU«–F¦ÅßÒùlßù‘F W-OOs,kë`ä°¡òôð°é¦°HRR²¾ùö;µm$Ij¤o¾ýNIÉÉ’$GGGÍœ6U /ÕÂ%KµpÉ[š9mª*UªT Ö]wURꯩºž®Úµ½ôæØ×‹u^ßÿø£fFÎѨêP1U*‹ƒœ=wN»tÍ·ÎÁáör/UªTÑ€þaÐ?L&“I'NžRl\œÆM˜¨ùs"ÍåjÖ¬i~ïì윯·Hjꯪãëk^ö«[G)©©·t>)©©bY[µ½¼lþ†),òîæÍºðÛo lÚ<ßúM›ß×A¯^kwwµ¦­–¿­¡¯ VMw÷BãÏ›¡Ñ«´le´ªW«¦‘ÃÂÕ¸aÃ"ÏéPb¢Þ˜8YÓ&MÔ#?Äÿj@Ù$@¼k{iQÔ<ùx{«¼Á`°*¾Á`Ð÷ß§ááj÷Üó°7@þ IDATÅÞÏÓÓCg’’tÿ}÷I’NÿrFµ<=ÍÛœœ”••%gggIRZZšÅXµ<=óÅúåL’Õu`íuß 7ÎråÊmݾCÛÞ/ßµ%%'«Wß~Ð?LNNNúñ§cúpë6͉˜¡™sæªyÓ§U·Nñë=òˆæÌŒÉdÒ§4qêtíÞ¾ÕâùìÚ³Gs¢hά5¨_ŸÿÑIe4VçŽ5ez„Nž:¥œœ;~\cÆ¿i±¼[õê:yêT‘1üªÝ{÷*-=]¹¹¹JJNÖ‚%KôÄãû¼ÚµÖì¹Q:Ÿ’¢ó))š=ožy'Iª_¯žbãÖ)33SIÉÉš1Ëb¬gÚ´Öœ¨ùJIMUJjª"çEÝVت{€|´{·4x´@bÇ×ÇGõýý¿{2335~â$M›4Q-š7ÓØÑ#5zìøBçnyý7uâäIåææ^»A‹H ­]¿^Q‹ë­E H~ò)Ñ  ¬KûüsóvkëÀVÝØäMïi@ÿ°BËwzA+¢Wéó/¾P׃ðä’¤¦Mšè—_ÎhÆìHM?.ß>Í›6Õˆ1¯+ùì9Ýz:i¢Ås™;¡$©S×nùÖºo¯îvqá7T`ÓŸ?éOOO/Öñññ ¡æ*¨ÓgN˯Ž`gäææf^ÞŸpÐbÙÆ Íïýýý‹ý]lûŸsP;P°†Éh¢6¬rã Ø" °ŠÑd¤6¬ÂX{@V¡ÀUè°$@`z€ì XÅh$°}$@@¹SéVv:úíQj®KHH 6í– ê7 æ*(“É$ƒÁ@EØ~Ä ¢a,X…9@ö€¬b2™¨€Í#«Ð`H€À*F €í#«˜Œ °}$@`z€ì X…IÐöÀ& ÊÅqn¿¬®³$1À”YÄÿØ‚ `*•T ¼ ŽêÕ«ë±jxøùÕ­+IJûL+–.Ö¾øjܰ¡¦Ïœ%鯡´®÷8°ä©€M™1S_9¢ììl‹å,G’Þ^µZÇOœÔÚÕÑZ»:Z?;¦èÕ1·T'Ñ1±úùô/Ú·FkWGë@BB¾íë6nÔ¡ÄD-[¼P[6oRnn®–._™¯Ì‡+6z¥¾HØÇn“©èIÐF£ÒÒÒ«õë+famj©‹Ó&Eµéš4j¨5q딑‘¡Ë—3³6NM5ä“ì\‰&@®ÿZ¿Eë¶ú`ëVEL+|¬»vixøkòô𧇇†‡)Pf쨑òñö–‹‹‹zuï¦ï~øÁªs‰˜:Y÷Þ㧈ّjÔF:uVÔÂEÊÈÈ(öqvÄÇkä°pyÕª%¯Zµ4rØ0íø(þ–êfûÎ4rX¸jyzšcåµùƒ-3b„|}|TÍÕUC_¬½ûöå+3rØPyzxÜÑÆRäzÛ?Õ¨‰‚ÚwÐæ>Ô˜‘#JüøÅikîCõuû5mÕZÍ‚ZÿÙNCùd;W©$ƒ%< “ɤ¤äd½9yª~øáGùx{(—šú«||þšdºŽ¯o25kÖ4¿wvv.²GaªT©¢ýÃ4 ˜L&“Nœ<¥Ø¸8›0QóçDë8©©¿æ;7¿ºu”’šzKu“’šZ V^gÏSÇ.]ó­spÈŸŸªíåuÇoK ¼½4.üö›ÖmxG³æÎÕ²E KôøÅikî “§ê™6­Õ»GIRÌÚµzsÒ-]8ŸO°c%>–Á`P__MŸ4QÓgGê÷?þ(PÆÓÓCÉÉÉæå3IIVÃÚòÜŸF„‡+ñð—ÅÞÏÓÓ#ß¹þåŒjyzš—œœ”••e^NKK³«–§g¾X¿œÉÍÞµ½´íý÷ÌC>%< C>½­ë. 7›D’j¸¹)´Wùúh±ëª°k+lÝÍÚÄZ_9¢>½{å›䫯¿æ“ìœCi®]ÛKO>þ˜>ŠßU`[Û Öšµ@©¿þªÔ_Õœù ¬ŠíV½ºNž:Ud™°¯j÷Þ½JKOWnn®’’“µ`É=ñøãÅ>NÛ Öš=7JçSRt>%E³çÍSÛÖAæíõëÕSlÜ:eff*)9YS#,Ï5ñL›Öš5_)©©JIMU伨|Û;wì¨)Ó#tòÔ)åääèØñã3þM›»an6ˆ$]¼xQ±kãôðC»® kÓÂÖݬM¬õÈÃ)fÍZ]¾|mÕkÖªÞÃóÉvΡ4ƒ¿ðÜszïƒ ¬ë*/¯Z 鮞½õÄc©R¥âÆÕ§wO…†õW@`#‹eú¿ÔWíÞ£N]BÔä_­ôÊ ×t×]wiê¤ Å>NXßPÝwï½êÚW=BûêûîW¿>¡æícGÒþ„µhóŒú¤F ÿi1ÖK}Båëë«»õP·^¡ üç?òmïÜYÍš6ÑðѯëéµÒØ7'ÞÖöK‹¥ ×ç l¤çƒ»èÇŸŽiÚ¤‰Å®«ÂÚ´°u7kkM~ó }ûÝ÷jÿBGµ¡£¾ÿáGMžðŸ `ç ¦?ÒŸžž^¬âããR¢'ñÓ±c6jŒ¶nÞD‹Ø¸ÓgN˯Ž`gäææf^ÞŸpÐbÙÆ Íïýýý‹ý]l»»»¤RîR”ȨùJKKÓÙsç4gþ5oÖ”V±&£‰JؼJwêÀ>ÞÞêÑç%åää¨yÓ§õêËýi ;Pœ9@¸ÓîX¤[—Õ­Ë‹´€1šŒTÀæ9P°C`ì X… {@V¡ÀUè°$@`£‘Àö‘åN¥[Ùéè·G©¹ ,!!JØ´[J€4¨ß€š« L&“ `gø €Š†!°`æØ °ŠÉd¢6¬B€= «M$@¶¬b22Àö‘Uè°$@`&AØ›H€ùú¨žÀF6S1%}.·Ï–êã:†ÀØ›H€D-Z¬!¯TâÁ¥~,[H*Øbb£¸ `*•T €ÀF·œÀøéØ15nÜȪXZ»F{÷}¬ó))ªì䤀'ŸP×à`ýãïOYŒSZI–S?ÿ¬EK—é‹ÄDý‘™©‡|@¡={ªÕ¿Z([‰žÒRX¼ ƒÁ ÷5ôÔß>x¼jÕºåûçvî)kîÛU©REŸìÝͧرJ¶p¿ÿþ»œ­Úgôø7äíå¥s#å]»¶2~ÿ]‡¾øB+¢W™ eåô/¿(lÀ«êÕ£»F„‘{MwýøãŠYWhÄžYêr=Qa4•–ž®µëÖëõ7&(zÙR›¾ž,që7(õ×_ùd;W&C`F­\µZϾÐI̓ÚhâÔiÊÌÌ”ô×/ð™ÿå]¶$ñð— Wâá/‹§¶——NÿrÆâö•K—h÷Þÿ(fm\‘qþñ÷§¿gÏ-ÕMICY¹Ù ’TÃÍM¡½zèÈ×GÍ뜜œ”••e^NKK»i›¶ÎÓÓCg’’Ì˧9S"CV­Š]£Ð^=øD€r¢L ;vÔ”é:yê”rrrtìøqÿ¦ÅònÕ«ëä©SEÆ ðªvïÝ«´ôtåææ*)9Y –,Ñ?^ì8Ú·Ó¬9s•””¬K—/+2j~¾í^µjiå[KôáÖ­ŠŽ‰µçå~/iý;ï*nýOIÑ•œýö[|}ìM릤Ρ¬ÜlIºxñ¢bׯéá‡4¯«_¯žbãÖ)33SIÉÉš1ë¦m^غ¶A­5{n”Χ¤è|JŠfÏ›§¶­ƒnëš>= çÊÎzâ±ÇøD€r¢D‡ÀºqéÚÐH]ƒ;ËÁÁ á£_Wrr²üüü4ðåþãôéÝS¡aýuùr†Å Ìû¿ÔW6mÒ´ˆYÊÊΖ§‡‡7j¨©“&;NïÝ•••¥~*33Sa}û(ãéá¡K«ÿ«ƒuõêÕBËøÕ­«å‹jÑ[Ë´<:ZYYÙzø¡Õ»ÇÍ{”Ô9”K=@ò¶}õjÕôÄãkÚ¤‰æucGÒ”3«šîî íÕCÿýä“"Ûª°ua}Cµp±z„ö•$µl©~}Bo뚢cbÕ»'½? <1˜þüIzzz±vˆWHH5WA>sZ~uü¨;“ 777óòþ„ƒË6nh~ïïï_ìï ` ÜÝÝ%•ÑX(?LF•°y$@`•âÌÀFV1šŒTÀæ‘U `H€À*ôØ ° =@ö€¬B€= «$@¶(w*ÝÊNG¿=JÍU` TÀ¦ÝR¤AýÔ\e2™ô삟ÔüʇúØé9^yå•W^yå•W^íäuü?Òx˜P¡L&“I’ÒÓÓ‹µC||¼BBB¨¹ êêÕ«š;w®>vzŽÊ°ͯ|¨&MšÈÍÍͼnÂA‹å7 4¿÷÷÷/öw°îîî’˜V2™L$?ì Ïo*" °ŠÑhTó+Rv„ç7 XÅh2ò B;Ã󀊈¬b2šø!€áù @EDV¡€ýáù @EDV1™è`ox~P‘ULF¿ °3<¿¨ˆÊ<ØHÊl?[¸†Ò>÷ã—æùMF~A`gx~PU*©@yÿ€îàà šîîúÇߟRø WU³fÍ2¹˜ëçxðÀM˦_¸ ÈyQúìŸërF†ªT©"ïÚµµ.fÕ-Å+-ÙÙÙZ»~ƒöüç?úùô/2^½ª5jè¡Ђ¹sÊü|è`>vzNM”FE¨P*•tÀ㔕•¥˜µqZ¶òmedü®y³gæÛn ¦Íœ¥}ÿWófÏTÃÀ@?~\+WÇûËBFF†ú¤ã'OjЀWÔ¶u\«VÕ×ß|«µë×ß‘ó»Þ„$€ý¸Ö¤  B)•!°œÕ#¤«$é‹Ã‡óm+l¸¥¶lU§®Ýøt3ué®m;vZ–iËöíz>¸‹Ÿn¦^½õÕ×_›ãuŒ}~è IR}99:Ê¿^=͉˜‘/†¥x…Åß½w¯zõí§¦­Z«m‡ç´ùÃ-ýŸ?Ö?Ÿn¦§5ÑÆw7Y,÷ÖÊ·õý?ªoï^êÙ-DžrvvÖßÿ ù‘³-îWšçg4I~ØžßTD¥6ˆÉd’$ÝåPô!¶lß®ÉÓgÈÇÛ[[ßOKÎ×Îøx‹å}‘¨5ÑokÂøqúáÇŸ4yÚµ¤EÞ^‰Ü´D5WWIÒ‹Ý{j”©ú`ËV¥¥§ç‹QÜxÞ}W£Ç½!Wתz7n6¬‰Ñ±cÇ -»}çG5v¼œœœ´pîu îl1îÞ}K’Ú?Óö¶Ú¢$ÏÏd21†4€áù @ET* ¬¬,ÅmØ(IjݪU‘e×®»6”Óðð×äéá!O b±ü ¯ÈÕµª‚ZþK’ôóéÓ·tŽS&¼©z<¢‹/jëöš<}†Ú?÷‚v‘|±$nýµk14\^^^rssÓ¨áC ”{wóf½9yм½k+får5 üg‘qÓÒ®Ó\ËÓó¶Ú£$ÏÏdb{Ãó€Š¨Ä Ô¨ù¿´låÛòñöVøàW‹,&)Y’äããc^WÇ××bùëÉ€J•®M_b4oé<Ÿ|âq­‹Y¥[>ÐØQ#U½Z5]ÉÉÑÂÅK­ŽuîüyI’ožk(LÔÂÅ2™Lzmà@Ýß}7{}òø”ÔÔÛj“’Š¿­k,ÉócûÃ󀊨T†Àª^­šF*÷5´pñ’|skܨG·IÒüE‹•––¦Ô_Õœù né¸nnn’¤¤¤ä›–í7` víÙ£´ôtåääèø‰’¤ÀüÓêxÝCºH’"çEéüùóºxé’æÎ_X ÜõÉË ùúX}¸u[‘q_î×O=ø ¢WÇh݆úõ×4]¼tIŸ‘¨ð£Š]/%y~ô°?<¿¨ˆJmôÊ•+«[×.ºxé’"fGZ,÷ïöíõÆØ1:yêguè¬ÁC‡©e‹×NÎÁºÓпŸj¸¹©C§Î lTdÙªUªjáÒ·ô\§`5nÑR‘Qóܱ£Æeu¼®ÁÁŠ˜:Y—/g¨s·êÒ½§î»ïžBËþý©¿)*r–5iÚtŬ³×ÕµªbV.W¿¾}ôá¶íêЩ³Z·ï q&(77·ØõR’çGûÃó€ŠÈ`2™L’”^D/¼âããRª'uìø ½Ø½‡î½ÇO›7n •lÈé3§µqýF¾DØ‘æW>T“&MÌ=œ%iÂA‹å7 4¿÷÷÷/öw°îîî’J±ˆ5FŒ«ï¾ÿ^WrrtêçÓš5g®$©oïÞ´”1M$?ì Ïo*¢J¶pÏ´i­©³ôÓ±cª\¹²üyDsfF¨E³¦´¹>_¢ìǵ9@šP*›H€´lÑ\-[4§5ì€ÑÄ öæc§çÔDiT€ Å*€5LFÓŸ¿ €½àù @EDV¡€ýáù @EDV¡€ýáù @EDV¡€ýáù @EDV1ü‚ÀÎðü ""«}ìôœùK4¯¼òÊ+¯¼òÊ+¯¶ÿJ‘Ád2™$)==½X;ÄÇÇëÿ=þÿ¨¹ ìòÅËT€rss3¿ßŸpÐb¹Æ Íïýýý‹ý]l»»»$©Ò­ìÜ ~j°‚2™L2 T€IHH T( «F*`óH€À*Ž˜€M#«Ð`H€À*F €í#«˜Œ °}$@`z€ì X…IÐöÀ& G¾>ªçƒ»( °‘ÍTŒ-‹-a,€=°‰HÔ¢Åòê@%زUjÞ¬©F&s/{k\_¶Ôc#ñð—Ú½}«ªV­*Iªá榠–-Ô²e¾ýoŒØÈüþêÕ«Zþv´¶îØ¡ßÿ]ýúôQÏn!ŽõÝ÷ßkèÈÑêÕ£»ºuy1ß6gggÍš>Ma©Þ#H’æ-\¨K«råÊåî†1I€l_™ôY·q£%&jÙâ…Ú²y“rssµtùJI%&0ÿË»lÉSš2c¦¾Lu|}UÍÕU#‡äÛþΦ÷45b¦Ì£æMŸ.2V»6mäèè(gggµnÕªÜÞ0$@ö L†À:{îœ:véšoƒÃíån·Ý IDAT^ªT©¢ýÃ4 ˜L&“Nœ<¥Ø¸8›0QóçD+Æù”ùÕ­cqûšõëÕ¡};=Zßÿ¦±¶lß.“ɤÜÜ\íˆW»6mÊå C`Ê$â]ÛK‹¢æÉÇÛ»Xå ƒUñ ƒ¸ÿ>W»çž/vœÚ^^:ýË=øÀý…n_¹t‰ú$WWWõîÑÝbœ'OjñÒeŠ^ö–L2饗¨~½zº÷ž{ÊÝ Ã {P&C`uîØQS¦Gèä©SÊÉÉѱãÇ5fü›Ë»U¯®“§N3lÀ«Ú½w¯ÒÒÓ•››«¤äd-X²DO<þx±ãthßN³æÌURR².]¾¬È¨ùù¶{Õª¥•o-ч[·*:&¶ÐYYY=n¼ÆŒ!__ÕñõÕ¨áÃ4jìøBç&±wô؃íبÀºÄƒÔ5¸³ >úu%''ËÏÏO_îo1NŸÞ=Ö_—/gXœÀ¼ÿK}µaÓ&M‹˜¥¬ìlyzx¨q£†š:iB±ãôîÑ]YYYê7` 233Ö·O2žZ±d±ú¿:XW¯^-PfÆìH5üg Z4kj^ײEs%>¬³"5ñqåꆡÀLþ¤?==½X;ÄÇÇ+$$„š« NŸ9-¿:~T€IHH›››yyÂA‹e7 4¿÷÷÷/öw°îîî’Êh,”&#C`l X…9@ö€¬b41Àö‘U  |0 V­{CV¡@ùPóÏIoä^£• \ «Ð |¸ï¾{ ]¿…õ`o*Q°=@Ê'GGýýoúùô/ºté’ÜÜÜäW·Ž©å XÅh$P^899é¡ "”K Ê[êrôÛ£Ô\–@%lÚ-%@Ôo@ÍUP&“IƒŠ°3üˆ@EÃX° s€ì XÅd2Q ›GV¡ÀUŒ& ÛGV1 `ûH€À*ôØ ° “ ìM$@Ž|}TÏwQ@`#›©[:[ÂX{` ¨E‹5äÕJª‡zH;ãwI’vÆïÒ#?¤õë—ËÆh$°}e’Y·q£%&jÙâ…Ú²y“rssµtùJI I•xð€ù_ÞeKž Д3õå‘#ÊÎÎ.°½8qV¯Y£Ã_~¥å‹iëæ÷t>%¥@™O>ݯAáÃ4fäuëòb¡q^}åeÅÆÅÉh4*6.N_~¹ÜÞ0&C`l_™$@6°EcFŒ¯ª¹ºjèkƒµwß¾ÛŠ1u²î½ÇO³#Õ,¨:tꬨ…‹”‘‘Qì[¶íШáÃTÇ×WÕ\]5"|H¾íïlzOS#fjÁÜ9jÞôi‹q|à~=üàCš4mºyøa=øÀýåö†!°•Êâ gÏSÇ.]ó­sp¸½ÜK•*U4 ˜ô“ÉdÒ‰“§§q&jþœÈbÅ8Ÿ’"¿ºu,n_³~½:´o§Gëûß4Ö€þaêЩ³¶¾·©\ß0$@ö L Þµ½´(jž|¼½‹UÞ`0Xß`0èûïÓˆðÿÏÞ}‡Eqíÿ ¨Q,ˆ *jzrMrM‚I®-–PQc ö^¢F¬ÑÄ56 öB³wQË5ň‰F7¿T{ £ ûûCÙ€´]DÜ]Þ¯çñ‘sæÌÌ÷ÌÌÂ~÷œñ‘×ûÍMn§œ««Îýy>ÓKÌW¯ú«D‰êÜ¡}–m¹¹UHó¿­â k'S`µjÑBŸOž¢ÓgÎ(11Q'NžÔˆQc2­ïXª”NŸ9“e›=ûöÓî½{u%.NIIIŠŠŽÖœùóõÚ«¯šÜN³&^šæ;SQQѺ¯~³Ó”»–-«¥ çkkh¨–q¶ˆ ë«#@Ü«×L·ìÈÁú°u+(`§!ŸŒTtt´*W®¬z÷Ê´®;ªKÏ^ŠOÈô潺wÓš 4iÊ4ý}û¶\œU«f M?Öäv:wh¯¿ÿþ[=ú~¤[·n©g·®éê¸8;kÉ|õê7@wïÞͰN~€5°3ÜÿJ\\œI+DDDÈÛÛ›ÈåSçΟS劕 €•‰ŒŒ”£££ÙëU©RÅä¿À899IÊ£)°`; ÉL°|$@`ž°$@`–dÏX> 0 S`¬ ˜… k@faÀY°$@`–äd ËGØûœ¬ôÓÏ?¹|,22’ ,ZŽ ¯¼ô ‘˧ ƒìì쀕áK,ò¦À‚YxÀY AX< 0 #@ր̒l °|$@`C2S`, ˜… k@fá!èk`‘ ÷ê5->pÖ°S`¬Až%@¬%a_¦b ,€5°Ï­†R'J•*¥ª¯¼¬!>U¹R%IÒ‘ƒ”›ÛÊ®½„„­ ÖÞ}_êRLŒŠ.,÷×_Ó‡­[ë­7ßÈ´ÜÜOI÷ù$*\HŸ}2<Íò‰S¦*))IãF}fU' #@Ö WG€9x@GЖukô¯_Ô˜ Ÿ?¶ûdÔh]¿~]sfÎÐ×{vióúµjÜÐSK–¯ÈÓý1lˆ~<~\;wí6. Ø¥ãÿûI#‡ µº† kðH¦À*Uª”:uh¯ß~ÿø,õ‘;‰‰šÿbªŽ?®Û·o§+7¥€à`=ö£ûÏS覺“®Î7û¿UŸÁ1l¨Úµm“a;O=ù¤}Ü_Ã?ýLÃ?ýLC}êÉÊ•­ò„1˜ `ùìs³±Ô£'œË(`Éâ ë…ïÚ¥¹3}åâì,Iâ3P­¼Û§©óéða*S¦Œ$©SûvZlÖ¾L™8AA+WiÊô:söœ\\œÕ ^=õèÚEÅ‹7©mÛÃä;uŠ*º¹I’†ú LS¾nÃF- Ôœ™¾zù¥*Y¶åÕ°¡V®^«‚ ÊóÝw­ö„!°¹þ "¿Õ¶ëUÑ­¢~ûí÷ ëÅÆ^V… Œ¯S ©¥$?¤{ÓHe4Š#+êÛ«§Ö)ò«}ò›>]W¯]ÓgcÇ™ÜÆ¥˜U®T1ÓòàÕ«Õ¬‰W¶ÉIÚ¶c‡ ƒ’’’aµ' €5Èõ)°ìììTÑÍM“ÇÓäé3tó¯¿ÒÕqqqVtt´ñõù¨(³·anýgŸyZC}|täè1“Û)çêªsžÏ´|é‚ùÚ½÷¿ Y™e;§NŸ–ÿ‚Eš>y’¦Mž¨ÙsýuæìY«MO‡S™2e$IÚ·ÓŠ `³öeÊÄ Z¹JS¦ÏЙ³çäââ¬õê©G×.*^¼¸ImlÛ&ß©STÑÍM’4Ôg`šòu6jY@ æÌôÕË/UÉ´çž}F/<÷¼ÆOš¬_xAÏ=ûŒÕž0$@Ö ×ŸòCä·Ú¶q½*ºUÔo¿ýža½ØØËªP¡‚ñuJ‚!µ”ä‡$=ñÄŽâÈŠƒƒƒúöê©5ÁAŠüjŸü¦O×Õk×ôÙØq&·q)&F•+UÌ´>:rô˜Éí”suÕ¹?ÏgZ¾tÁ|íÞû_†¬ÌvÜÜ*¤ùßZñ €5(ð¨.WÎU¯¿ZU;ï?ü;µFžòõ›£ØË—{ù²|gÏ1«mÇR¥túÌ™,ëôìÛO»÷îÕ•¸8%%%)*:ZsæÏ×k¯¾jr;ÍšxišïLEEEëF|¼føÍNSîZ¶¬–.œ¯­¡¡Z”/NF€¬AGÙø￯[¶¦[Þ³[¹º–UkïöòîØY¯U­*{{ÓGÒµsGuéÙ+Í3GÔ«{7íܽG-Ûz«ö;ïªOÿU°`AM?Öäv:wh¯W«þ[=ú~¤÷Z´RyW×tu\œµd¾¿v„ïÔ’å+lþ„aÀØî¥?..Τ"""äíí«;ñlj<|„B7m G,ܹóçT¹be`e"##åèèhözUªT1ùo°NNN’ñ¬Ìð›­+W®èÂÅ‹ò=GõêÖ¡W¬€!™)°–Ïþqm¸Bùòêе»U¯ÎÛê×»½axÀ<¶H»¶mÔ®mzÀÊ$xÀò 0S`¬ ˜… k@faÀY°$@`–äd ËGØûœ¬ôÓÏ?¹|,22’ ,ZŽ ¯¼ô ‘˧ ƒìì쀕áK,ò¦À‚YxÀY AX< 0 #@ր̒l °|$@`C2S`, ˜… k@fá!èk` ãÿûIÍ[·•{õšôˆ…c ,€5°ˆˆß< ì÷‘Ž<ëm“TÉ]L°ö¹Õ{õš9N`üqâ„jÕªir[Y%5\ïQ$Uò3F€¬½%ìÄÍ›7U¸P!“ë§NjlVyVÇaÊömÁÀXË—' M[¶iÄСr«PA%K”Рhï¾}d[Ã’‹³s†eá»viˆÏÇrqv–‹³³†ø 4«Ü”ãÈjû¶€ÀäÉ3@.\¼¨m?L³¬@G“{)çêšiYlìeU¨PÁøº¢››Yå¦GVÛ·$@Ö O å˹jžß,U(_Þ¤úvvv9ÞVV뺸8+::ZO=ù¤$é|T”Yå¦ÇÃì»5à k'S`µjÑBŸOž¢ÓgÎ(11Q'NžÔˆQc2­ïXª”NŸ9“ëûÑÈÃS¾~s{ù²b/_–ïì9f•›{¶ˆ k«#@Ü«×L·ìÈÁú°u+(`§!ŸŒTtt´*W®¬z÷Ê´®;ªKÏ^ŠOÈуÐ3Ó³[M›9K­½ÛËÞÞ^m[·Ò¡Ã?˜\nîqØ"F€¬áþWúãââLZ!""BÞÞÞ6qðœ8¡ÁÃG(tÓ†•çGçΟS劕 €•‰ŒŒ”£££ÙëU©RÅä¿À899IÊ£)°,É ¿ÙºråŠ.\¼(ßÙsT¯n³Êó;C2S`,Ÿ}~;à åË«C×îJLLT½:o«ßSXeWžßñ €5Èw vmÛ¨]Û69.Ïï’ <`ù ˜ƒ)°Ö€Ì€5 ³0` H€À,ŒX 0Kr2 €å#lŽ}NVúé矈\>I-G W^z…ÈåSƒAvvvÀÊdô%–[ßRÑ'Š_ß¾}[EŠ!XlS`Á,<ÀvˆÜ¯¿ÿþ[’tçÎm8¸Ÿ °$@`ƒÁ@lÄÍ› :pp¿âãoÿ[aO`F€ØŽÅK(>!^_~ý_ 9886ƒ 0K²€­¨Q£¶Š;—Á`PÑ¢ÅT³zm‚Àf0f1$3€­x¢Èz§¾`“³0` H€À,<` ,2â^½&=c¡˜ ` ,ò G g,T‰%€ªQ£A¯ØîÏiG4€Usrr’Ä3@€ "l `sH€›CØ Àæ6‡°9$@€Í!l `sH€›CØ Àæ6‡°9$@€Í!l `sH€›CØ Àæ6‡°9$@€Í!l `sH€›CØ Àæ6‡°9$@€Í!l `sH€›CØ Àæ6‡°9$@€Í!‚<÷®WS½ëÕ4Ó×Ä…c€‡eŸ“•®]»¦ù‹—臣ÇtóæM+VT®eËjÁœÙÆ:)‚ÚÙÙ©p¡B*Y²¤žzòI½S¿®Þ­__vvvéêî ÛnÒöOž:¥ð]»uèðº£bÅŠª|¹ròhÐ@ͼ«`Á‚Y®Ÿ Õk×éÛȃº#{{{•*YRO=õ¤&kñvûÎmܼE_}³_磢”œœ,ÇR¥ôÌÓOiÒøq¹º-sûÆ¥ƒ½½½BV,“s™2ƲØË—Õ±[%%%Yýq>Êë8?Å€mÈQÄož¿öˆÔ„1£õf5w>{V«Ö¬Í°îî¡úëÖ-EEEkkh¨¦ùÎÒž½û4aìh)\8G;=sÎ\5òðÐï5“kÙ²ºzõšVkÞ‚…:uê´éº×¯_×€ÁCwõª>êÕSµjÖP¡B…ô?ÿ¬[¶Z|‡Ý¼ySCF|ª3gϪ{—Îz§n]/î _~ûM6máŒÎÆÚ Õ¯w¯4¯-E^'̹Ž-õ 39J€ýñ¸$éÅçŸW¡B…ôÂsÏiܨÏ2­_¬hQ=ÿܳ:ÈG…‹Ѷí;´jÍZuíÔ1G;íï7+ÍkgõëÝK»öìÕÞ/¿hgmï IDATÌ2¢è Ô«{7y5jh\þfµjz³Zµtõ7nÙª‹—ÈÎÎN¥Uý?o©OÏ*V´¨¤¾!?øãZµn._¾¢J+ªG×.:qò¤¶íØ¡„ø=óôÓЯ¯^xî9I’Á`PxÄ.mÞª /ÊÅÙYÍßkª÷š4I3:æAA+WéÄÉ“êÔ¾Z·øÀ¸üµªUõZÕªÆ×ƒA[·ïжí;t)&Fe˺è=//5¯™±ý”}6ÈG«Ö®SLl¬*Wª¤ûõÕËUª¤›¦Júçî”×ýûöÑÚ tùòíÞjÒv³cJl2Û~VÞ}§¾ÂÂwª}Û6rttÔÕk×¾3B==žã¾ÿdÈ`­Y¿AÑ.¨\9Wµnñ¼6L;Së=ãÌú'ExÄ.­ß´Y.^T…òåõaëVšê;3M[9¹ŽsÒÿy} ™=¤Dñâ’¤žýúiÚÌY Ø¥«×®™´îûM›H’öîû2Wäÿ~ùE’äâìœe½ß}'IªS»–Iíþõ×_Z¶p¾vlÞ¨n;)lg„–­Ìpû çÎјOGèô™3úlì8E_¸ e hÔÈúå·ß4Í÷ŸÄÍö°pÍœ3WÏ=óŒÖªNíÚš;¡v„ïÌr¾þö[I÷>ÌÏÊæm¡š·`¡Þp]kC‚Tíõ×å¿h±¶lKŸ$8vü¸ügÏÒ°AuòÔ)ùúÍ‘”öƒç=aÛ3ü ú'´t¾¿1ù`Îv3cNlÜ~V¼Û´QbR’ÖoÚ,IZ¿i³’ µû°íCõý—ß|£i“&jeÀrU(_^3gÏUÄî=9®gjÿHRÄî=ò=Gå\]²|™¦Mš¨½ûöåÊuœ“þÏëc€Ìä(òÉÁzþ¹guãF¼víÙ+ßÙsÔ®sW“’å\]%I—¯\ɵƒ¸pñ¢æ-X$;;;õéÙ=˺ׯß$9•.fyÊÛ|€sÇvÞz²re.\Xžï6$EÞO¢¤Ö­S'wpÐîîÆe];uTqUëMIÒÙsçŒe›ï':´ó–ƒƒƒZ·ü ÍòÌ\½zïêÔϱÈHhX˜$©uË*îà ¶-[J’¶Ý_žZ÷.UÜÁAuj×–$ýyþ¼É±ïÞ¹“r´Ý̘›·Ÿ· åU¿n…îSTô…îØ¡&eš43µïûôè®2eœäTº´úô¸wþ¥$YrRÏœþIY¿oÏ*SÆIeÊ8©o¯žü:67þê 39šë߯¼¬sf+öòeüþ–)>>^KW¨AýzY®{áâ%IÙ€oªá;µpéRݹ“¨aƒ|Tý­·²¬_º´£bc/+&6VÝÜŒË÷„mO—üøå·ß´"(X'OžÒøx I÷œý 2eœ$I…S=×$åS¦mJYÿ^.J’:÷HûAoTt´IûùÊU(_>Óz1—bîÕwt4®'I11±éê¦ì§½½}ºýÌŽ““SŽ·›ù9bzlÜ~vÚØVÿýò+ 9RÉw“Õ®Më ë™Ó÷)I=Ir-[6Í1䤞9ý“²~¹rÿ´]¾\¹G~›ÿGu ™³²‹³³šy5Ößé’¤[·ne»ÎÖÐ{ßâ7õÖÌÄÅÅéÓ1ã4kî={dZÇœ¾_¸t™âââwõª-].IjõAó×3Gë÷¦[¼l¹â®^Õ•+qZ°di®]Çæö^d&GS`98Ó²€@]»~M‰‰I*]ÚQÍšx©[çNéêz4i¦B… ©d‰z²re Tþ iاŸÉ©tiyg2]RN´xÿ=9–*¥[¶¨c·{Ä¿òÒKjÕ¢E–ë¥ÞÿˆÝ»µ< Pw““U²dI=ûôÓÆzm[µ”Á`Ю={µ#|§Ê–-«¾={èƒ÷š™µŸ]:vP@ÈJã>fÛÜÚnNc“›Ìéûºµkkä˜±ŠŠ¾ ggùôï§Fž9®gކïênò]­ß´Y»õPE· z¿iSþሠ(ðÐ×±¹ýŸ×Ç™±3ÜŸÓ'..ŽhfHIØe—0µ^n9sö¬zôí§J+jÅâ…V[[8GÊ£øz5`åÆMš¬ßOœPbb¢þ<^sÜK´kÛ†coÙÀº5¨WW~sæéÔ™3*\¸°žîY=JµjTçä[LlS`›EØ Àæ6‡°9$@€Í!l `sH€›CØ Àæ6‡°9$@€Í!l `sH€›CØ Àæ6‡°9$@€Í!l `sH€›CØ Àæ6‡°9$@€Í!l `sH€›CØ Àæ6‡°9$@€Í!l޽¹+DDD5 iذ!A`uìs²’··7‘ò‰¸¸8‚Àê0°9$@€Í!l `sH€€ p¯^“ ÐH…€ÇŠŒ< ¹–1 ší?_u=W}ÏFz§‘—-]fÖú–^­C‡©®‡§êzxjàÐaŠŠŠ6¹ÜÚ?»òÏ!s¯¿¼Ø?IºzíšÞmÜDwÓ,òɈ4¯ïܹ£¼tõÚ59x ×nhW®\Ñ”é3Ôôƒ–z«vÕóh¨þ>ƒµÿ@¤E߈³JåF‚ȽzMµònŸ®Ï ƒZ~Ø.Í6RŸg^M5fÂçiîeyÜ×oFNœ<¥ƒ†¨výªU¿úù Ò'NXE?'$$hîüjÞº­jÔ­¯z 5xø'úþÐá û©ZZòðjª‘£ÇèRL ¿ÙÜ—k M[¶ê»ïiU`€V®PäwßkKh¨±O£#¤ùgNü|ýf+11QÖ¬ÒúU!:uúŒ¶mßa3ñûlÜ8½ðÜóÚ¾i“¶oÚ¤çŸ}VŸgr¹µvå©ÏŸœ\y±’TÚÑQUÿýоúúã²ë7nè«oöëÚµkÆeÿýò+½Zõß*íè˜k7³˜ØXuêÞSEŠÑÜY¾úfïnmݰNm[µÔêuëòýÍþ‰'Šè›o¿M³ì˯¿QÑ¢O¤«›r®­ \¡Û·okÚÌYY¶ý¸¯ßýyþ¼z÷ë¯ÿ¼õ†¶nX§mÖ©æþ£Þý?ÖÙsç,¾¯>5Zׯ_ל™3ôõž]Ú¼~­7ôÔ’å+2ì§Cß~£UA*ë⢑£Çò› À}¹– S¿>½äV¡‚Ü*TP¿>½º=ÌX¾Èžê׫«%ŠË¡X1uhç­ÿýô&¯oéåóçø©V*V´¨œJ—–Ï€þ:rìÇ\‹ßWû÷kØàA*ãä¤2NN>d¶„n·™øýþÇ uéÔA%JW‰ÅÕµSGýþÇ “Ë­ýø³+Øó'/÷¯Y“&Ún|}üøÿ”œœ¬ÿ÷¿ÚÛ±CÍš4‘”ö›ïß:¬vº¨zzjÒ¼…6oÛf,KNNÖÒjúAKÕóh¨q'éÖ­[Æò‹—¨qCO úx€ž~ê))RD¥J•ÒÛµkÉßïŸðÝ«×ÔÊÕkÔø½æªV£–$éNb¢fÌò“‡WSyx5ÕŒY~iF±dôÍýGM‡èÝÆMTß³‘¦ÌðUâ£`r"eŽüILLÔ”é3Tß³‘<¼š*0de¶muîÐAA!i–«KÇŽ™®SÖÅEŸ ¢¿Ë²íÇ}ý>hÑ’ejÓª¥:x{«L™2*S¦ŒÚ{¨6-[hñ²å&÷ëÙsç4l䧪ïÙHo7ðÐ#Ó$òrÒ¦8rô˜|ôWåJ•T¨P!•vt”GƒZ²À?ã7òäâ쬞ݺê—_å7€ûr-ròÔi½\¥ŠñõKUªèäéSÖ½uë–֮ߠ7«¹›¼¾¥—?èÐáôÂóÏ¥YöN#/Õ¬÷ŽÚ´ï ÕëÖ+99Ù¬öíììÒü|òÔI›‰_íš5¼r•Ÿ À•ª]³†ÉåÖ~üæž_æ^y¹oת©_~ýUqW¯J’Ž?®ÿyKÇŽßK€ÄÄÆê÷'õv­ô>?^Ý»vÑ×{wkÙÂi’¤«Ö®Õá#G´È®¶mÚ ¤¤$-X¼ÔXþmd¤š5ñ2)^?=ª åKõCä½ËVèä©Ó X®€åúãÄ -4ëxðûCZ µ+ƒuöì9- zèûjʈŸGÿ, ÒÙsjíÊ`…,×Èì§øjP¿žâ®^5&¢9¢ë×oèzuz?÷õû ïR“ÆÒ-oêÕXßþÁäãþé(µiÕJ;C·*|ëf•uqÑÜù ªLñ†»»>ÿbªŽ?®Û·og[?99YW®\ÑòÀ ½òÒKüfpŸ}n5tëÖ-/^ÜøºDñâºyó¯tõR¾]ëTº´V,Ydòú–^žÚ¯¿ÿ®©3|å7cºqYʇ—wuâÄI͘姨èh õhRûµkÖï¬Ùìó±¤{Sbýõ×-›‰ßÐA>êÚ³·ñÛÙåË•SÀÒÅ&—[ûñ›s~åäúËËý³··—gƒÚ±Kí>l«cÇk`¿~ò›;O’´=,\ ßm {ûô·Ÿ‚í{9VWãâT®œ«Æ|:ÒX¶iË6Íœ6Un*H’}<@ºõÐà$IW¯^S9W× ï7©¯AI6x\œ¯Ã""4{Æt¹–-{¿|°ÿD}zö0¹† öQYãù:hØpõîÑý‘ܸw„ï”ߌiÆí ]yáB…ôR•iò„ñ ݱÃäö‡ò‘Aµhó¡Ú¶ï¨gž~ZŽ©žŸ`íñ;a¢7ôÔW»wé«Ý»Ô¸¡§ÆŒÿÜärk?~Sϯœ^y½Íš4QhX˜¯ªÿ~E×oÜÐÄDm 3Nõ YÓ¦èÐáôa§.jÞº­¾Mõú /ªEÛÓ< ;õŸuñÒ¥t÷›Œž›ò`¢$6ö²*º¹_W®TQ1±±fÝS¯_©¢›Ùë›#&66Ýþš¢i/ýß/?kç®ÝúãÄ 5õjœa½”{w쬂 jøÁéÊRøþ¸¯ß•vtÌ0þ±—/Ë©ti“ãüó/¿ªwÿªçÑPîÕkêíн|9Çý`ooŸfjµwîÜI“ˆrppPß^=µ&8H‘_í“ßôéºzíš>;.ÃóûÈÁÚ»3L­[¶Ô´™3ùÍà¾\K€<ûÌÓú¿_~1¾þù—_ôìÓÏdX×ÁÁA¼?Ô¯¿ýnòú–^.I»öìÑgcÆiú”Érýµ,ãeWÀN… 6¹ýR%KjÒøqúrw„v‡mW‰%ôÖÕl&~ÇŽW×ÎÒ<# õ3#²+·öã7çúÉÉõ—×û—’ü ݦW^~Y’ôï—_ÖÚõT¸pá “ƒ’ô¯_”ïÔ)úïÎ0 ñ¨q'ËÊ—sÕöÍÓ|è{øÀ~cyÍêÿѶí;LŠWêéä$ÉÅÅY磢Œ¯Ïýy>͂… ëï¿ÿ6¾¾råJº6S¯>**Ã9ñà¾J÷žÍ‘z{ž2©­Â… É»M?AíÚ¶UáB…2¬—ß=á;4qüØ4«OK¹~ôÖ›ohGøÎtË·‡…ëÍT÷ÍìúuĨÑjæå¥­×ëðýÚ·kgš© Íí‡J+ê÷ßO·ü·ßÿH—”KÝÿÏ>ó´†úøèÈÑc™¶]ÚÑQ]:uÐñÿýÄo6÷åZ¤iãÆò_¸XQÑÑŠŠŽ–ÿÂÅjÖôŸùøGŸ ÓgÎ())I—.]Ò¼…‹ô†ûë&¯oéå!«WËož¿Λ“áì#Gщ“§”˜˜¨ÓgÎhÜç“äÑ Éí;^—bbŸ ˆÝ{´"(X=»u³™ø½øÂó Q|ü½g‡è_/¼`r¹µvå{ýåÅþ=8O3//Í]°Po¸ß{ÖO5÷×µhÉR½—Éè”ëäÔéÓJJJºwƒJõá«-ôùä):}æŒuâäI5ÆXÞ§gm ׬9suúÌݾ}[7âãõÍþo³_#OMŸé§K11º£é³f©‘§‡±ü¥ýKA+WéÖ­[ŠŠŽÖÄ)ÓÒµáë7[1±±Š‰•¯ßly5j˜e|2zwFK•Òé3gÒ,kÜÐ3ÍöfÌò3ù\éÚ©£}ûºtìko$ûú}P¯îÝ´vÃF­\½FW®\Ñ•+W´rõ­Ý°QÝ»t1¹_oýý·T´hQ]¸pQ¿˜òPýжu+M˜ÿâ µnÙÂX¯gß~Ú½w¯®ÄÅ)))IQÑÑš3¾^{õÕLÛ¾~ýº‚BV¦{ö@~–kÏiùAsEEG«]ç.÷^7o®æÍšËëÔ®­£ÆèÌÙ³rrrRíš54aì“×·ôò™³çÞ[þa»4qÙ¿o¯Š-ªwêÕÓgcÇéìÙ³*[¶¬zx¨g·.&·ÿæÕÔ©[Å'$赪U5kúT=õde›‰ß„1£5Íw–š|pïCÀWÿýoM;Úärk?þìÊ¥´˜§üœò-üǽÇŽ×kU«¦Ù߯Êož¿ªÝOtVs]wÕøÄ@jõêÔÑÐ#}ᢞyê)M?ÎXöaëV*PÀNC>©èèhU®\Yõîe,/_®œ—.Ñ¢eËÔ§ÿÇŠ»zUÅ‹—ûë¯)`Éâ,ï_=»u‘ß\uèr/©èÑ ztýçúüô“áúü‹/´<0HeœœÔ¥S}õÍ7iÚxë7Ô®S%%%©¡‡‡ºuéœéö2ŠWF ‘#¨kçŽêÒ³—âãŒýݽk͘å§6í:ÈÞÞ^Û·Ów‡=¶7’Ç}ý>èÉÊ•µhÞÍñ_ ‹—è¯[·äP¬˜–-Z˜æ¾™]¿ŽýìSÍœ=[Ÿ|6JÎÎeÔ©};íÝ÷¥±ÜÜ~hÝâ=ñDÍš3Wçþx_çýïÑßùÀüñôUÊ¿·xXĵ“QýÇuŸùýê7ÐGµê7PæïikèvN°@ŒyÄnÞ¼©Â… ˆ<°iËV}÷ý!­ ÐÊÀŠüî{m ÍÛ‡9xà±|²j:µo§ÿF„kMp ,¨1>Ï1ç¸8®¼>VîëÖsoDÎû*åß«eó÷¹vR9{&^¾m‹—.Ñw‡qò€z$ ;‰‰š1ËO^MåáÕT3fùéNb¢$©{Ÿ¾ŠØ½'Mý‹/ɳi3%$$ȽzM‡èÝÆMTß³‘¦ÌðUâýuSþè6òSÕ÷l¤·xhȈ‘ºvíš±<11QS¦ÏP}ÏFòðjªÀ•YîkvÛ{ðÞ̶ò­ÄÔßpÍhYV±I©»rõ5~¯¹ªÕ¨e\¶~Ó&5kÑJÿy»®Z·k¯c?þ¨m;v¨y붪^§ž:÷è©3gϦ;6S¤®ç^½¦6lÚ¬&Í[Û=qòT–m¦,›ƒ5bØPµkÛ&OÎ¥QãÇ«{×.úzïn-[¸@ÿûéÿ2½˜zî§¾dÖΣ>®¥ËWèÂ…‹Z·*D«‚ôýáÃ9¾¯dwo^µv­9¢EþsµmÓ%%%iÁ⥙¶—] srnš²/öEf}“Ù9aÊ}Ö”÷‰¼Œ{FïI{/ÏNVÛ4å¼Ì,¾ô—yï'ÛÃÃUÍýu•uqyì׎)÷ÁéR‰þ@IDAT¼z8tø]‰‹“gÓfªïÙHc&|®øøþª ôH a6ØG®eËʵlY À/Q¼¸nÞüë¡úÞœí›Ã”XåtÛ¿þþ»¦ÎðÕðLÎýì®ÁÇóìΉmÛÃ4|È`UtsSÉ%4Ôg`š¶×mب‰S¦jÎL_Õ«óvžK Ú+ör¬®ÆÅ©\9Wùtd–10åÜÏè>‘Gy\á»viˆÏÇrqv–‹³³†<osdwoÞ´e›F *· T²D úx€öîÛ—é±fÜœ›æìKv²;'²ºÏšò>‘—qÏè\4§/r"«óß”óÒÜ÷±üÔ_¦¾Ÿ$''+(d•:whoòþçŵ“•¼z¸z횢¢£µ&8H×®Vbb¢|ýfóWX ûGÑhlìeUts3¾®\©¢bbc¯»wé¢9þþjèñ®.YªÎÛë‰'ž0–§^·RE·4ëþü˯šíï¯ß~û]7âã%I ü“lj‰M·íìdµ½Ô²ÛvnÄF’ʹº¦[ÏÙ¹Œñç”X•)“vÙíÛ·s¥ÿ¦Ý2NNjÒ¸‘/[®AP'§Lëæ$žYõUÑ¢E• GGGIR|B‚ŠåJßç´~nÅêÿÛ»ó(;ê2oàßY‰BÒ! ‚  /[BœIˆÌ˰%‚’ AQdQ˜a“5¬†-¶€ #FVAw< B È‚dß:¼ƒY{¹ó‡¦§;éô½Ýétwn>Ÿsî9}»–ßï÷ÔSUI=]U¥¶ýò+¯ä‚ ÿ9—\tavÿØG7¸®bû`GżXN,\´¨Ù}úžéÓ3úˆQù?ŸøøFí÷-×µW\žÛ¦Þ™[nŸšm·Ù&ßþæ™þ©OmTî7u(E[Žkñâ%Ù~ûí›\wK;6Ï_° Ç~öøF¿kîxP,†­ÉÍÖö¥59ÑÜq¶”óD{ƽX.¶Å¹q]͵YJ^¶ô<¶%m¯RÏ'¿|æ™|x§²ËÎ;—ÜÿöØwšÓžçˆ³Îüzúþíøòío~#ãÆŸ:ŸMrHÿþÛeÎܹõßß=§Ñã>}ÀˆtíÚ-7ÜüÃÌœõzÆŽÓhù†ËΙ;·Ñ²çœAF•G~üP^~ñ…üê©'=Êg@ÿþ–Ÿ=gnÑþ6×^CÅÚ®¨¨ØèØ”ºžŽÒ½{÷¬ZµªþûÒ¥KMÿ¯?¼•GfüØQ1/–ƒÌ»³7§Ûxs~ñô3EßýÓÖãÚc÷Ýsõ.Ï3O<–³Îüz.¼øÒf÷çRrÝåJ=.´å¸ú÷ß.óæÍkrÝ¥*vl±Ç¹û¾û³råÊÌ7/7xïÈÊ•+sþ…å’‹.Ì?øéœ{ö·sö¹ç7úKÙ†}*Ï–n«#?<7M¹5sçÍËÜyórÓ”[3úÈQµí[›+ŶIKcU¬í{§OÏäoÊ”¯ÏžŸøDÑ|hnìȘˉÑGŒÊW_“¹sçå¿ß?W­óÈ‘äö)7ç‘3Ö{¦ý¦×w/ø^þôöÛ©©©ùëµÁEº¦Ž ¥äþº6t|Ù”ã:ìàCrõäë³xÉ’,^²$W_w}Éǃu;6;öØüË¥—çíwÞIuuuÞúãsÎùßÛ`ߊŰ5¹Ù’¾Û6ÍåÄÆžCÛ;îÅŽ'­Éç9_ËËÖìK[Òö*å\ö‹ÿ/={ô̾{ïÝ¢íµ©÷bÿÎj¯sÄÑG‘k&_ŸªeËRµlY®ºvrF޾Éÿ @Ëm’G`M:yB&ßpSNœpr’äàƒÊ)'4š§K—­²Ó‡>”ÑGŒZoù¿6,Ÿû„ÔÔÔäЃÎÉNªŸöýóÎÍ5×]—³Ï;?Ûm×/_8ásyúWÏÖOÿâÄ ¹êÚÉùÌçNL×®]óù>—ß¾ôRýôWgÎ\ï?ô͵×P±¶'žôùL˜tjÞÿ/|ÿF)±ÙTšúÏxKßrîÙßÉ¿\vY¦N»;ý*+3á 'æ¹çŸO’\våU9þ3ÇÕß}0rĈ̞='—]yU.<ÿ¼õb_,žMin[=fLæÎ›—Ïô×xŽ3&cFn“m_êü c¼öçµ1nØ~±Xµ´ík®»á¯c>þs–yáWOgë^½š{sû`GżXNœtâ YµjUN9í+Y¹re&ßôݹï;¶×9âèÑGfþ‚7þ„ÔÕÖæ€ÃsÖ׿^RŒh_…¿Ý·_UUUÒO>ùdÆßèwï¿ÿ—5v\~õTé/„>ó[ßÉa‡¼ÞÝCÿaÿV¿¼»_:ý«9åä“óÉý†¶K{l8öÚïØ¶7´–SÌ«mÇõ‡·ÞÊ7¿sNfüäaÛN³-Ê)/í;bÔ™•ú€Î òoï[ÞèHuuuîàÁüö¥—sóõ“‹._WW—ŸþlFxèáºÛn¹è‚óKšØþ#²ýàÁ¹âÒK\x…`¤%¶<8'Nübª««sàÈrz+·òèmò, |¹Øœ¬½ÄŸeG(; @ÙQÊŽPv@€²£” ì(€eG(; @ÙQÊŽPv@€²£” ì(€eG(; @ÙQÊŽPv@€²£” ì(€eG(; @ÙQÊŽPv@€²£” ì(€eG(; @ÙQÊŽPv@€²£” ì(€eG(; @ÙQÊŽPv@€²£” ì(€eG(; @ÙQÊŽPv@€²£” ì(€eG(; @ÙQÊŽPv@€²£” ìT …B’TUU‰°Y«¬¬Lâ  )€eG(; @ÙQÊN×–.ðæ›oŠÐ!vß}÷’æ«( …$©ªª*iÊÊJÑÚ])µŒµuŒ®›båÉ;@€²£” ì(€eG(; @ÙQÊNW!€ŽU(²pñÂÌ_0?+V®Zmë^[gð ÁØ`***ä]'‰u]]]Þzû­,{oYjjj¯…ºvíš¾}úf·]vK—.¥ßסláâ…YZµ4{ï¹wúUöZmiÕÒüçýg’dЀAò®“Äú­·ßÊš5k2lÈ0±ne¬ßxó¼õö[ùØ®+y9è`óÌÏÞ{îm·Ù6kÖ¬ZmÛm¶ÍÛ#3_ŸYô¢¼¼k¿X/{oY† &Öëïþñ¼üû—[´œt°+W¤²oeV¯^-l”ºººTö­,é‘Vò®ýb]SS#Ömë–>>L:ØÚ÷ Á MsJÞ‰õ–ë†@ ( .ŽÒf¹$ïÄzKŽõZ ÐÁ*R‘B¡ººº^ׇ–gŸzb³ŒÃæÜ÷ΤP(¤"íšw[êvßÜb½%äuC ÐÁ***RWW×fG;ëEÖÿ{ب<óÄc›eßÛ3m±ýK},S[æ]9æl9ÆzsUj¬R€N¢”G¼¼;{N¦N›–WgÎÊÊ•+³ë.»äøÏŒËÈ#Z´žŽðôãÖ÷í ÃÈÓ?Úª´Ö†Úlhùòå™þ£‡òëßü&K/I÷îݳ÷^{fÌQ£3tß}Û4›SÞmŒÍ9g7·XoêüÝÜ(€@G«(íýsçÍË7¿sv>3nlN;uRúöé“·þô§üèáŸä€áÃëçÛ\.&7ÕÏMÝ÷bëÿçË.Ï€þýséEfà€Y¾|y^93÷Ü?=CöÙgó‰kEÛåÝÆ(·œí̱.—üÝèX7 líûŠ]vï}sÔèŒ;fLýïöøØÇò½sÏi´ìÚŸ«««sÛwåÙç~$9ðÓ#3iâ„tëÖ-IòûW_Ë­S§æÝÙsÒ·OŸœpügsø¡‡Ô¯ãþ”ÇŸz*Ë—¯ÈðOýC¾úå/¥gÏžëõë¤SNÍEœŸ?¼S’ä©§ŸÎ!”$yçÏïæûÿrq¦Ý~k>bt~ñèŒ|Äè$É?:2Iò‹GgÔ¯kÆ£å‡β÷ÞË®Ù%ßüÚÙùÃ.iøˆÑùúé_iv¼7ßz[ž{þ…tÝj«Œ=fLn¿ó® ö½áöoÉ{)6åEùΚ³m¥3ź=ò·wïÞíã–Æº¡.N/б***R[[[ÿŽ€ }~ÿêkùô#š'IýÏ÷=ð`ÞùóŸsãµ×äÆk¯ÉŸÞ~;÷=ð`ýô˯¾:ã?s\~òÀý¹êòKóoügý´‡ÿõ§ymæ¬\qÉÅ™vÛ-©©©É]÷ÜÛd›û ’™³f¥®®.‹-Î?¼%Ë—/O]]]^›53ÆiÔ·'g<’$yrÆ#yrÆ#úþÒï^É•—]’‡î»'ŸÜo¿L¾á¦’ÇÓpìëþnCm®ûÙ{¯½rÍõ7fÖ¿ÿ{V®ZÕä<ÿ|éå=jTî»kjîzGúõ«ÌwÞ•Þ½{gÄðýóóÇo4ÿÏ"ÿøéOgë­·nÔÇbã½wúY¸pQn¹ñúÜtݵùý«¯59Æu?µµµ%¿—¢”¼Û˜OgÍÙ¶út¦X·GþvDŒ[ë†@ Xû×áÍ}þûý÷SÙ·o³ó4\×3Ï>›Ó&’~ý*Ó¯_eN›4)Ï<û\ýô­ºl•%K«²ì½÷Ò»íræ§×O{üɧrú—OÍÀÒ»wïœ2qBžñÅ&ÛÜoè¾™ùúë) yúÙgÓ½{·<ûëçS(2sÖë:dÈz}kjÌIrÆi_Ê€þýÓ£GŒstþðÇ?–<ž ­³¹éë~¾ûí³²ãÛçÆNɸñ'd¤SsÛÔ;ó—åËëçùáõ“³÷^{¦{·nÙzë^™pâ yé•WR(2fô‘™ñØã©©©I¡PHMMM}ü‰sÔè&ûÓÜxõÜs9õ‹SÙ·o*ûöÍ—N9¹ä\i˼ۘOgÍÙ¶üt–X·GþvTŒ[{÷ŒG`@«¨¨hô×ðòÁ~0K–.Í ›oíz–VUe@ÿõß ˜¥UKë¿_ðÝs2ýGå¾éäü@¾|Ê3lèÐ$ÉÂE‹rÊi§7ÙÏuíµçž¹é–[SWW—gž}.ß8ãŒ<øðsÈ?”7Þ|3g~õôFé¿n?ÚvÛmëß­[·¬Y³¦äñlhŦ7Ô³gÏœ8þøœ8þø …¼;{N~üÓŸæW] Ï?/Iò‡·þ˜©wß?þéíüå/I’téÒ%uuuÙaûí³Ó‡>”çóbFŽž_¿ð›||ݳ]¿~MÆ øxû×Ð@Ic¨««+ù®„RònctÖœm+)Öí‘¿ã–Æº!èJ¹8ºï^{å¹_?ŸãÆ[t]IRÙ·2óæÏÏNÚ1I2wÞÜô«üß ñÙeçœwö·S(òò+¯äÚëoÌ=SoO’ è¿].ºàü 0 Éu7Ô£{÷ 80Ï=ÿBºwï–aC‡äþÌ‹ÿöÛ 8(Ý»w_ïâÿ†.š6÷»bãéÞ­[V®\™=z$I–½÷^Im6çC;îI'd©_®_öò«þú¦s¾uVzo½u–¯X‘ñ_˜P?ýè#È}>˜û*ÌøyNûÒ¤ aŠwþ‚Ùq‡’$óæÏßà2Åb¸1y·1:kζå~ÛYbÝùÛ1Þ˜6< :ØÚ óÅÿ2þ³Çåg>–ŸþlF/Y’5kÖäÍÿúC.½âª&'4rÄðÜzÇÔ,^²$‹—,É-wLÍÈÃë§_q͵ywöì¿=î&©èò¿/j>üÐCsÃÍSòîì9©®®ÎÛïü9?¸úš ömè¾ûæö;ïÊ#G¦P(äÀÈ”ÛnÏÐ!û6Ù·m>øÁ¼;{Î…Ôšñìºë®ùÉ#?ËÊU«²`áÂÜøÃ)EÛ\÷sÎßËó¿ùM–-{/Õ55Y°paî¼çÞ|âã{ÔϳjÕªôêÕ3=ºwÏÂE‹rÃÍÛÙwŸ½³bÅÊÌxìñôìÙ3Ùyç’ɵîxo»ó®,]Z•¥K«rûw5¹ÌºŸ–Þ•°)YÔ™s¶->)Öí‘¿ã–Æº!w€@«HEIϸû4Ù·±ÇŒÉ·Ï=/Ë—/ÏÏþÑzÓ*u<_9uRnœ2%ýø'éÓ§OÆŽ9:¿}éå¢m6tü¸qyô‰'rÓ”[³fÍšôíÛ7ÆÉ7¿vÆÿ¾·ã+§åŽ»¦åò«®Ieß¾9æ¨Ñyñßþ­Qß:rTnšrk.<ÿÜõÆÔT<64ÞÛ¦Þ™ÓÏüF¶êÚ5G~X^›5«hž …T¤¢Íònctæœm )Öí‘¿ã–ÆºQÜ ëYUU•3 t€ß½ú»ì³ç>Y½zµ`°AïüùÝ\zÅ•¹õ¦š¯Gyíõײ߾ûÉ»ML¬;_¬“¤²²2‰;@ S¨­­m÷÷ÐùMvwŽ=ú¨TW×䎻¦åï?9¬hžÔÖÖÊ»vÜoźóÅz-è`kßàâ(ëê¿ÝvùÖwÏKMMMþnØ~9þ¸ãJz zKÞK±©ònìøŠÎóãé÷mÖÛ§³ÄzKˆ¹w€Àf¨"©­­m—çè³yuØ¡uØ¡~W,OjkkK~/Ŧ̻‡ï¿·è<›{Îw–Xo 1/5Ö )€@'PWW§B›å’¼ë-9Ök)€@ëÕ«WV¬\‘Ý{¸@ÊF©¨¨ÈŠ•+Ò«W/y׉bÝ£G±nƒX÷èÑ£EË)€@Û~ðö™;onúlÛ'={ôZmÕêUyïÿ¿—¶ßAÞu¢X8( .Hß>}ꕱ^öÞ² 8¨EË)€@ëÛ§oêêê2Áü¬^½Z@hµ=zdð ÁéÛ§ojkkå]'‰õÀS[W› —õmµÕV4hP˜êêê’—«(üí~›ªª*Q€Ò­[·tíÚ5]ºt Z­®®.555%_$–wíëž={¦{÷¨¼* Y³fMV­ZUÒü•••IÜBuuu‹þ²äÝæeÕªU%_À§m(ëeG(; @ÙQÊŽPv@€²£” ì(€eG(; @Ùùø*†JîÄwIEND®B`‚antimicro-2.23/other/scripts/000077500000000000000000000000001300750276700162445ustar00rootroot00000000000000antimicro-2.23/other/scripts/build-sdl-lib.bat000066400000000000000000000012141300750276700213550ustar00rootroot00000000000000REM Build script used to compile SDL2. It is mainly a reference for which REM options need to be used in order to compile. REM Move to directory that contains the SDL source directory. REM Just use a static location for now. cd "C:\Users\Travis\Downloads\SDL2-Source" REM Make build directory and change cwd to build mkdir build cd build REM Generate Makefile with specific options cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="%TEMP%\SDL2" -DSDL_STATIC=OFF -DVIDEO_OPENGLES=OFF -DRENDER_D3D=OFF ..\SDL2-2.0.4 REM Compile mingw32-make mingw32-make install REM Get out of build directory cd .. antimicro-2.23/share/000077500000000000000000000000001300750276700145365ustar00rootroot00000000000000antimicro-2.23/share/antimicro/000077500000000000000000000000001300750276700165235ustar00rootroot00000000000000antimicro-2.23/share/antimicro/blank.txt000066400000000000000000000000001300750276700203410ustar00rootroot00000000000000antimicro-2.23/share/antimicro/translations/000077500000000000000000000000001300750276700212445ustar00rootroot00000000000000antimicro-2.23/share/antimicro/translations/CMakeLists.txt000066400000000000000000000032121300750276700240020ustar00rootroot00000000000000# This will ensure that the *.qm files will be stored # in the right place within the build directory. file(GLOB antimicro_TRANSLATIONS antimicro_*.ts) list(APPEND antimicro_TRANSLATIONS antimicro.ts) file(GLOB_RECURSE antimicro_BASE_SOURCES ${PROJECT_SOURCE_DIR}/src/*.cpp) file(GLOB_RECURSE antimicro_BASE_FORMS ${PROJECT_SOURCE_DIR}/src/*.ui) if(USE_QT5) if(UPDATE_TRANSLATIONS) # if(TRANS_KEEP_OBSOLETE) QT5_CREATE_TRANSLATION(antimicro_QMFILES ${antimicro_BASE_SOURCES} ${antimicro_BASE_FORMS} ${antimicro_TRANSLATIONS}) # else() # QT5_CREATE_TRANSLATION(antimicro_QMFILES ${antimicro_BASE_SOURCES} # ${antimicro_BASE_FORMS} ${antimicro_TRANSLATIONS} # OPTIONS "-no-obsolete") # endif(TRANS_KEEP_OBSOLETE) else() QT5_ADD_TRANSLATION(antimicro_QMFILES ${antimicro_TRANSLATIONS}) endif(UPDATE_TRANSLATIONS) else() if(UPDATE_TRANSLATIONS) # if(TRANS_KEEP_OBSOLETE) QT4_CREATE_TRANSLATION(antimicro_QMFILES ${antimicro_BASE_SOURCES} ${antimicro_BASE_FORMS} ${antimicro_TRANSLATIONS}) # else() # QT4_CREATE_TRANSLATION(antimicro_QMFILES ${antimicro_BASE_SOURCES} # ${antimicro_BASE_FORMS} ${antimicro_TRANSLATIONS} # OPTIONS "-no-obsolete") # endif(TRANS_KEEP_OBSOLETE) else() QT4_ADD_TRANSLATION(antimicro_QMFILES ${antimicro_TRANSLATIONS}) endif(UPDATE_TRANSLATIONS) endif(USE_QT5) add_custom_target(updateqm DEPENDS ${antimicro_QMFILES}) install(FILES ${antimicro_QMFILES} DESTINATION "share/antimicro/translations") set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM true) antimicro-2.23/share/antimicro/translations/antimicro.ts000066400000000000000000011263521300750276700236130ustar00rootroot00000000000000 AboutDialog About Version <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Originally developed by Travis Nickles &lt;nickles.travis@gmail.com&gt;, now maintained by the AntiMicro group at https://github.com/AntiMicro.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Contributors:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;"><br /></span>Zerro Alvein</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">aybe</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jeff Backus &lt;jeff.backus@gmail.com&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Arthur Moore<br />Anton Tornqvist &lt;antont@inbox.lv&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7185</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">DarkStarSword</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">est31</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ProfessorKaos64</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">qwerty12</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA0</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Translators:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VaGNaroK &lt;vagnarokalkimist@gmail.com&gt; - Brazilian Portuguese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx - Chinese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Belleguic Terence &lt;hizo@free.fr&gt; - French</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Leonard Koenig &lt;leonard.r.koenig@googlemail.com&gt; - German</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phob - German</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">tou omiya - Japanese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Dmitriy Koshel &lt;form.eater@gmail.com&gt; - Russian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jay Alexander Fleming &lt;tito.nehru.naser@gmail.com&gt; - Serbian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">burunduk - Ukrainian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Flavio HR &lt;flavio.hrx@gmail.com&gt; - Spanish</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA - wazaaaaa00&lt;@&gt;gmail&lt;.&gt;com - Italian</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> Info Changelog Since December 30, 2012, I have been working on antimicro in my spare time. What originally started as a fork of QJoyPad and a way to learn proper event-driven programming has turned into something much bigger than I originally intended. Although I have spent a lot of time learning new techniques, finding out more about the domain of KB+M emulation, and spending Friday nights bashing my head against my keyboard, it has been a fun and enriching experience overall. The need for this program came from me using similar programs on Windows to play several games that did not provide native controller support. Although some alternatives existed on Linux, there wasn't really anything that I felt was good enough in terms of functionality or in-game controls in order to really enjoy games that I wanted to play with using KB+M emulation. QJoyPad was the main program that I had used in the past although it had aged a lot and it didn't provide some basic functionality that I thought was essential. The project was dead as it had not been updated in several years so I decided to make my own. Since then, I have tried to find out what the other programs do right and then improve upon it. I have also discovered some neat tricks along the way and I have learned more about how native gamepad controls are implemented in some games than I ever really wanted to know. Although there are definitely areas where this program could improve, I find that this program offers the best in-game control experience for playing older, and some newer, games that do not provide native controller support. Development of this program is not as high of a priority for me anymore. This is mainly due to the fact that the Steam Controller works pretty well for the task of playing PC games compared to using an Xbox 360 controller. However, it does look like there is still a reason for this program to exist for a while. Copyright: 2013 - 2016 Credits antimicro <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">GNU GENERAL PUBLIC LICENSE</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Version 3, 29 June 2007</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Preamble</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Developers that use the GNU GPL protect your rights with two steps:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">(1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The precise terms and conditions for copying, distribution and modification follow.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">TERMS AND CONDITIONS</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">0. Definitions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;This License&quot; refers to version 3 of the GNU General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Copyright&quot; also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;The Program&quot; refers to any copyrightable work licensed under this License. Each licensee is addressed as &quot;you&quot;. &quot;Licensees&quot; and &quot;recipients&quot; may be individuals or organizations.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;modify&quot; a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a &quot;modified version&quot; of the earlier work or a work &quot;based on&quot; the earlier work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;covered work&quot; means either the unmodified Program or a work based on the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;propagate&quot; a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;convey&quot; a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An interactive user interface displays &quot;Appropriate Legal Notices&quot; to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">1. Source Code.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;source code&quot; for a work means the preferred form of the work for making modifications to it. &quot;Object code&quot; means any non-source form of a work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;Standard Interface&quot; means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;System Libraries&quot; of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A &quot;Major Component&quot;, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;Corresponding Source&quot; for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source for a work in source code form is that same work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">2. Basic Permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">3. Protecting Users' Legal Rights From Anti-Circumvention Law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">4. Conveying Verbatim Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">5. Conveying Modified Source Versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) The work must carry prominent notices stating that you modified it, and giving a relevant date.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to &quot;keep intact all notices&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an &quot;aggregate&quot; if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">6. Conveying Non-Source Forms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;User Product&quot; is either (1) a &quot;consumer product&quot;, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, &quot;normally used&quot; refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Installation Information&quot; for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">7. Additional Terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Additional permissions&quot; are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Limiting the use for publicity purposes of names of licensors or authors of the material; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All other non-permissive additional terms are considered &quot;further restrictions&quot; within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">8. Termination.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">9. Acceptance Not Required for Having Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">10. Automatic Licensing of Downstream Recipients.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An &quot;entity transaction&quot; is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">11. Patents.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;contributor&quot; is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's &quot;contributor version&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A contributor's &quot;essential patent claims&quot; are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, &quot;control&quot; includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">In the following three paragraphs, a &quot;patent license&quot; is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To &quot;grant&quot; such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. &quot;Knowingly relying&quot; means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A patent license is &quot;discriminatory&quot; if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">12. No Surrender of Others' Freedom.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">13. Use with the GNU Affero General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">14. Revised Versions of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License &quot;or any later version&quot; applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">15. Disclaimer of Warranty.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM &quot;AS IS&quot; WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">16. Limitation of Liability.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">17. Interpretation of Sections 15 and 16.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.</span></p></body></html> About Development License Program Version %1 Program Compiled on %1 at %2 Built Against SDL %1 Running With SDL %1 Using Qt %1 Using Event Handler: %1 AddEditAutoProfileDialog Auto Profile Dialog Profile: Browse Window: Select Window. Click on the appropriate application window and the application file path will be populated in the form. Detect Window Properties Class: Title: Application: Select Devices: Select this profile to be the default loaded for the specified device. The selection will be used instead of the all default profile option. Set as Default for Controller A different profile is already selected as the default for this device. Current (%1) Open Config Select Program Programs (*.exe) Please use the main default profile selection. Please select a window by using the mouse. Press Escape if you want to cancel. Capture Application Window Could not obtain information for the selected window. Application Capture Failed Profile file path is invalid. No window matching property was specified. Program path is invalid or not executable. File is not an .exe file. No window matching property was selected. AdvanceButtonDialog Advanced Assignments Toggle Turbo Set Selector Blank or KB/M Hold Pause Cycle Distance Insert Delete Clear All Time: 0.01s 0s Insert a pause that occurs in between key presses. Release Insert a new blank slot. Delete a slot. Clear all currently assigned slots. Specify the duration of an inserted Pause or Hold slot. 0m &Mouse Speed Mod: Specify the range past an axis dead zone in which a sequence of actions will execute. Distance: % Mouse Mod Press Time Delay Execute Load Set Change Text Entry Placeholder 0 Set the percentage that mouse speeds will be modified by. Auto Reset Cycle After seconds Executable: ... Arguments: Enabled Mode: <html><head/><body><p>Normal: Repeatedly press and release a button by the chosen rate.</p><p>Gradient: Modify the button press and button release delay based on how far an axis has been moved. The rate will remain the same.</p><p>Pulse: Modify how many times a button is pressed and released per second. The button delay will remain the same.</p></body></html> Normal Gradient Pulse Delay: 0.10s Rate: 10.0/s Disabled Select Set 1 One Way Select Set 1 Two Way Select Set 1 While Held Select Set 2 One Way Select Set 2 Two Way Select Set 2 While Held Select Set 3 One Way Select Set 3 Two Way Select Set 3 While Held Select Set 4 One Way Select Set 4 Two Way Select Set 4 While Held Select Set 5 One Way Select Set 5 Two Way Select Set 5 While Held Select Set 6 One Way Select Set 6 Two Way Select Set 6 While Held Select Set 7 One Way Select Set 7 Two Way Select Set 7 While Held Select Set 8 One Way Select Set 8 Two Way Select Set 8 While Held sec. /sec. Set %1 Select Set %1 One Way Two Way While Held Choose Executable Slots past a Cycle action will be executed on the next button press. Multiple cycles can be added in order to create partitions in a sequence. Delays the time that the next slot is activated by the time specified. Slots activated before the delay will remain active after the delay time has passed. Distance action specifies that the slots afterwards will only be executed when an axis is moved a certain range past the designated dead zone. Insert a hold action. Slots after the action will only be executed if the button is held past the interval specified. Chose a profile to load when this slot is activated. Mouse mod action will modify all mouse speed settings by a specified percentage while the action is being processed. This can be useful for slowing down the mouse while sniping. Specify the time that keys past this slot should be held down. Insert a release action. Slots after the action will only be executed after a button release if the button was held past the interval specified. Change to selected set once slot is activated. Full string will be typed when a slot is activated. Execute program when slot is activated. Choose Profile Config Files (*.amgp *.xml) AdvanceStickAssignmentDialog Stick/Pad Assignment Sticks DPads %1 (Joystick %2) Stick 1 Enabled Assign X Axis: Y Axis: Stick 2 Number of Physical DPads: %1 Virtual DPad 1 Up: Down: Note: This window is meant for backwards compatibility with profiles made before antimicro 2.0. Since version 2.0, use of the Game Controller Mapping window is preferred. Left: Right: Axis %1 Axis %1 - Axis %1 + Button %1 Move stick 1 along the X axis Move stick 1 along the Y axis Move stick 2 along the X axis Move stick 2 along the Y axis Press a button or move an axis AxisEditDialog Axis Mouse (Horizontal) Mouse (Inverted Horizontal) Mouse (Vertical) Mouse (Inverted Vertical) Arrows: Up | Down Arrows: Left | Right Keys: W | S Keys: A | D NumPad: KP_8 | KP_2 NumPad: KP_4 | KP_6 None Set the value to use as the limit for an axis. Useful for a worn out analog stick. Negative Half Throttle Positive Half Throttle Name: Specify the name of an axis. Mouse Settings Set the value of the dead zone for an axis. Presets: Dead Zone: Max Zone: [NO KEY] Throttle setting that determines the behavior of how to interpret an axis hold or release. Negative Throttle Normal Positive Throttle Current Value: Set Set %1 Left Mouse Button Right Mouse Button ButtonEditDialog Dialog To make a new assignment, press any keyboard key or click a button in the Keyboard or Mouse tab Placeholder Toggle Enables a key press or release to only occur when a controller button is pressed. Enables rapid key presses and releases. Turbo controller. Turbo Current: Slots Na&me: Specify the name of a button. Action: Specify the action that will be performed in game while this button is being used. Advanced Set Set %1 CapturedWindowInfoDialog Captured Window Properties Information About Window Class: TextLabel Title: Path: Match By Properties Class Title Path Full Path File Name CommandLineUtility Profile location %1 is not an XML file. Profile location %1 does not exist. An invalid set number '%1' was specified. Controller identifier '%s'' is not a valid value. No display string was specified. Controller identifier is not a valid value. No set number was specified. No controller was specified. An invalid event generator was specified. No event generator string was specified. Qt style flag was detected but no style was specified. No log level specified. antimicro version Usage: antimicro [options...] [profile] Options Print help text. Print version information. Launch program in system tray only. Launch program with the tray menu disabled. Launch program without the main window displayed. Launch program with the configuration file selected as the default for selected controllers. Defaults to all controllers. Apply configuration file to a specific controller. Value can be a controller index, name, or GUID. Unload currently enabled profile(s). Value can be a controller index, name, or GUID. Start joysticks on a specific set. Value can be a controller index, name, or GUID. Advance profile loading set options. Launch program as a daemon. Enable logging. Use specified display for X11 calls. Useful for ssh. Choose between using XTest support and uinput support for event generation. Default: xtest. Choose between using SendInput and vmulti support for event generation. Default: sendinput. Print information about joysticks detected by SDL. Open game controller mapping window of selected controller. Value can be a controller index or GUID. DPadContextMenu Mouse (Normal) Mouse (Inverted Horizontal) Mouse (Inverted Vertical) Mouse (Inverted Horizontal + Vertical) Arrows Keys: W | A | S | D NumPad None Standard Eight Way 4 Way Cardinal 4 Way Diagonal Mouse Settings DPadEditDialog Dialog Presets: Mouse (Normal) Mouse (Inverted Horizontal) Mouse (Inverted Vertical) Mouse (Inverted Horizontal + Vertical) Arrows Keys: W | A | S | D NumPad None Dpad Mode: &Name: 4 Way Cardinal 4 Way Diagonal DPad Delay: Time lapsed before a direction change is taken into effect. s Specify the name of a dpad. Mouse Settings Standard Standard: 8 region dpad with two direction buttons active when the dpad is in a diagonal region. Eight Way: 8 region dpad with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region dpad with regions corresponding to the cardinal directions of the dpad. Useful for menus. 4 Way Diagonal: 4 region dpad with each region corresponding to a diagonal zone. Eight Way Set Set %1 EditAllDefaultAutoProfileDialog Default Profile Profile: Browse Open Config Profile file path is invalid. ExtraProfileSettingsDialog Extra Profile Settings Key Press Time: 0.00 ms Profile Name: s GameController Game Controller GameControllerDPad DPad GameControllerMappingDialog Game Controller Mapping <html><head/><body><p>antimicro makes use of the <a href="https://wiki.libsdl.org/CategoryGameController"><span style=" text-decoration: underline; color:#0057ae;">Game Controller API</span></a> provided by SDL 2 in order to abstract various gamepads to fit a unified standard. In order to make a button assignment, please highlight the mapping cell for the appropriate button row below. You can then press a button or move an axis on your gamepad and the cell will update with the physical button or axis that will be used.</p><p>antimicro will use the mapping that you specify to save a mapping string that will be loaded into SDL.</p></body></html> A B X Y Back Start Guide Left Shoulder Right Shoulder Left Stick Click Right Stick Click Left Stick X Left Stick Y Right Stick X Right Stick Y Left Trigger Right Trigger DPad Up DPad Left DPad Down DPad Right Mapping SDL 2 Game Controller Mapping String Last Axis Event: Current Axis Detection Dead Zone: 5000 10000 15000 20000 25000 30000 32000 Game Controller Mapping (%1) (#%2) Discard Controller Mapping? Discard mapping for this controller? If discarded, the controller will be reverted to a joystick once you refresh all joysticks. GameControllerSet Back Guide Start LS Click RS Click L Shoulder R Shoulder L Trigger R Trigger GameControllerTrigger Trigger JoyAxis Axis JoyAxisButton Negative Positive Unknown Button JoyAxisContextMenu Mouse (Horizontal) Mouse (Inverted Horizontal) Mouse (Vertical) Mouse (Inverted Vertical) Arrows: Up | Down Arrows: Left | Right Keys: W | S Keys: A | D NumPad: KP_8 | KP_2 NumPad: KP_4 | KP_6 None Mouse Settings Left Mouse Button Right Mouse Button JoyButton Processing turbo for #%1 - %2 Finishing turbo for button #%1 - %2 Processing press for button #%1 - %2 Processing release for button #%1 - %2 Distance change for button #%1 - %2 Button [NO KEY] [Set %1 1W] [Set %1 2W] [Set %1 WH] JoyButtonContextMenu Toggle Turbo Clear Set Select Disabled Set %1 Set %1 1W Set %1 2W Set %1 WH JoyButtonSlot Mouse Up Down Left Right LB MB RB B4 B5 Pause Hold Cycle Distance Release Mouse Mod Press Time Delay Load %1 Set Change %1 [Text] %1 [Exec] %1 [NO KEY] JoyControlStick Stick JoyControlStickButton Up Down Left Right Button JoyControlStickContextMenu Mouse (Normal) Mouse (Inverted Horizontal) Mouse (Inverted Vertical) Mouse (Inverted Horizontal + Vertical) Arrows Keys: W | A | S | D NumPad None Standard Eight Way 4 Way Cardinal 4 Way Diagonal Mouse Settings JoyControlStickEditDialog Dialog X: 0 Y: Distance: Presets: Mouse (Normal) Mouse (Inverted Horizontal) Mouse (Inverted Vertical) Mouse (Inverted Horizontal + Vertical) Arrows Keys: W | A | S | D NumPad None Stick Mode: Standard: 8 region stick with two direction buttons active when the stick is in a diagonal region. Eight Way: 8 region stick with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region stick with regions corresponding to the cardinal directions of the stick. Useful for menus. 4 Way Diagonal: 4 region stick with each region corresponding to a diagonal zone of the stick. 4 Way Cardinal 4 Way Diagonal Dead zone value to use for an analog stick. Value when an analog stick is considered moved 100%. The area (in degrees) that each diagonal region occupies. Square Stick: Percentage to modify a square stick coordinates to confine values to a circle % Stick Delay: Time lapsed before a direction change is taken into effect. s Modifier: Edit button that is active while the stick is active. This button is useful for assigning zones with modifier keys that can be used to assign walk/run functionality to an analog stick. PushButton Name: Specify the name of an analog stick. Mouse Settings Standard Bearing: % Safe Zone: Eight Way Dead Zone: Max Zone: Diagonal Range: Set Set %1 JoyControlStickModifierButton Modifier JoyDPad DPad JoyDPadButton Up Down Left Right Button JoyTabWidget <New> Remove Remove configuration from recent list. Load Load configuration file. Save Save changes to configuration file. Save As Save changes to a new configuration file. Sets Copy from Set Settings Set 1 Set 2 Set 3 Set 4 Set 5 Set 6 Set 7 Set 8 Stick/Pad Assign Controller Mapping Quick Set Names Toggle button name displaying. Pref Change global profile settings. Reset Revert changes to the configuration. Reload configuration file. Open Config Config Files (*.amgp *.xml) Config File (*.%1.amgp) Save Profile Changes? Changes to the new profile have not been saved. Would you like to save or discard the current profile? Changes to the profile "%1" have not been saved. Would you like to save or discard changes to the current profile? Sticks DPads No buttons have been assigned. Please use Quick Set to assign keys to buttons or disable hiding empty buttons. Set %1: %2 Set %1 Copy Set Assignments Are you sure you want to copy the assignments and device properties from %1? Save Config Set Joystick Joystick JoystickStatusWindow Properties Details Name: %1 Number: Axes: Buttons: Hats: GUID: Game Controller: Axes Buttons Hats %1 (#%2) Properties Axis %1 Hat %1 No Yes MainSettingsDialog Edit Settings General Controller Mappings Language Auto Profile Mouse <html><head/><body><p>Specify the default directory that the program should use in file dialogs when loading a profile or saving a new profile.</p></body></html> Recent Profile Count: <html><head/><body><p>Number of profiles that can be placed in recent profile list. 0 will result in the program not enforcing a limit on the number of profiles displayed.</p></body></html> Gamepad Poll Rate: Change the poll rate that the program uses to discover new events from gamepads. Defaults to 10 ms. Reducing the poll rate value could cause the application to use more CPU power so please test the setting that you use before using antimicro unattended. Hide main window when the main window close button is clicked instead of quitting the program. Close To Tray Have Windows start antimicro at system startup. Launch At Windows Startup Display recent profiles for all controllers as a single list in the tray menu. Defaults to using sub-menus. Single Profile List in Tray Have the program minimize to the taskbar. By default, the program minimizes to the system tray if available. Minimize to Taskbar This option will cause the program to hide all buttons that have no slots assigned to them. The Quick Set dialog window will have to be used to bring up the edit dialog for gamepad buttons. Hide Empty Buttons When the program is launched, open the last known profile that was opened during the previous session. Auto Load Last Opened Profile Only show the system tray icon when the program first launches. Launch in Tray Associate .amgp files with antimicro in Windows Explorer. Associate Profiles Key Repeat Active keys will be repeatedly pressed when this option is enabled. Enable Specifies how much time should elapse before key repeating begins. Specifies how many times key presses will be performed per seconds. <html><head/><body><p>antimicro has been translated into many different languages by contributors. By default, the program will choose an appropriate translation based on your system's locale setting. However, you can make antimicro load a different translation depending on the language that you choose from the list below.</p></body></html> French Italian Japanese Russian Serbian Simplified Chinese Ukrainian Class Title Program Disable the "Enhanced Pointer Precision" Windows setting while antimicro is running. Disabling "Enhanced Pointer Precision" will allow mouse movement within antimicro to be more precise. Disable Enhance Pointer Precision Smoothing Histor&y Size: Weight &Modifier: Refresh Rate: The refresh rate is the amount of time that will elapse in between mouse events. Please be cautious when editing this setting as it will cause the program to use more CPU power. Setting this value too low can cause system instability. Please test the setting before using it unattended. Spring Screen: Utilize the specified screen for spring mode. On Linux, the default is to use the primary screen. On Windows, the default is to use all available screens. Accel Numerator: 0 Accel Denominator: Accel Threshold: If the acceleration values for the virtual mouse have been changed by a different process, particularly when quitting an older game, then you might want to reset the acceleration values used by the virtual mouse. Reset Acceleration Delay: Profi&le Directory: ms Rate: times/s Below is a list of the custom mappings that have been saved. You can use the following table to delete mappings or have mappings temporarily disabled. You can also disable mappings that are included with SDL; just insert a new row with the appropriate joystick GUID and check disable. Settings will not take affect until you either refresh all joysticks or unplug that particular joystick. GUID Mapping String Disable? Delete Insert Default Brazilian Portuguese English German Active Devices: All Device Profile Default? Add Edit Also, Windows users who want to use a low value should also check the "Disable Enhance Pointer Precision" checkbox if you haven't disabled the option in Windows. Select Default Profile Directory Are you sure you want to delete the profile? MainWindow antimicro No Joysticks have been found. Please plug in a joystick and then choose the "Update Joysticks" option in the main menu If events are not seen by a game, please click here to run this application as the Adminstrator. &App &Options &Help &Quit Ctrl+Q &Update Joysticks Ctrl+U &Hide Ctrl+H &About Ctrl+A About Qt Properties Key Checker Home Page GitHub Page Game Controller Mapping Settings Stick/Pad Assign Wiki Could not find a proper controller identifier. Exiting. (%1) Open File &Restore Run as Administrator? Are you sure that you want to run this program as Adminstrator? Some games run as Administrator which will cause events generated by antimicro to not be used by those games unless antimicro is also run as the Adminstrator. This is due to permission problems caused by User Account Control (UAC) options in Windows Vista and later. Failed to elevate program Failed to restart this program as the Administrator Could not find controller. Exiting. MouseAxisSettingsDialog Mouse Settings - Set %1 MouseButtonSettingsDialog Mouse Settings - Set %1 MouseControlStickSettingsDialog Mouse Settings Set %1 MouseDPadSettingsDialog Mouse Settings Set %1 MouseSettingsDialog Mouse Settings Mouse Mode: Cursor mode is used to move the mouse cursor around the screen relative to its current position depending on how much you move an axis or if a button is pressed. Spring mode is used to move the mouse cursor from the center of the screen depending on how much you move an axis. The mouse cursor will be returned to the center of the screen when the axis is moved back to the dead zone. Cursor Spring Acceleration: Enhanced Precision Linear Quadratic Cubic Quadratic Extreme Power Function Easing Quadratic Easing Cubic Mouse Speed Settings Enable to change the horizontal and vertical speed boxes at the same time. Change Together Options for adding more acceleration to the mouse movement beyond what the acceleration curve would produce. Acceleration is added based on how quickly an axis is moved in one gamepad poll. This is meant to help work around some of the issues of the very limited input range available using typical gamepad analog sticks. Delta Acceleration &Multiplier: Mi&n Threshold: 1 = 20 pps Wheel Hori. Speed: Set the speed used for horizontal mouse wheel movement according to number of simulated notches per second. Set the speed used for vertical mouse wheel movement according to number of simulated notches per second. Sensitivit&y: For Power Function acceleration curve. Specifies the factor to use for curve sensitivity. When the value is above 1.0, the mouse movement will be accelerated faster at the low end of an axis. Easing Duration: s Highest value to accelerate mouse movement by x Start %: Acceleration begins at this percentage of the base multiplier Minimum amount of axis travel required for acceleration to begin Max Threshold: Maximum axis travel before acceleration has reached the multiplier value E&xtra Duration: Curve: Ease Out Sine Ease Out Quad Ease Out Cubic Release Radius: Specifies that the spring area will be relative to the mouse position set by a non-relative spring. Relative Mouse Status X: 0 (0 pps) Y: 1 = 1 notch(es)/s Enhanced: Three tier curve that makes the mouse move slow on the low end of an axis and fast on the high end. Linear: Mouse moves proportionally to axis. Quadratic: Mouse accelerates slowly on low end. Cubic: Mouse accelerates slower than Quadratic. Quadratic Extreme: Raises mouse speed 1.5 times once 95% axis travel has been reached. Power Function: Allows for a more custom curve option. Easing Quadratic: Axis high end is gradually accelerated over a period of time using a Quadratic curve. Easing Cubic: Axis high end is gradually accelerated over a period of time using a Cubic curve. Hori&zontal Speed: &Vertical Speed: Wheel Vert. Speed: Specifies the amount of time (in seconds) that will be required before the mouse is fully accelerated after reaching the high end of an axis. % Extend the time that extra acceleration is applied. Axis travel will be taken into account. A slower flick will decrease the actual time that extra acceleration will be applied. Spring Settings Spring Width: Changes the width of the region that the cursor can move in spring mode. 0 will use the entire width of your screen. Spring Height: Changes the height of the region that the cursor can move in spring mode. 0 will use the entire height of your screen. %n notch(es)/s %n notch/s %n notches/s QKeyDisplayDialog Key Checker <html><head/><body><p>Press a key on your keyboard to see how the key is detected by this application. The window will show the system native key value, the original value given by Qt (if applicable), and the custom value used by antimicro.</p><p>The antimicro key value and the Qt key value will usually be the same. antimicro tries to use the key values defined in Qt when possible. Check the page <a href="https://doc.qt.io/qt-4.8/qt.html#Key-enum"><span style=" text-decoration: underline; color:#0057ae;">https://doc.qt.io/qt-4.8/qt.html#Key-enum</span></a> for a list of values defined by Qt. If you discover that a key is not natively supported by this program, please report the problem to antimicro's <a href="https://github.com/AntiMicro/antimicro"><span style=" text-decoration: underline; color:#0057ae;">GitHub page</span></a> so that the program can be edited to support it directly. As it is, a custom prefix is added to unknown values so they can still be used; the main problem is that the profile will no longer be portable.</p></body></html> Event Handler: Native Key Value: 0x00000000 Qt Key Value: antimicro Key Value: QObject Super Menu Mute Vol+ Vol- Play/Pause Play Pause Prev Next Mail Home Media Search Daemon launched Failed to launch daemon Launching daemon Display string "%1" is not valid. Failed to set a signature id for the daemon Failed to change working directory to / Quitting Program # of joysticks found: %1 List Joysticks: --------------- Joystick %1: Index: %1 GUID: %1 Name: %1 Yes No Game Controller: %1 # of Axes: %1 # of Buttons: %1 # of Hats: %1 Attempting to use fallback option %1 for event generation. Failed to open event generator. Exiting. Using %1 as the event generator. Could not raise process priority. QuickSetDialog Quick Set <html><head/><body><p>Please press a button or move an axis on %1 (<span style=" font-weight:600;">%2</span>).<br/>A dialog window will then appear which will<br/>allow you to make an assignment.</p></body></html> Quick Set %1 SetAxisThrottleDialog Throttle Change The throttle setting for Axis %1 has been changed. Would you like to distribute this throttle change to all sets? SetJoystick Set %1: %2 Set %1 SetNamesDialog Set Name Settings Set 1 Set 2 Set 3 Set 4 Set 5 Set 6 Set 7 Set 8 Name SimpleKeyGrabberButton Mouse SpringModeRegionPreview Spring Mode Preview UInputEventHandler Could not find a valid uinput device file. Please check that you have the uinput module loaded. lsmod | grep uinput Could not open uinput device file Please check that you have permission to write to the device Using uinput device file %1 UInputHelper a b c d e f g h i j k l m n o p q r s t u v w x y z Esc F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 ` 1 2 3 4 5 6 7 8 9 0 - = BackSpace Tab [ ] \ CapsLock ; ' Enter Shift_L , . / Ctrl_L Super_L Alt_L Space Alt_R Menu Ctrl_R Shift_R Up Left Down Right PrtSc Ins Del Home End PgUp PgDn NumLock * + KP_Enter KP_1 KP_2 KP_3 KP_4 KP_5 KP_6 KP_7 KP_8 KP_9 KP_0 SCLK Pause Super_R Mute VolDn VolUp Play Stop Prev Next [NO KEY] UnixWindowInfoDialog Captured Window Properties Information About Window Class: TextLabel Title: Path: Match By Properties Class Title Path VDPad VDPad VirtualKeyPushButton Space Tab Shift (L) Shift (R) Ctrl (L) Ctrl (R) Alt (L) Alt (R) ` ~ - = [ ] \ Caps ; ' , . / ESC PRTSC SCLK INS PGUP DEL PGDN 1 2 3 4 5 6 7 8 9 0 NUM LK * + E N T E R < : Super (L) Menu Up Down Left Right VirtualKeyboardMouseWidget Keyboard Mouse Mouse Settings Left Mouse Up Mouse Left Button Mouse Middle Button Mouse Right Button Mouse Wheel Up Mouse Wheel Left Mouse Wheel Right Mouse Wheel Down Mouse Down Mouse Right Mouse Button 4 Mouse Mouse 8 Mouse Button 5 Mouse Mouse 9 Mouse NONE Applications Browser Back Browser Favorites Browser Forward Browser Home Browser Refresh Browser Search Browser Stop Calc Email Media Media Next Media Play Media Previous Media Stop Search Volume Down Volume Mute Volume Up VirtualMousePushButton INVALID WinAppProfileTimerDialog Capture Application After pressing the "Capture Application" button, please select the application window that you want to have a profile associated with. The active application will be captured after the selected number of seconds. Timer: Seconds Cancel WinExtras [NO KEY] AntiMicro Profile X11Extras ESC Tab Space DEL Return KP_Enter Backspace xinput extension was not found. No mouse acceleration changes will occur. xinput version must be at least 2.0. No mouse acceleration changes will occur. Virtual pointer found with id=%1. PtrFeedbackClass was not found for virtual pointer.No change to mouse acceleration will occur for device with id=%1 Changing mouse acceleration for device with id=%1 XMLConfigReader Could not write updated profile XML to file %1. XMLConfigWriter Could not write to profile at %1. antimicro-2.23/share/antimicro/translations/antimicro_br.ts000066400000000000000000011303211300750276700242650ustar00rootroot00000000000000 AboutDialog About Sobre Version Versão <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Originally developed by Travis Nickles &lt;nickles.travis@gmail.com&gt;, now maintained by the AntiMicro group at https://github.com/AntiMicro.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Contributors:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;"><br /></span>Zerro Alvein</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">aybe</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jeff Backus &lt;jeff.backus@gmail.com&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Arthur Moore<br />Anton Tornqvist &lt;antont@inbox.lv&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7185</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">DarkStarSword</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">est31</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ProfessorKaos64</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">qwerty12</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA0</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Translators:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VaGNaroK &lt;vagnarokalkimist@gmail.com&gt; - Brazilian Portuguese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx - Chinese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Belleguic Terence &lt;hizo@free.fr&gt; - French</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Leonard Koenig &lt;leonard.r.koenig@googlemail.com&gt; - German</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phob - German</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">tou omiya - Japanese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Dmitriy Koshel &lt;form.eater@gmail.com&gt; - Russian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jay Alexander Fleming &lt;tito.nehru.naser@gmail.com&gt; - Serbian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">burunduk - Ukrainian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Flavio HR &lt;flavio.hrx@gmail.com&gt; - Spanish</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA - wazaaaaa00&lt;@&gt;gmail&lt;.&gt;com - Italian</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> Info Changelog Since December 30, 2012, I have been working on antimicro in my spare time. What originally started as a fork of QJoyPad and a way to learn proper event-driven programming has turned into something much bigger than I originally intended. Although I have spent a lot of time learning new techniques, finding out more about the domain of KB+M emulation, and spending Friday nights bashing my head against my keyboard, it has been a fun and enriching experience overall. The need for this program came from me using similar programs on Windows to play several games that did not provide native controller support. Although some alternatives existed on Linux, there wasn't really anything that I felt was good enough in terms of functionality or in-game controls in order to really enjoy games that I wanted to play with using KB+M emulation. QJoyPad was the main program that I had used in the past although it had aged a lot and it didn't provide some basic functionality that I thought was essential. The project was dead as it had not been updated in several years so I decided to make my own. Since then, I have tried to find out what the other programs do right and then improve upon it. I have also discovered some neat tricks along the way and I have learned more about how native gamepad controls are implemented in some games than I ever really wanted to know. Although there are definitely areas where this program could improve, I find that this program offers the best in-game control experience for playing older, and some newer, games that do not provide native controller support. Development of this program is not as high of a priority for me anymore. This is mainly due to the fact that the Steam Controller works pretty well for the task of playing PC games compared to using an Xbox 360 controller. However, it does look like there is still a reason for this program to exist for a while. Copyright: 2013 - 2016 Credits Créditos antimicro <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">GNU GENERAL PUBLIC LICENSE</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Version 3, 29 June 2007</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Preamble</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Developers that use the GNU GPL protect your rights with two steps:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">(1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The precise terms and conditions for copying, distribution and modification follow.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">TERMS AND CONDITIONS</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">0. Definitions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;This License&quot; refers to version 3 of the GNU General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Copyright&quot; also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;The Program&quot; refers to any copyrightable work licensed under this License. Each licensee is addressed as &quot;you&quot;. &quot;Licensees&quot; and &quot;recipients&quot; may be individuals or organizations.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;modify&quot; a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a &quot;modified version&quot; of the earlier work or a work &quot;based on&quot; the earlier work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;covered work&quot; means either the unmodified Program or a work based on the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;propagate&quot; a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;convey&quot; a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An interactive user interface displays &quot;Appropriate Legal Notices&quot; to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">1. Source Code.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;source code&quot; for a work means the preferred form of the work for making modifications to it. &quot;Object code&quot; means any non-source form of a work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;Standard Interface&quot; means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;System Libraries&quot; of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A &quot;Major Component&quot;, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;Corresponding Source&quot; for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source for a work in source code form is that same work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">2. Basic Permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">3. Protecting Users' Legal Rights From Anti-Circumvention Law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">4. Conveying Verbatim Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">5. Conveying Modified Source Versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) The work must carry prominent notices stating that you modified it, and giving a relevant date.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to &quot;keep intact all notices&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an &quot;aggregate&quot; if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">6. Conveying Non-Source Forms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;User Product&quot; is either (1) a &quot;consumer product&quot;, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, &quot;normally used&quot; refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Installation Information&quot; for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">7. Additional Terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Additional permissions&quot; are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Limiting the use for publicity purposes of names of licensors or authors of the material; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All other non-permissive additional terms are considered &quot;further restrictions&quot; within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">8. Termination.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">9. Acceptance Not Required for Having Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">10. Automatic Licensing of Downstream Recipients.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An &quot;entity transaction&quot; is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">11. Patents.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;contributor&quot; is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's &quot;contributor version&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A contributor's &quot;essential patent claims&quot; are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, &quot;control&quot; includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">In the following three paragraphs, a &quot;patent license&quot; is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To &quot;grant&quot; such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. &quot;Knowingly relying&quot; means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A patent license is &quot;discriminatory&quot; if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">12. No Surrender of Others' Freedom.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">13. Use with the GNU Affero General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">14. Revised Versions of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License &quot;or any later version&quot; applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">15. Disclaimer of Warranty.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM &quot;AS IS&quot; WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">16. Limitation of Liability.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">17. Interpretation of Sections 15 and 16.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.</span></p></body></html> About Development License Licença Program Version %1 Program Compiled on %1 at %2 Built Against SDL %1 Running With SDL %1 Using Qt %1 Using Event Handler: %1 AddEditAutoProfileDialog Auto Profile Dialog Profile: Browse Window: Select Window. Click on the appropriate application window and the application file path will be populated in the form. Detect Window Properties Class: Title: Application: Select Devices: Select this profile to be the default loaded for the specified device. The selection will be used instead of the all default profile option. Set as Default for Controller A different profile is already selected as the default for this device. Current (%1) Open Config Abrir Configuração Select Program Programs (*.exe) Please use the main default profile selection. Please select a window by using the mouse. Press Escape if you want to cancel. Capture Application Window Could not obtain information for the selected window. Application Capture Failed Profile file path is invalid. No window matching property was specified. Program path is invalid or not executable. File is not an .exe file. No window matching property was selected. AdvanceButtonDialog Advanced Avançado Assignments Atribuições Toggle Alternar Turbo Turbo Set Selector Definir Seletor Blank or KB/M Hold Segurar Pause Pausar Cycle Ciclo Distance Distância Insert Inserir Delete Deletar Clear All Limpar tudo Time: Tempo: 0.01s 0s Insert a pause that occurs in between key presses. Inserir uma pausa que ocorre entre teclas pressionadas. Release Liberar Insert a new blank slot. Inserir um novo slot vazio. Delete a slot. Deletar um slot. Clear all currently assigned slots. Limpar todos os slots atribuido atualmente. Specify the duration of an inserted Pause or Hold slot. Especificar a duração de uma pausa inserida ou manter o slot. 0m 0m &Mouse Speed Mod: Specify the range past an axis dead zone in which a sequence of actions will execute. Especifique o intervalo passado em uma zona morta, no eixo em que uma seqüência de ações será executado. Distance: Distância: % Mouse Mod Press Time Delay Execute Load Carregar Set Change Text Entry Placeholder Espaço Reservado 0 0 Set the percentage that mouse speeds will be modified by. Auto Reset Cycle After seconds Executable: ... Arguments: Enabled Habilitar Mode: <html><head/><body><p>Normal: Repeatedly press and release a button by the chosen rate.</p><p>Gradient: Modify the button press and button release delay based on how far an axis has been moved. The rate will remain the same.</p><p>Pulse: Modify how many times a button is pressed and released per second. The button delay will remain the same.</p></body></html> Normal Normal Gradient Pulse Delay: Atrasar: 0.10s Rate: Taxa: 10.0/s Disabled Inválido Select Set 1 One Way Selecionar e definir uma maneira Select Set 1 Two Way Selecionar e definir duas maneiras Select Set 1 While Held Selecionar e Definir um Enquanto Realiza Select Set 2 One Way Selecionar e definir 2 uma maneira Select Set 2 Two Way Selecionar e definir 2 duas maneiras Select Set 2 While Held Selecionar e Definir 2 Enquanto Realiza Select Set 3 One Way Selecionar e definir 3 uma maneira Select Set 3 Two Way Selecionar e definir 3 duas maneiras Select Set 3 While Held Selecionar e definir 3 Enquanto Realiza Select Set 4 One Way Selecionar e definir 4 uma maneira Select Set 4 Two Way Selecionar e definir 4 duas maneiras Select Set 4 While Held Selecionar e definir 4 enquanto realiza Select Set 5 One Way Selecionar e definir 5 uma maneiras Select Set 5 Two Way Selecionar e definir 5 duas maneiras Select Set 5 While Held Selecionar e definir 5 enquanto realiza Select Set 6 One Way Selecionar e definir 6 uma maneiras Select Set 6 Two Way Selecionar e definir 6 duas maneiras Select Set 6 While Held Selecionar e definir 6 enquanto realiza Select Set 7 One Way Selecionar e definir 7 uma maneiras Select Set 7 Two Way Selecionar e definir 7 duas maneiras Select Set 7 While Held Selecionar e definir 7 enquanto realiza Select Set 8 One Way Selecionar e definir 8 uma maneiras Select Set 8 Two Way Selecionar e definir 8 duas maneiras Select Set 8 While Held Selecionar e definir 8 enquanto realiza sec. /sec. Set %1 Select Set %1 One Way Two Way While Held Choose Executable Slots past a Cycle action will be executed on the next button press. Multiple cycles can be added in order to create partitions in a sequence. Delays the time that the next slot is activated by the time specified. Slots activated before the delay will remain active after the delay time has passed. Distance action specifies that the slots afterwards will only be executed when an axis is moved a certain range past the designated dead zone. Insert a hold action. Slots after the action will only be executed if the button is held past the interval specified. Chose a profile to load when this slot is activated. Mouse mod action will modify all mouse speed settings by a specified percentage while the action is being processed. This can be useful for slowing down the mouse while sniping. Specify the time that keys past this slot should be held down. Insert a release action. Slots after the action will only be executed after a button release if the button was held past the interval specified. Change to selected set once slot is activated. Full string will be typed when a slot is activated. Execute program when slot is activated. Choose Profile Config Files (*.amgp *.xml) AdvanceStickAssignmentDialog Stick/Pad Assignment Atribuir Stick/Pad Sticks Analógicos DPads Direcionais %1 (Joystick %2) Stick 1 Analógico 1 Enabled Habilitado Assign X Axis: Eixo X: Y Axis: Aixo Y: Stick 2 Analógico 2 Number of Physical DPads: %1 Número de Dpads físico:%1 Virtual DPad 1 DPad 1 Virtual Up: Cima: Down: Baixo: Note: This window is meant for backwards compatibility with profiles made before antimicro 2.0. Since version 2.0, use of the Game Controller Mapping window is preferred. Left: Esquerda: Right: Direita: Axis %1 Eixo %1 Axis %1 - Eixo %1- Axis %1 + Eixo %1+ Button %1 Botão %1 Move stick 1 along the X axis Move stick 1 along the Y axis Move stick 2 along the X axis Move stick 2 along the Y axis Press a button or move an axis AxisEditDialog Axis Eixo Mouse (Horizontal) Mouse (Horizontal) Mouse (Inverted Horizontal) Mouse (Horizontal Invertido) Mouse (Vertical) Mouse (Vertical) Mouse (Inverted Vertical) Mouse (Vertical Invertido) Arrows: Up | Down Setas: Cima | Baixo Arrows: Left | Right Setas: Esquerda | Direita Keys: W | S Teclas: W | S Keys: A | D Teclas: A | D NumPad: KP_8 | KP_2 Pad Numérico: KP_8 | KP_2 NumPad: KP_4 | KP_6 Pad Numérico: KP_4 | KP_6 None Nada Set the value to use as the limit for an axis. Useful for a worn out analog stick. Negative Half Throttle Positive Half Throttle Name: Specify the name of an axis. Mouse Settings Configurações do Mouse Set the value of the dead zone for an axis. Defina o valor da zona morta para um eixo. Presets: Predefinido: Dead Zone: Zona Morta: Max Zone: Zona Máxima: [NO KEY] [SEM TECLA] Throttle setting that determines the behavior of how to interpret an axis hold or release. Posição do acelerador, que determina o comportamento de como interpretar um eixo ou liberação. Negative Throttle Acelerador Negativo Normal Normal Positive Throttle Aceleração Positiva Current Value: Valor Atual: Set Definir Set %1 Left Mouse Button Right Mouse Button ButtonEditDialog Dialog Diálogo To make a new assignment, press any keyboard key or click a button in the Keyboard or Mouse tab Para fazer uma nova atribuição, pressionar qualquer tecla do teclado ou clicar em um botão na guia do teclado ou mouse Placeholder Espaço Reservado Toggle Alternar Enables a key press or release to only occur when a controller button is pressed. Permite um pressionamento ou a liberação para ocorrer apenas quando um botão é pressionado no controlador. Enables rapid key presses and releases. Turbo controller. Permite o rápido pressionamento de teclas e lançamentos. Turbo controlador. Turbo Turbo Current: Atual: Slots Slot Na&me: Specify the name of a button. Action: Specify the action that will be performed in game while this button is being used. Advanced Avançado Set Definir Set %1 CapturedWindowInfoDialog Captured Window Properties Information About Window Class: TextLabel Title: Path: Match By Properties Class Title Path Full Path File Name CommandLineUtility Profile location %1 is not an XML file. A localização do perfil %1 não é um arquivo XML. Profile location %1 does not exist. A localização do perfil %1 não existe. An invalid set number '%1' was specified. Controller identifier '%s'' is not a valid value. No display string was specified. Controller identifier is not a valid value. No set number was specified. No controller was specified. An invalid event generator was specified. No event generator string was specified. Qt style flag was detected but no style was specified. No log level specified. antimicro version Usage: antimicro [options...] [profile] Options Opções Print help text. Imprimir texto de ajuda. Print version information. Imprimir informações da versão. Launch program in system tray only. Lançar programa na bandeja do sistema. Launch program with the tray menu disabled. Lançar programa com o menu da bandeja desativado. Launch program without the main window displayed. Launch program with the configuration file selected as the default for selected controllers. Defaults to all controllers. Apply configuration file to a specific controller. Value can be a controller index, name, or GUID. Unload currently enabled profile(s). Value can be a controller index, name, or GUID. Start joysticks on a specific set. Value can be a controller index, name, or GUID. Advance profile loading set options. Launch program as a daemon. Enable logging. Use specified display for X11 calls. Useful for ssh. Choose between using XTest support and uinput support for event generation. Default: xtest. Choose between using SendInput and vmulti support for event generation. Default: sendinput. Print information about joysticks detected by SDL. Open game controller mapping window of selected controller. Value can be a controller index or GUID. DPadContextMenu Mouse (Normal) Mouse (Normal) Mouse (Inverted Horizontal) Mouse (Horizontal Invertido) Mouse (Inverted Vertical) Mouse (Inverted Horizontal + Vertical) Mouse (Horizontal + Vertical Invertido) Arrows Setas Keys: W | A | S | D Teclas: W | A | S | D NumPad Pad Numérico None Nada Standard Padrão Eight Way Oito Maneiras 4 Way Cardinal 4 Way Diagonal Mouse Settings DPadEditDialog Dialog Diálogo Presets: Predefinido: Mouse (Normal) Mouse (Normal) Mouse (Inverted Horizontal) Mouse (Horizontal Invertido) Mouse (Inverted Vertical) Mouse (Vertical Invertido) Mouse (Inverted Horizontal + Vertical) Mouse (Horizontal + Vertical Invertido) Arrows Setas Keys: W | A | S | D Teclas: W | A | S | D NumPad Pad Numérico None Nada Dpad Mode: Modo Pad: &Name: 4 Way Cardinal 4 Way Diagonal DPad Delay: Time lapsed before a direction change is taken into effect. s Specify the name of a dpad. Mouse Settings Configuração do Mouse Standard Padrão Standard: 8 region dpad with two direction buttons active when the dpad is in a diagonal region. Eight Way: 8 region dpad with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region dpad with regions corresponding to the cardinal directions of the dpad. Useful for menus. 4 Way Diagonal: 4 region dpad with each region corresponding to a diagonal zone. Eight Way Oito Maneiras Set Definir Set %1 EditAllDefaultAutoProfileDialog Default Profile Profile: Browse Open Config Abrir Configuração Profile file path is invalid. ExtraProfileSettingsDialog Extra Profile Settings Key Press Time: 0.00 ms Profile Name: s s GameController Game Controller GameControllerDPad DPad Direcional GameControllerMappingDialog Game Controller Mapping <html><head/><body><p>antimicro makes use of the <a href="https://wiki.libsdl.org/CategoryGameController"><span style=" text-decoration: underline; color:#0057ae;">Game Controller API</span></a> provided by SDL 2 in order to abstract various gamepads to fit a unified standard. In order to make a button assignment, please highlight the mapping cell for the appropriate button row below. You can then press a button or move an axis on your gamepad and the cell will update with the physical button or axis that will be used.</p><p>antimicro will use the mapping that you specify to save a mapping string that will be loaded into SDL.</p></body></html> A B X Y Back Start Guide Left Shoulder Right Shoulder Left Stick Click Right Stick Click Left Stick X Left Stick Y Right Stick X Right Stick Y Left Trigger Right Trigger DPad Up DPad Left DPad Down DPad Right Mapping SDL 2 Game Controller Mapping String Last Axis Event: Current Axis Detection Dead Zone: 5000 5000 10000 10000 15000 15000 20000 20000 25000 25000 30000 30000 32000 32000 Game Controller Mapping (%1) (#%2) Discard Controller Mapping? Discard mapping for this controller? If discarded, the controller will be reverted to a joystick once you refresh all joysticks. GameControllerSet Back Guide Start LS Click RS Click L Shoulder R Shoulder L Trigger R Trigger GameControllerTrigger Trigger JoyAxis Axis Eixo JoyAxisButton Negative Negativo Positive Positivo Unknown Desconhecido Button Botão JoyAxisContextMenu Mouse (Horizontal) Mouse (Horizontal) Mouse (Inverted Horizontal) Mouse (Horizontal Invertido) Mouse (Vertical) Mouse (Vertical) Mouse (Inverted Vertical) Arrows: Up | Down Setas: Cima | Baixo Arrows: Left | Right Setas: Esquerda | Direita Keys: W | S Teclas: W | S Keys: A | D Teclas: A | D NumPad: KP_8 | KP_2 Pad Numérico: KP_8 | KP_2 NumPad: KP_4 | KP_6 Pad Numérico: KP_4 | KP_6 None Nada Mouse Settings Left Mouse Button Right Mouse Button JoyButton Processing turbo for #%1 - %2 Finishing turbo for button #%1 - %2 Processing press for button #%1 - %2 Processing release for button #%1 - %2 Distance change for button #%1 - %2 Button Botão [NO KEY] [SEM TECLA] [Set %1 1W] [Set %1 2W] [Set %1 WH] JoyButtonContextMenu Toggle Alternar Turbo Turbo Clear Set Select Disabled Inválido Set %1 Set %1 1W Set %1 2W Set %1 WH JoyButtonSlot Mouse Mover Up Cima Down Baixo Left Esquerda Right Direita LB LB MB MB RB RB B4 B5 Pause Pausar Hold Segurar Cycle Ciclo Distance Distância Release Soltar Mouse Mod Press Time Delay Load %1 Set Change %1 [Text] %1 [Exec] %1 [NO KEY] [SEM TECLA] JoyControlStick Stick Analógico JoyControlStickButton Up Cima Down Baixo Left Esquerda Right Direita Button Botão JoyControlStickContextMenu Mouse (Normal) Mouse (Normal) Mouse (Inverted Horizontal) Mouse (Horizontal Invertido) Mouse (Inverted Vertical) Mouse (Inverted Horizontal + Vertical) Mouse (Horizontal + Vertical Invertido) Arrows Setas Keys: W | A | S | D Teclas: W | A | S | D NumPad Pad Numérico None Nada Standard Padrão Eight Way Oito Maneiras 4 Way Cardinal 4 Way Diagonal Mouse Settings JoyControlStickEditDialog Dialog Diálogo X: X: 0 0 Y: Y: Distance: Distância: Presets: Predefinido: Mouse (Normal) Mouse (Normal) Mouse (Inverted Horizontal) Mouse (Horizontal Invertido) Mouse (Inverted Vertical) Mouse (Vertical invertido) Mouse (Inverted Horizontal + Vertical) Mouse (Horizontal + Vertical Invertido) Arrows Setas Keys: W | A | S | D Teclas: W | A | S | D NumPad Pad Numérico None Nada Stick Mode: Modo Analógico: Standard: 8 region stick with two direction buttons active when the stick is in a diagonal region. Eight Way: 8 region stick with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region stick with regions corresponding to the cardinal directions of the stick. Useful for menus. 4 Way Diagonal: 4 region stick with each region corresponding to a diagonal zone of the stick. 4 Way Cardinal 4 Way Diagonal Dead zone value to use for an analog stick. Value when an analog stick is considered moved 100%. The area (in degrees) that each diagonal region occupies. Square Stick: Percentage to modify a square stick coordinates to confine values to a circle % Stick Delay: Time lapsed before a direction change is taken into effect. s Modifier: Edit button that is active while the stick is active. This button is useful for assigning zones with modifier keys that can be used to assign walk/run functionality to an analog stick. PushButton Name: Specify the name of an analog stick. Mouse Settings Configurações do Mouse Standard Padrão Bearing: % Safe Zone: Eight Way Oito Maneiras Dead Zone: Zona da Morte: Max Zone: Zona Máxima: Diagonal Range: Alcance Diagonal: Set Definir Set %1 JoyControlStickModifierButton Modifier JoyDPad DPad Direcional JoyDPadButton Up Cima Down Baixo Left Esquerda Right Direita Button Botão JoyTabWidget <New> Novo Remove Remove configuration from recent list. Load Carregar Load configuration file. Save Salvar Save changes to configuration file. Save As Salvar Como Save changes to a new configuration file. Sets Copy from Set Settings Set 1 Set 2 Set 3 Set 4 Set 5 Set 6 Set 7 Set 8 Stick/Pad Assign Atribuir Analógico/Direcional Controller Mapping Quick Set Definir Rápido Names Toggle button name displaying. Pref Change global profile settings. Reset Resetar Revert changes to the configuration. Reload configuration file. Open Config Abrir Configuração Config Files (*.amgp *.xml) Config File (*.%1.amgp) Save Profile Changes? Changes to the new profile have not been saved. Would you like to save or discard the current profile? Changes to the profile "%1" have not been saved. Would you like to save or discard changes to the current profile? Sticks Analógicos DPads Direcionais No buttons have been assigned. Please use Quick Set to assign keys to buttons or disable hiding empty buttons. Set %1: %2 Set %1 Copy Set Assignments Are you sure you want to copy the assignments and device properties from %1? Save Config Salvar Configuração Set Definir Joystick Joystick Analógico JoystickStatusWindow Properties Details Name: %1 Number: Axes: Buttons: Hats: GUID: Game Controller: Axes Buttons Hats %1 (#%2) Properties Axis %1 Eixo %1 Hat %1 No Yes MainSettingsDialog Edit Settings General Controller Mappings Language Auto Profile Mouse <html><head/><body><p>Specify the default directory that the program should use in file dialogs when loading a profile or saving a new profile.</p></body></html> Recent Profile Count: <html><head/><body><p>Number of profiles that can be placed in recent profile list. 0 will result in the program not enforcing a limit on the number of profiles displayed.</p></body></html> Gamepad Poll Rate: Change the poll rate that the program uses to discover new events from gamepads. Defaults to 10 ms. Reducing the poll rate value could cause the application to use more CPU power so please test the setting that you use before using antimicro unattended. Hide main window when the main window close button is clicked instead of quitting the program. Close To Tray Have Windows start antimicro at system startup. Launch At Windows Startup Display recent profiles for all controllers as a single list in the tray menu. Defaults to using sub-menus. Single Profile List in Tray Have the program minimize to the taskbar. By default, the program minimizes to the system tray if available. Minimize to Taskbar This option will cause the program to hide all buttons that have no slots assigned to them. The Quick Set dialog window will have to be used to bring up the edit dialog for gamepad buttons. Hide Empty Buttons When the program is launched, open the last known profile that was opened during the previous session. Auto Load Last Opened Profile Only show the system tray icon when the program first launches. Launch in Tray Associate .amgp files with antimicro in Windows Explorer. Associate Profiles Key Repeat Active keys will be repeatedly pressed when this option is enabled. Enable Specifies how much time should elapse before key repeating begins. Specifies how many times key presses will be performed per seconds. <html><head/><body><p>antimicro has been translated into many different languages by contributors. By default, the program will choose an appropriate translation based on your system's locale setting. However, you can make antimicro load a different translation depending on the language that you choose from the list below.</p></body></html> French Italian Japanese Russian Serbian Simplified Chinese Ukrainian Class Title Program Disable the "Enhanced Pointer Precision" Windows setting while antimicro is running. Disabling "Enhanced Pointer Precision" will allow mouse movement within antimicro to be more precise. Disable Enhance Pointer Precision Smoothing Histor&y Size: Weight &Modifier: Refresh Rate: The refresh rate is the amount of time that will elapse in between mouse events. Please be cautious when editing this setting as it will cause the program to use more CPU power. Setting this value too low can cause system instability. Please test the setting before using it unattended. Spring Pular Screen: Utilize the specified screen for spring mode. On Linux, the default is to use the primary screen. On Windows, the default is to use all available screens. Accel Numerator: 0 0 Accel Denominator: Accel Threshold: If the acceleration values for the virtual mouse have been changed by a different process, particularly when quitting an older game, then you might want to reset the acceleration values used by the virtual mouse. Reset Acceleration Delay: Atrasar: Profi&le Directory: ms Rate: Taxa: times/s Below is a list of the custom mappings that have been saved. You can use the following table to delete mappings or have mappings temporarily disabled. You can also disable mappings that are included with SDL; just insert a new row with the appropriate joystick GUID and check disable. Settings will not take affect until you either refresh all joysticks or unplug that particular joystick. GUID Mapping String Disable? Delete Deletar Insert Inserir Default Brazilian Portuguese English German Active Devices: All Device Profile Default? Add Edit Also, Windows users who want to use a low value should also check the "Disable Enhance Pointer Precision" checkbox if you haven't disabled the option in Windows. Select Default Profile Directory Are you sure you want to delete the profile? MainWindow No Joysticks have been found. Please plug in a joystick and then choose the "Update Joysticks" option in the main menu Nenhum joystick foi encontrados. Por favor, conecte um joystick e, em seguida, escolha a opção "Atualizar Joysticks" no menu principal &App Stick/Pad Assign Atribuir Analógico/Dpad &Options &Opções antimicro If events are not seen by a game, please click here to run this application as the Adminstrator. &Help &Ajuda &Quit &Sair Ctrl+Q Ctrl+Q &Update Joysticks &Atualizar joysticks Ctrl+U Ctrl+U &Hide &Esconder Ctrl+H Ctrl+H &About &Sobre Ctrl+A Ctrl+A About Qt Sobre Qt Properties Key Checker Home Page GitHub Page Game Controller Mapping Settings Wiki Could not find a proper controller identifier. Exiting. (%1) Open File Abrir Arquivo &Restore &Restaurar Run as Administrator? Are you sure that you want to run this program as Adminstrator? Some games run as Administrator which will cause events generated by antimicro to not be used by those games unless antimicro is also run as the Adminstrator. This is due to permission problems caused by User Account Control (UAC) options in Windows Vista and later. Failed to elevate program Failed to restart this program as the Administrator Could not find controller. Exiting. MouseAxisSettingsDialog Mouse Settings - Configuração do Mouse Set %1 MouseButtonSettingsDialog Mouse Settings - Configuração do Mouse Set %1 MouseControlStickSettingsDialog Mouse Settings Set %1 MouseDPadSettingsDialog Mouse Settings Set %1 MouseSettingsDialog Mouse Settings Configuração do Mouse Mouse Mode: Modo do Mouse: Cursor mode is used to move the mouse cursor around the screen relative to its current position depending on how much you move an axis or if a button is pressed. Spring mode is used to move the mouse cursor from the center of the screen depending on how much you move an axis. The mouse cursor will be returned to the center of the screen when the axis is moved back to the dead zone. Cursor Cursor Spring Pular Acceleration: Aceleração: Enhanced Precision Linear Linear Quadratic Quadrático Cubic Cúbico Quadratic Extreme Extremo Quadrático Power Function Função Pwer Easing Quadratic Easing Cubic Mouse Speed Settings Configuração da velocidade do Mouse Enable to change the horizontal and vertical speed boxes at the same time. Change Together Alterar Junto Options for adding more acceleration to the mouse movement beyond what the acceleration curve would produce. Acceleration is added based on how quickly an axis is moved in one gamepad poll. This is meant to help work around some of the issues of the very limited input range available using typical gamepad analog sticks. Delta Acceleration &Multiplier: Mi&n Threshold: Horizontal Speed: Velocidade Horizontal: 1 = 20 pps 1 = 20 pps Vertical Speed: Velocidade Vertical: Wheel Hori. Speed: Set the speed used for horizontal mouse wheel movement according to number of simulated notches per second. Set the speed used for vertical mouse wheel movement according to number of simulated notches per second. Sensitivit&y: For Power Function acceleration curve. Specifies the factor to use for curve sensitivity. When the value is above 1.0, the mouse movement will be accelerated faster at the low end of an axis. Easing Duration: s Highest value to accelerate mouse movement by x x Start %: Acceleration begins at this percentage of the base multiplier Minimum amount of axis travel required for acceleration to begin Max Threshold: Maximum axis travel before acceleration has reached the multiplier value E&xtra Duration: Curve: Ease Out Sine Ease Out Quad Ease Out Cubic Release Radius: Specifies that the spring area will be relative to the mouse position set by a non-relative spring. Relative Mouse Status X: X: 0 (0 pps) Y: Y: 1 = 1 notch(es)/s Enhanced: Three tier curve that makes the mouse move slow on the low end of an axis and fast on the high end. Linear: Mouse moves proportionally to axis. Quadratic: Mouse accelerates slowly on low end. Cubic: Mouse accelerates slower than Quadratic. Quadratic Extreme: Raises mouse speed 1.5 times once 95% axis travel has been reached. Power Function: Allows for a more custom curve option. Easing Quadratic: Axis high end is gradually accelerated over a period of time using a Quadratic curve. Easing Cubic: Axis high end is gradually accelerated over a period of time using a Cubic curve. Hori&zontal Speed: &Vertical Speed: Wheel Vert. Speed: Sensitivity: Sensibilidade: Specifies the amount of time (in seconds) that will be required before the mouse is fully accelerated after reaching the high end of an axis. % Extend the time that extra acceleration is applied. Axis travel will be taken into account. A slower flick will decrease the actual time that extra acceleration will be applied. Spring Settings Configuração do Pulo Spring Width: Pulo de Largura: Changes the width of the region that the cursor can move in spring mode. 0 will use the entire width of your screen. Spring Height: Pulo de Altura: Changes the height of the region that the cursor can move in spring mode. 0 will use the entire height of your screen. %n notch(es)/s QKeyDisplayDialog Key Checker <html><head/><body><p>Press a key on your keyboard to see how the key is detected by this application. The window will show the system native key value, the original value given by Qt (if applicable), and the custom value used by antimicro.</p><p>The antimicro key value and the Qt key value will usually be the same. antimicro tries to use the key values defined in Qt when possible. Check the page <a href="https://doc.qt.io/qt-4.8/qt.html#Key-enum"><span style=" text-decoration: underline; color:#0057ae;">https://doc.qt.io/qt-4.8/qt.html#Key-enum</span></a> for a list of values defined by Qt. If you discover that a key is not natively supported by this program, please report the problem to antimicro's <a href="https://github.com/AntiMicro/antimicro"><span style=" text-decoration: underline; color:#0057ae;">GitHub page</span></a> so that the program can be edited to support it directly. As it is, a custom prefix is added to unknown values so they can still be used; the main problem is that the profile will no longer be portable.</p></body></html> Event Handler: Native Key Value: 0x00000000 Qt Key Value: antimicro Key Value: QObject Super Menu Menu Mute Vol+ Vol- Play/Pause Play Pause Pausar Prev Next Next Mail Home Home Media Search Daemon launched Failed to launch daemon Launching daemon Display string "%1" is not valid. Failed to set a signature id for the daemon Failed to change working directory to / Quitting Program # of joysticks found: %1 List Joysticks: --------------- Joystick %1: Index: %1 GUID: %1 Name: %1 Yes No Game Controller: %1 # of Axes: %1 # of Buttons: %1 # of Hats: %1 Attempting to use fallback option %1 for event generation. Failed to open event generator. Exiting. Using %1 as the event generator. Could not raise process priority. QuickSetDialog Quick Set Definir rápido <html><head/><body><p>Please press a button or move an axis on %1 (<span style=" font-weight:600;">%2</span>).<br/>A dialog window will then appear which will<br/>allow you to make an assignment.</p></body></html> Quick Set %1 SetAxisThrottleDialog Throttle Change Suprimir Rápido The throttle setting for Axis %1 has been changed. Would you like to distribute this throttle change to all sets? A configuração do acelerador para o eixo %1 foi alterada. Gostaria de distribuir essa mudança de aceleração para todos os conjuntos? SetJoystick Set %1: %2 Set %1 SetNamesDialog Set Name Settings Set 1 Set 2 Set 3 Set 4 Set 5 Set 6 Set 7 Set 8 Name SimpleKeyGrabberButton Mouse Mouse SpringModeRegionPreview Spring Mode Preview UInputEventHandler Could not find a valid uinput device file. Please check that you have the uinput module loaded. lsmod | grep uinput Could not open uinput device file Please check that you have permission to write to the device Using uinput device file %1 UInputHelper a a b b c c d d e e f f g g h h i i j j k k l l m m n n o o p p q q r r s s t t u u v v w w x x y y z z Esc F1 F1 F2 F2 F3 F3 F4 F4 F5 F5 F6 F6 F7 F7 F8 F8 F9 F9 F10 F10 F11 F11 F12 F12 ` ` 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 0 0 - - = = BackSpace BackSpace Tab Tab [ [ ] ] \ \ CapsLock ; ; ' ' Enter Shift_L Shift_L , , . . / / Ctrl_L Super_L Super_L Alt_L Alt_L Space Espaço Alt_R Alt_R Menu Menu Ctrl_R Shift_R Shift_R Up Cima Left Esquerda Down Baixo Right Direita PrtSc Ins Del Home Home End End PgUp PgDn NumLock * * + + KP_Enter KP_Enter KP_1 KP_1 KP_2 KP_2 KP_3 KP_3 KP_4 KP_4 KP_5 KP_5 KP_6 KP_6 KP_7 KP_7 KP_8 KP_8 KP_9 KP_9 KP_0 KP_0 SCLK SCLK Pause Pausar Super_R Mute VolDn VolUp Play Stop Prev Next Next [NO KEY] [SEM TECLA] UnixWindowInfoDialog Captured Window Properties Information About Window Class: TextLabel Title: Path: Match By Properties Class Title Path VDPad VDPad VDPad VirtualKeyPushButton Space Espaço Tab Tab Shift (L) Shift (L) Shift (R) Shift (R) Ctrl (L) Ctrl (L) Ctrl (R) Ctrl (R) Alt (L) Alt (L) Alt (R) Alt (R) ` ` ~ ~ - - = = [ [ ] ] \ \ Caps Caps ; ; ' ' , , . . / / ESC ESC PRTSC PRTSC SCLK SCLK INS INS PGUP PGUP DEL DEL PGDN PGDN 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 0 0 NUM LK NUM LK * * + + E N T E R E N T E R < < : : Super (L) Menu Menu Up Cima Down Baixo Left Esquerda Right Direita VirtualKeyboardMouseWidget Keyboard Teclado Mouse Mouse Mouse Settings Configurações do Mouse Left Mouse Esquerda Up Mouse Cima Left Button Mouse Middle Button Mouse Right Button Mouse Wheel Up Mouse Roda pra Cima Wheel Left Mouse Roda pra Esquerda Wheel Right Mouse Roda pra Direita Wheel Down Mouse Roda pra Baixo Down Mouse Baixo Right Mouse Direita Button 4 Mouse Mouse 8 Mouse Button 5 Mouse Mouse 9 Mouse NONE NADA Applications Browser Back Browser Favorites Browser Forward Browser Home Browser Refresh Browser Search Browser Stop Calc Email Media Media Next Media Play Media Previous Media Stop Search Volume Down Volume Mute Volume Up VirtualMousePushButton INVALID INVÃLIDO WinAppProfileTimerDialog Capture Application After pressing the "Capture Application" button, please select the application window that you want to have a profile associated with. The active application will be captured after the selected number of seconds. Timer: Seconds Cancel WinExtras [NO KEY] [SEM TECLA] AntiMicro Profile X11Extras ESC ESC Tab Tab Space Espaço DEL DEL Return KP_Enter KP_Enter Backspace Retrocesso xinput extension was not found. No mouse acceleration changes will occur. xinput version must be at least 2.0. No mouse acceleration changes will occur. Virtual pointer found with id=%1. PtrFeedbackClass was not found for virtual pointer.No change to mouse acceleration will occur for device with id=%1 Changing mouse acceleration for device with id=%1 XMLConfigReader Could not write updated profile XML to file %1. XMLConfigWriter Could not write to profile at %1. antimicro-2.23/share/antimicro/translations/antimicro_de.ts000066400000000000000000011401111300750276700242500ustar00rootroot00000000000000 AboutDialog About Über Version Version <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Originally developed by Travis Nickles &lt;nickles.travis@gmail.com&gt;, now maintained by the AntiMicro group at https://github.com/AntiMicro.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Contributors:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;"><br /></span>Zerro Alvein</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">aybe</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jeff Backus &lt;jeff.backus@gmail.com&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Arthur Moore<br />Anton Tornqvist &lt;antont@inbox.lv&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7185</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">DarkStarSword</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">est31</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ProfessorKaos64</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">qwerty12</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA0</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Translators:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VaGNaroK &lt;vagnarokalkimist@gmail.com&gt; - Brazilian Portuguese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx - Chinese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Belleguic Terence &lt;hizo@free.fr&gt; - French</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Leonard Koenig &lt;leonard.r.koenig@googlemail.com&gt; - German</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phob - German</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">tou omiya - Japanese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Dmitriy Koshel &lt;form.eater@gmail.com&gt; - Russian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jay Alexander Fleming &lt;tito.nehru.naser@gmail.com&gt; - Serbian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">burunduk - Ukrainian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Flavio HR &lt;flavio.hrx@gmail.com&gt; - Spanish</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA - wazaaaaa00&lt;@&gt;gmail&lt;.&gt;com - Italian</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> Info Changelog Since December 30, 2012, I have been working on antimicro in my spare time. What originally started as a fork of QJoyPad and a way to learn proper event-driven programming has turned into something much bigger than I originally intended. Although I have spent a lot of time learning new techniques, finding out more about the domain of KB+M emulation, and spending Friday nights bashing my head against my keyboard, it has been a fun and enriching experience overall. The need for this program came from me using similar programs on Windows to play several games that did not provide native controller support. Although some alternatives existed on Linux, there wasn't really anything that I felt was good enough in terms of functionality or in-game controls in order to really enjoy games that I wanted to play with using KB+M emulation. QJoyPad was the main program that I had used in the past although it had aged a lot and it didn't provide some basic functionality that I thought was essential. The project was dead as it had not been updated in several years so I decided to make my own. Since then, I have tried to find out what the other programs do right and then improve upon it. I have also discovered some neat tricks along the way and I have learned more about how native gamepad controls are implemented in some games than I ever really wanted to know. Although there are definitely areas where this program could improve, I find that this program offers the best in-game control experience for playing older, and some newer, games that do not provide native controller support. Development of this program is not as high of a priority for me anymore. This is mainly due to the fact that the Steam Controller works pretty well for the task of playing PC games compared to using an Xbox 360 controller. However, it does look like there is still a reason for this program to exist for a while. Copyright: 2013 - 2016 Credits Mitwirkende antimicro <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">GNU GENERAL PUBLIC LICENSE</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Version 3, 29 June 2007</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Preamble</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Developers that use the GNU GPL protect your rights with two steps:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">(1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The precise terms and conditions for copying, distribution and modification follow.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">TERMS AND CONDITIONS</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">0. Definitions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;This License&quot; refers to version 3 of the GNU General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Copyright&quot; also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;The Program&quot; refers to any copyrightable work licensed under this License. Each licensee is addressed as &quot;you&quot;. &quot;Licensees&quot; and &quot;recipients&quot; may be individuals or organizations.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;modify&quot; a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a &quot;modified version&quot; of the earlier work or a work &quot;based on&quot; the earlier work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;covered work&quot; means either the unmodified Program or a work based on the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;propagate&quot; a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;convey&quot; a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An interactive user interface displays &quot;Appropriate Legal Notices&quot; to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">1. Source Code.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;source code&quot; for a work means the preferred form of the work for making modifications to it. &quot;Object code&quot; means any non-source form of a work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;Standard Interface&quot; means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;System Libraries&quot; of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A &quot;Major Component&quot;, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;Corresponding Source&quot; for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source for a work in source code form is that same work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">2. Basic Permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">3. Protecting Users' Legal Rights From Anti-Circumvention Law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">4. Conveying Verbatim Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">5. Conveying Modified Source Versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) The work must carry prominent notices stating that you modified it, and giving a relevant date.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to &quot;keep intact all notices&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an &quot;aggregate&quot; if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">6. Conveying Non-Source Forms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;User Product&quot; is either (1) a &quot;consumer product&quot;, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, &quot;normally used&quot; refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Installation Information&quot; for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">7. Additional Terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Additional permissions&quot; are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Limiting the use for publicity purposes of names of licensors or authors of the material; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All other non-permissive additional terms are considered &quot;further restrictions&quot; within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">8. Termination.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">9. Acceptance Not Required for Having Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">10. Automatic Licensing of Downstream Recipients.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An &quot;entity transaction&quot; is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">11. Patents.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;contributor&quot; is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's &quot;contributor version&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A contributor's &quot;essential patent claims&quot; are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, &quot;control&quot; includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">In the following three paragraphs, a &quot;patent license&quot; is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To &quot;grant&quot; such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. &quot;Knowingly relying&quot; means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A patent license is &quot;discriminatory&quot; if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">12. No Surrender of Others' Freedom.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">13. Use with the GNU Affero General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">14. Revised Versions of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License &quot;or any later version&quot; applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">15. Disclaimer of Warranty.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM &quot;AS IS&quot; WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">16. Limitation of Liability.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">17. Interpretation of Sections 15 and 16.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.</span></p></body></html> About Development Über die Entwicklung License Lizenz Program Version %1 Programmversion %1 Program Compiled on %1 at %2 Programm kompiliert am %1 um %2 Built Against SDL %1 Nutzt SDL %1 Running With SDL %1 Läuft mit SDL %1 Using Qt %1 Benutzt Qt %1 Using Event Handler: %1 AddEditAutoProfileDialog Auto Profile Dialog Auto-Profil-Dialog Profile: Profil: Browse Durchsuchen Window: Fenster: Select Window. Click on the appropriate application window and the application file path will be populated in the form. Wählen Sie das Fenster. Klicken Sie auf das entsprechende Anwendungs-Fenster und der Anwendungs-Dateipfad wird in das Formular eingetragen. Detect Window Properties Erkenne Fenstereigenschaften Class: Klasse: Title: Titel: Application: Anwendung: Select Wähle Devices: Geräte: Select this profile to be the default loaded for the specified device. The selection will be used instead of the all default profile option. Wählen Sie dieses Profil als Standard für das jeweilige Gerät. Diese Auswahl wird anstatt jeder anderen Standardeinstellung genutzt. Set as Default for Controller Setze als Standardcontroller A different profile is already selected as the default for this device. Ein anderes Profil ist bereits als Standard für dieses Gerät ausgewählt. Current (%1) Aktuell (%1) Open Config Konfiguration öffnen Select Program Wähle Anwendung Programs (*.exe) Programme (*.exe) Please use the main default profile selection. Bitte benutzen Sie die Standard-Profilauswahl. Please select a window by using the mouse. Press Escape if you want to cancel. Bitte wählen Sie mit der Maus ein Fenster aus. Escape drücken um abzubrechen. Capture Application Window Anwendungsfenster auswählen Could not obtain information for the selected window. Konnte nicht Information für das ausgewählte Fenster gewinnen. Application Capture Failed Anwendungsauswahl fehlgeschlagen Profile file path is invalid. Profil-Dateipfad ist ungültig. No window matching property was specified. Kein zugehöriges Fenster wurde spezifiziert. Program path is invalid or not executable. Programmpfad ist ungültig oder nicht ausführbar. File is not an .exe file. Datei ist keine .exe-Datei. No window matching property was selected. Kein zugehöriges Fenster wurde ausgewählt. AdvanceButtonDialog Advanced Erweitert Assignments Zuweisungen Toggle Umschalten Turbo Turbo Set Selector Wähle Set Blank or KB/M Leer oder KB/M Hold Halten Pause Pause Cycle Kreislauf Distance Distanz Insert Einfügen Delete Entfernen Clear All Leeren Time: Zeit: 0.01s 0.01s 0s 0s Insert a pause that occurs in between key presses. Fügt eine Pause zwischen den Tasten ein. Release Freigeben Insert a new blank slot. Fügt eine neue leere Aktion hinzu. Delete a slot. Löscht eine Aktion. Clear all currently assigned slots. Löscht alle zugewiesenen Aktionen. Specify the duration of an inserted Pause or Hold slot. Gibt die Dauer der hinzugefügten Pause- oder Haltenaktion an. 0m 0m &Mouse Speed Mod: Specify the range past an axis dead zone in which a sequence of actions will execute. Gibt die Distanz der Achse zur "Dead Zone" an, in der die Sequenz an Aktionen ausgeführt wird. Distance: Distanz: % % Mouse Mod Maus Mod Press Time Druckzeit Delay Verzögerung Execute Load Laden Set Change Wähle Änderung Text Entry Placeholder Platzhalter 0 0 Mouse Speed Mod: Maus Mod Geschwindigkeit: Set the percentage that mouse speeds will be modified by. Stellen Sie den Prozentsatz ein um der die Mausgeschwindigkeit modifiziert werden soll. Auto Reset Cycle After Zyklus automatisch neustarten nach seconds Sekunden Executable: ... Arguments: Enabled Aktiviert Mode: Modus: <html><head/><body><p>Normal: Repeatedly press and release a button by the chosen rate.</p><p>Gradient: Modify the button press and button release delay based on how far an axis has been moved. The rate will remain the same.</p><p>Pulse: Modify how many times a button is pressed and released per second. The button delay will remain the same.</p></body></html> <html><head/><body><p>Normal: Wiederholt mit der eingestellten Rate Taste drücken und loslassen.</p><p>Verlaufend: Ändere die Auslösen-/Loslassen-Verzögerung aufgrund wie weit die eine Achse bewegt wurde.</p><p>Pulsierend: Ändere wie häufig eine Taste pro Sekunde ausgelöst wurde. Die Verögerung bleibt gleich.</p></body></html> Normal Normal Gradient Verlaufend Pulse Pulsierend Delay: Verzögerung: 0.10s 0.10s Rate: Rate: 10.0/s 10.0/s Disabled Deaktiviert Select Set 1 One Way Wähle Set 1: einseitig Select Set 1 Two Way Wähle Set 1: wechselseitig Select Set 1 While Held Wähle Set 1: festgehalten Select Set 2 One Way Wähle Set 2: einseitig Select Set 2 Two Way Wähle Set 2: wechselseitig Select Set 2 While Held Wähle Set 2: festgehalten Select Set 3 One Way Wähle Set 3: einseitig Select Set 3 Two Way Wähle Set 3: wechselseitig Select Set 3 While Held Wähle Set 3: festgehalten Select Set 4 One Way Wähle Set 4: einseitig Select Set 4 Two Way Wähle Set 4: wechselseitig Select Set 4 While Held Wähle Set 4: festgehalten Select Set 5 One Way Wähle Set 5: einseitig Select Set 5 Two Way Wähle Set 5: wechselseitig Select Set 5 While Held Wähle Set 5: festgehalten Select Set 6 One Way Wähle Set 6: einseitig Select Set 6 Two Way Wähle Set 6: wechselseitig Select Set 6 While Held Wähle Set 6: festgehalten Select Set 7 One Way Wähle Set 7: einseitig Select Set 7 Two Way Wähle Set 7: wechselseitig Select Set 7 While Held Wähle Set 7: festgehalten Select Set 8 One Way Wähle Set 8: einseitig Select Set 8 Two Way Wähle Set 8: wechselseitig Select Set 8 While Held Wähle Set 8: festgehalten sec. Sek. /sec. /Sek. Set %1 Set %1 Select Set %1 Wähle Set %1 One Way Einweg Two Way Zweiwege While Held Solang wie gehalten Choose Executable Slots past a Cycle action will be executed on the next button press. Multiple cycles can be added in order to create partitions in a sequence. Delays the time that the next slot is activated by the time specified. Slots activated before the delay will remain active after the delay time has passed. Distance action specifies that the slots afterwards will only be executed when an axis is moved a certain range past the designated dead zone. Insert a hold action. Slots after the action will only be executed if the button is held past the interval specified. Chose a profile to load when this slot is activated. Wähle ein Profil zum Laden wenn dieser Slot aktiviert ist. Mouse mod action will modify all mouse speed settings by a specified percentage while the action is being processed. This can be useful for slowing down the mouse while sniping. Specify the time that keys past this slot should be held down. Insert a release action. Slots after the action will only be executed after a button release if the button was held past the interval specified. Change to selected set once slot is activated. Wechsle zu ausgewähltem Set wenn Slot aktiviert ist. Full string will be typed when a slot is activated. Execute program when slot is activated. Choose Profile Wähle Profil Config Files (*.amgp *.xml) Konfigurationsdateien (*.amgp *.xml) AdvanceStickAssignmentDialog Stick/Pad Assignment Stick/Pad Zuweisung Sticks Sticks DPads DPads %1 (Joystick %2) %1 (Joystick %2) Stick 1 Stick 1 Enabled Aktiviert Assign Zuweisen X Axis: X Achse: Y Axis: Y Achse: Stick 2 Stick 2 Number of Physical DPads: %1 Nummer der physischen DPads: %1 Virtual DPad 1 Virtueller DPad 1 Up: Hoch: Down: Runter: Note: This window is meant for backwards compatibility with profiles made before antimicro 2.0. Since version 2.0, use of the Game Controller Mapping window is preferred. Hinweis: Dieses Fenster ist nur zur Rückwärtskompatibilität zu Profilen für antimicro vor 2.0 gedacht. Seit Version 2.0 wird das Spielecontroller-Zuweisungsfenster bevorzugt. Left: Links: Right: Rechts: Axis %1 Achse %1 Axis %1 - Achse %1 - Axis %1 + Achse %1 + Button %1 Button %1 Move stick 1 along the X axis Bewege Stick 1 entlang der X Achse Move stick 1 along the Y axis Bewege Stick 1 entlang der Y Achse Move stick 2 along the X axis Bewege Stick 2 entlang der X Achse Move stick 2 along the Y axis Bewege Stick 2 entlang der Y Achse Press a button or move an axis Drücke einen Button oder bewege eine Achse AxisEditDialog Axis Achse Mouse (Horizontal) Maus (Horizontal) Mouse (Inverted Horizontal) Maus (Invertiert Horizontal) Mouse (Vertical) Maus (Vertikal) Mouse (Inverted Vertical) Maus (Invertiert Vertikal) Arrows: Up | Down Pfeiltasten: Hoch | Runter Arrows: Left | Right Pfeiltasten: Links | Rechts Keys: W | S Tasten: W | S Keys: A | D Tasten: A | D NumPad: KP_8 | KP_2 Nummernblock: KP_8 | KP_2 NumPad: KP_4 | KP_6 Nummernblock: KP_4 | KP_6 None Nichts Set the value to use as the limit for an axis. Useful for a worn out analog stick. Setze einen Wert als Limitierung einer Achse. Nützlich bei abgenutzten Analogsticks. Negative Half Throttle Negative Halbbeschleunigung Positive Half Throttle Positive Halbbeschleunigung Name: Name: Specify the name of an axis. Vergebe den Namen der Achse. Mouse Settings Mauseinstellungen Set the value of the dead zone for an axis. Bestimmt den Wert der Dead Zone einer Achse. Presets: Vorgaben: Dead Zone: Dead Zone: Max Zone: Max Zone: [NO KEY] [KEINE TASTE] Throttle setting that determines the behavior of how to interpret an axis hold or release. Beschleunigung gibt das Verhalten an wie das Halten oder Loslassen einer Achse interpretiert wird. Negative Throttle Negative Beschleunigung Normal Normal Positive Throttle Positive Beschleunigung Current Value: Aktueller Wert: Set Set Set %1 Set %1 Left Mouse Button Linke Maustaste Right Mouse Button Rechte Maustaste ButtonEditDialog Dialog Dialog To make a new assignment, press any keyboard key or click a button in the Keyboard or Mouse tab Um eine neue Zuweisung zu machen, drück eine Taste oder klick einen Button im Tastatur oder Mausreiter Placeholder Platzhalter Toggle Umschalten Enables a key press or release to only occur when a controller button is pressed. Tasten werden erst, wenn der Button gedrückt wurde entweder festgehalten oder frei gelassen. Enables rapid key presses and releases. Turbo controller. Aktiviert schnelles Tastendrücken oder Freigeben. Autofeuer. Turbo Turbo Current: Aktuell: Slots Slots Na&me: Specify the name of a button. Vergebe den Namen des Buttons. Action: Aktion: Specify the action that will be performed in game while this button is being used. Gibt die Aktion des Buttons an, die Ingame genutzt wird. Advanced Advanced Set Set Set %1 Set %1 CapturedWindowInfoDialog Captured Window Properties Erkannte Fenstereigenschaften Information About Window Fensterinformationen Class: Klasse: TextLabel Title: Titel: Path: Pfad: Match By Properties Class Klasse Title Titel Path Pfad Full Path vollständiger Pfad File Name Dateinmae CommandLineUtility Profile location %1 is not an XML file. Profilort %1 ist keine XML Datei. Profile location %1 does not exist. Profilort %1 existiert nicht. An invalid set number '%1' was specified. Controller identifier '%s'' is not a valid value. No display string was specified. Controller identifier is not a valid value. Controllernummer ist keine gültige Ziffer. No set number was specified. Kein Set gewählt. No controller was specified. Kein Controller wurde spezifiert. An invalid event generator was specified. Ein ungültiger Ereignisgenerator wurde angegeben. No event generator string was specified. Kein Ereignesgenerator String wurde angegeben. Qt style flag was detected but no style was specified. Qt style Parameter erkannt, aber kein Style spezifiziert. No log level specified. Kein Log-Level angegeben. antimicro version antimicro Version Usage: antimicro [options...] [profile] Options Optionen Print help text. diese Hilfe ausgeben. Print version information. Programmversion ausgeben. Launch program in system tray only. Nur im Systemtray starten. Launch program with the tray menu disabled. Starten mit deaktiviertem Systemtray. Launch program without the main window displayed. Starten mit verstecktem Hauptfenster. Launch program with the configuration file selected as the default for selected controllers. Defaults to all controllers. Programm mit ausgewählter Konfigurations- datei als Standard für alle Controller starten. Apply configuration file to a specific controller. Value can be a controller index, name, or GUID. Übernehme Konfigurationsdatei zu dem angegebenen Controller. Wert kann Controllerindex, Name oder GUID sein. Unload currently enabled profile(s). Value can be a controller index, name, or GUID. Aktuell aktiviertes Profil entladen. Wert kann Controllerindex, Name oder GUID sein. Start joysticks on a specific set. Value can be a controller index, name, or GUID. Starte Joysticks beim angegebenen Set. Wert kann Controllerindex, Name oder GUID sein. Advance profile loading set options. Launch program as a daemon. Starte Programm als Dienst. Enable logging. Aktiviere Logging. Use specified display for X11 calls. Useful for ssh. Nutze angegebenes Display für X11. Nützlich für ssh. Choose between using XTest support and uinput support for event generation. Default: xtest. Wähle zwischen XTest Unterstützung und uinput Unterstützung zur Ereignisgenerierung. Standard: xtest. Choose between using SendInput and vmulti support for event generation. Default: sendinput. Wähle zwischen der Nutzung von SendInput und vmulti support zur Ereignisgenerierung. Standard: sendinput. Print information about joysticks detected by SDL. Zeige Informationen über Joysticks die von SDL erkannt wurden. Open game controller mapping window of selected controller. Value can be a controller index or GUID. Öffne Gamecontrollerzuweisungs-Fenster für den ausgewählten Controller. Wert kann ein Controller Index oder GUID sein. DPadContextMenu Mouse (Normal) Maus (Normal) Mouse (Inverted Horizontal) Maus (Invertiert Horizontal) Mouse (Inverted Vertical) Maus (Invertiert Vertikal) Mouse (Inverted Horizontal + Vertical) Maus (Invertiert Horizontal + Vertikal) Arrows Pfeiltasten Keys: W | A | S | D Tasten: W | A | S | D NumPad Nummerntastatur None Nichts Standard Standard Eight Way 8-Weg 4 Way Cardinal 4-Wege kardinal 4 Way Diagonal 4-Wege diagonal Mouse Settings Mauseinstellungen DPadEditDialog Dialog Dialog Presets: Vorgaben: Mouse (Normal) Maus (Normal) Mouse (Inverted Horizontal) Maus (Invertiert Horizontal) Mouse (Inverted Vertical) Maus (Invertiert Vertikal) Mouse (Inverted Horizontal + Vertical) Maus (Invertiert Horizontal + Vertikal) Arrows Pfeiltasten Keys: W | A | S | D Tasten: W | A | S | D NumPad Nummerntastatur None Nichts Dpad Mode: DPad Modus: &Name: 4 Way Cardinal 4-Wege kardinal 4 Way Diagonal 4-Wege diagonal DPad Delay: DPad-Verzögerung: Time lapsed before a direction change is taken into effect. Zeit abgelaufen bevor eine Richtungsänderung vollzogen wird. s Specify the name of a dpad. Vergebe den Namen des DPads. Mouse Settings Mauseinstellungen Standard Standard Standard: 8 region dpad with two direction buttons active when the dpad is in a diagonal region. Eight Way: 8 region dpad with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region dpad with regions corresponding to the cardinal directions of the dpad. Useful for menus. 4 Way Diagonal: 4 region dpad with each region corresponding to a diagonal zone. Eight Way 8-Wege Set Set Set %1 Set %1 EditAllDefaultAutoProfileDialog Default Profile Standardprofil Profile: Profil: Browse Durchsuchen Open Config Konfiguration öffnen Profile file path is invalid. Profil-Dateipfad ist ungültig. ExtraProfileSettingsDialog Extra Profile Settings Weitere Profileinstellungen Key Press Time: Tastendruckzeit: 0.00 ms 0.00 ms Profile Name: Profilname: s s GameController Game Controller Gamecontroller GameControllerDPad DPad DPad GameControllerMappingDialog Game Controller Mapping Game Controller Zuweisung <html><head/><body><p>antimicro makes use of the <a href="https://wiki.libsdl.org/CategoryGameController"><span style=" text-decoration: underline; color:#0057ae;">Game Controller API</span></a> provided by SDL 2 in order to abstract various gamepads to fit a unified standard. In order to make a button assignment, please highlight the mapping cell for the appropriate button row below. You can then press a button or move an axis on your gamepad and the cell will update with the physical button or axis that will be used.</p><p>antimicro will use the mapping that you specify to save a mapping string that will be loaded into SDL.</p></body></html> A A B B X X Y Y Back Zurück Start Start Guide Guide Left Shoulder linker Schulterbutton Right Shoulder rechter Schulterbutton Left Stick Click linker Stick Klick Right Stick Click rechter Stick Klick Left Stick X linker Stick X Left Stick Y linker Stick Y Right Stick X rechter Stick X Right Stick Y rechter Stick Y Left Trigger linker Trigger Right Trigger rechter Trigger DPad Up DPad Hoch DPad Left DPad Links DPad Down DPad Runter DPad Right DPad Rechts Mapping Zuweisung SDL 2 Game Controller Mapping String SDL 2 Game Controller Zuweisungsstring Last Axis Event: Letztes Achsenereignis: Current Axis Detection Dead Zone: Aktuelle Achsenerkennungs Totzone: 5000 5000 10000 10000 15000 15000 20000 20000 25000 25000 30000 30000 32000 32000 Game Controller Mapping (%1) (#%2) Spielecontroller Zuweisung (%1) (#%2) Discard Controller Mapping? Controller Zuweisung verwerfen? Discard mapping for this controller? If discarded, the controller will be reverted to a joystick once you refresh all joysticks. Zuweisung für diesen Controller verwerfen? Wenn verworfen, kehrt der Controller zu einem Joystick zurück wenn alle Joysticks aktualisiert werden. GameControllerSet Back Zurück Guide Handbuch Start Start LS Click LS Klick RS Click RS Klick L Shoulder L Schulter R Shoulder R Schulter L Trigger L Trigger R Trigger R Trigger GameControllerTrigger Trigger Trigger JoyAxis Axis Achse JoyAxisButton Negative Negativ Positive Positiv Unknown Unbekannt Button Button JoyAxisContextMenu Mouse (Horizontal) Maus (Horizontal) Mouse (Inverted Horizontal) Maus (Invertiert Horizontal) Mouse (Vertical) Maus (Vertikal) Mouse (Inverted Vertical) Maus (Invertiert Vertikal) Arrows: Up | Down Pfeiltasten: Hoch | Runter Arrows: Left | Right Pfeiltasten: Links | Rechts Keys: W | S Tasten: W | S Keys: A | D Tasten: A | D NumPad: KP_8 | KP_2 Nummernblock: KP_8 | KP_2 NumPad: KP_4 | KP_6 Nummernblock: KP_4 | KP_6 None Nichts Mouse Settings Mauseinstellungen Left Mouse Button Linke Maustaste Right Mouse Button Rechte Maustaste JoyButton Processing turbo for #%1 - %2 Finishing turbo for button #%1 - %2 Processing press for button #%1 - %2 Processing release for button #%1 - %2 Distance change for button #%1 - %2 Button Button [NO KEY] [KEINE TASTE] [Set %1 1W] [Set %1 2W] [Set %1 WH] JoyButtonContextMenu Toggle Umschalten Turbo Turbo Clear Leeren Set Select Set-Auswahl Disabled Deaktiviert Set %1 Set %1 Set %1 1W Set %1 1W Set %1 2W Set %1 2W Set %1 WH JoyButtonSlot Mouse Maus Up Hoch Down Runter Left Links Right Rechts LB LB MB MB RB RB B4 B4 B5 B5 Pause Pause Hold Halten Cycle Kreislauf Distance Distanz Release Freigeben Mouse Mod Maus Mod Press Time Druckzeit Delay Verzögerung Load %1 Lade %1 Set Change %1 [Text] %1 [Exec] %1 [NO KEY] [KEINE TASTE] JoyControlStick Stick Stick JoyControlStickButton Up Hoch Down Runter Left Links Right Rechts Button Button JoyControlStickContextMenu Mouse (Normal) Maus (Normal) Mouse (Inverted Horizontal) Maus (Invertiert Horizontal) Mouse (Inverted Vertical) Maus (Invertiert Vertikal) Mouse (Inverted Horizontal + Vertical) Maus (Invertiert Horizontal + Vertikal) Arrows Pfeiltasten Keys: W | A | S | D Tasten: W | A | S | D NumPad Nummerntastatur None Nichts Standard Standard Eight Way 8-Wege 4 Way Cardinal 4-Wege kardinal 4 Way Diagonal 4-Wege diagonal Mouse Settings Mauseinstellungen JoyControlStickEditDialog Dialog Dialog X: X: 0 0 Y: Y: Distance: Distanz: Presets: Vorgaben: Mouse (Normal) Maus (Normal) Mouse (Inverted Horizontal) Maus (Invertiert Horizontal) Mouse (Inverted Vertical) Maus (Invertiert Vertikal) Mouse (Inverted Horizontal + Vertical) Maus (Invertiert Horizontal + Vertikal) Arrows Pfeiltasten Keys: W | A | S | D Tasten: W | A | S | D NumPad Nummerntastatur None Nichts Stick Mode: Stickmodus: Standard: 8 region stick with two direction buttons active when the stick is in a diagonal region. Eight Way: 8 region stick with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region stick with regions corresponding to the cardinal directions of the stick. Useful for menus. 4 Way Diagonal: 4 region stick with each region corresponding to a diagonal zone of the stick. Standard: 8-Wege-Stick mit zwei Richtungstasten aktiv wenn der Stick in diagonaler Richtung ist. 8-Wege: 8-Wege-Stick mit jedem Weg einer eigenen Taste entsprechend. Nur eine Taste ist gleichzeitig aktiv. Nützlich für "rougelike" Spiele. 4-Wege Kardinal: 4-Regionen-Stick, wobei jede Region einer Kardinal-/Himmelsrichtung des Sticks entspricht. Nützlich für Menüs. 4-Wege Diagonal: 4-Regionen-Stick, wobei jede Region einer Diagonal-Zone des Sticks entspricht. 4 Way Cardinal 4-Wege kardinal 4 Way Diagonal 4-Wege diagonal Dead zone value to use for an analog stick. Totzonenwert für Analogsticks. Value when an analog stick is considered moved 100%. Wert für den ein Analogstick als 100% ausgelenkt betrachtet wird. The area (in degrees) that each diagonal region occupies. Den Bereich (in Grad) die jede diagonale Region einnimmt. Square Stick: Percentage to modify a square stick coordinates to confine values to a circle % % Stick Delay: Stick Verzögerung: Time lapsed before a direction change is taken into effect. Abgelaufene Zeit bis eine Richtungsänderung wirksam wird. s Modifier: Modifikator: Edit button that is active while the stick is active. This button is useful for assigning zones with modifier keys that can be used to assign walk/run functionality to an analog stick. PushButton Name: Name: Specify the name of an analog stick. Vergebe den Namen eines Analogsticks. Mouse Settings Mauseinstellungen Standard Standard Bearing: % Safe Zone: Eight Way 8-Wege Dead Zone: Dead Zone: Max Zone: Max Zone: Diagonal Range: diagonale Reichweite: Set Set Set %1 Set %1 JoyControlStickModifierButton Modifier Modifikator JoyDPad DPad DPad JoyDPadButton Up Hoch Down Runter Left Links Right Rechts Button Button JoyTabWidget <New> <Neu> Remove Entfernen Remove configuration from recent list. Entferne Konfiguration aus den letzten Einträgen. Load Laden Load configuration file. Lade Konfigurationsdatei. Save Speichern Save changes to configuration file. Änderungen in Konfigurationsdatei speichern. Save As Speichern unter Save changes to a new configuration file. Änderungen in neue Konfigurationsdatei speichern. Sets Sets Copy from Set Settings Einstellungen Set 1 Set 1 Set 2 Set 2 Set 3 Set 3 Set 4 Set 4 Set 5 Set 5 Set 6 Set 6 Set 7 Set 7 Set 8 Set 8 Stick/Pad Assign Stick/Pad Zuweisung Controller Mapping Controllerzuweisung Quick Set Schnellkonfiguration Names Namen Toggle button name displaying. Buttonnamendarstellung wechseln. Pref Einst Change global profile settings. Globale Profileinstellungen ändern. Reset Reset Revert changes to the configuration. Reload configuration file. Änderungen der Konfiguration zurücksetzen. Neuladen der Konfiguration. Open Config Konfiguration öffnen Config Files (*.amgp *.xml) Konfigurationsdateien (*.amgp *.xml) Config File (*.%1.amgp) Konfigurationsdatei (*.%1.amgp) Save Profile Changes? Profiländerungen speichern? Changes to the new profile have not been saved. Would you like to save or discard the current profile? Änderungen am neuen Profil wurden nicht gespeichert. Möchten Sie das aktuelle Profil speichern oder verwerfen? Changes to the profile "%1" have not been saved. Would you like to save or discard changes to the current profile? Änderungen am neuen Profil %1 wurden nicht gespeichert. Möchten Sie das aktuelle Profil speichern oder verwerfen? Sticks Sticks DPads DPads No buttons have been assigned. Please use Quick Set to assign keys to buttons or disable hiding empty buttons. Es wurden keine Tasten zugewiesen. Bitte verwenden Sie den Schnellkonfiguration um Tasten zuzuweisen oder deaktivieren Sie das Ausblenden leerer Tasten. Set %1: %2 Set %1: %2 Set %1 Set %1 Copy Set Assignments Kopiere Set-Zuweisungen Are you sure you want to copy the assignments and device properties from %1? Sind Sie sicher, dass Sie die Aufgaben-und Geräteeigenschaften von%1 kopieren möchten? Save Config Konfiguration speichern Set Set Joystick Joystick Joystick JoystickStatusWindow Properties Eigenschaften Details Details Name: Name: %1 %1 Number: Nummer: Axes: Achsen: Buttons: Buttons: Hats: Hats: GUID: GUID: Game Controller: Gamecontroller: Axes Achsen Buttons Buttons Hats Hats %1 (#%2) Properties %1 (#%2) Eigenschaften Axis %1 Achse %1 Hat %1 Hat %1 No Nein Yes Ja MainSettingsDialog Edit Settings Einstellungen ändern General Allgemein Controller Mappings Controllerzuweisungen Language Sprache Auto Profile Autoprofil Mouse Maus <html><head/><body><p>Specify the default directory that the program should use in file dialogs when loading a profile or saving a new profile.</p></body></html> <html><head/><body><p>Geben Sie das Standardverzeichnis an, dass das Programm im Dateidialog verwenden soll beim Laden oder Speichern eines Profils.</p></body></html> Recent Profile Count: Einträge an Profilen merken: <html><head/><body><p>Number of profiles that can be placed in recent profile list. 0 will result in the program not enforcing a limit on the number of profiles displayed.</p></body></html> <html><head/><body><p>Anzahl der Profile, die in den letzten Profilen-Liste platziert werden können. 0 = keine Begrenzung.</p></body></html> Gamepad Poll Rate: Change the poll rate that the program uses to discover new events from gamepads. Defaults to 10 ms. Reducing the poll rate value could cause the application to use more CPU power so please test the setting that you use before using antimicro unattended. Hide main window when the main window close button is clicked instead of quitting the program. Verstecke Hauptfenster anstatt es zu schließen, wenn die "Schließen"-Schaltfläche gedrückt wurde. Close To Tray Schließen im Tray Have Windows start antimicro at system startup. Lade antimicro beim Systemstart. Launch At Windows Startup Beim Windows-Start starten Display recent profiles for all controllers as a single list in the tray menu. Defaults to using sub-menus. Zeige die zuletzt benutzten Profile aller Controller als eine Liste anstatt als Untermenüs. Single Profile List in Tray Einzelprofil-Menü im Tray Have the program minimize to the taskbar. By default, the program minimizes to the system tray if available. Minimiere das Programm in die Taskleiste. Standardmäßig wird AntiMicro, falls möglich, in das System-Tray minimiert. Minimize to Taskbar In die Taskleiste minimieren This option will cause the program to hide all buttons that have no slots assigned to them. The Quick Set dialog window will have to be used to bring up the edit dialog for gamepad buttons. Diese Option versteckt alle Tasten denen keine Aktion zugeordnet wird. Der Schnelleinstellungs-Dialog muss benutzt werden um die Editier-Einstellungen aufzurufen. Hide Empty Buttons Verstecke leere Schaltflächen When the program is launched, open the last known profile that was opened during the previous session. Wenn das Programm gestartet wurde, öffne das zuletzt benutzte Profil. Auto Load Last Opened Profile Zuletzt geöffnetes Profil automatisch öffnen Only show the system tray icon when the program first launches. Zeige das System-Tray-Icon nur, wenn das Programm zum ersten Mal startet. Launch in Tray Starten im Tray Associate .amgp files with antimicro in Windows Explorer. Assoziiere .amgp-Dateien mit antimicro im Windows Explorer. Associate Profiles Assoziiere Profile Key Repeat Tastenanschlag Active keys will be repeatedly pressed when this option is enabled. Dauerhaft gedrückte Tasten werden wiederholt gedrückt, wenn diese Option aktiviert ist. Enable Aktivieren Specifies how much time should elapse before key repeating begins. Bestimmt die Zeit die abläuft bis das Wiederholen des Tastenanschlags beginnt. Specifies how many times key presses will be performed per seconds. Bestimmt wie oft Tastenanschläge pro Sekunde durchgeführt werden. <html><head/><body><p>antimicro has been translated into many different languages by contributors. By default, the program will choose an appropriate translation based on your system's locale setting. However, you can make antimicro load a different translation depending on the language that you choose from the list below.</p></body></html> <html><head/><body><p>antimicro wurde durch Mitwirkende in viele verschiedene Sprachen übersetzt. Standardmäßig wählt das Programm ein die entsprechende Übersetzung anhand der Einstellung Ihres Systems. Jedoch können Sie antimicro eine andere Übersetzung anhand der Sprache von der Liste hierunter wählen.</p></body></html> French Französisch Italian Japanese Russian Russisch Serbian Serbisch Simplified Chinese Ukrainian Ukrainisch Class Klasse Title Titel Program Programm Disable the "Enhanced Pointer Precision" Windows setting while antimicro is running. Disabling "Enhanced Pointer Precision" will allow mouse movement within antimicro to be more precise. Deaktiviere die "Zeigerbeschleunigung verbessern" Windowseinstellung während antimicro läuft. Dies erlaubt präzisere Mausbewegungen in antimicro. Disable Enhance Pointer Precision Deaktiviere "Zeigerbeschleunigung verbessern" Smoothing Glättung Histor&y Size: Weight &Modifier: Refresh Rate: Wiederholrate: The refresh rate is the amount of time that will elapse in between mouse events. Please be cautious when editing this setting as it will cause the program to use more CPU power. Setting this value too low can cause system instability. Please test the setting before using it unattended. Spring Quelle Screen: Bildschirm: Utilize the specified screen for spring mode. On Linux, the default is to use the primary screen. On Windows, the default is to use all available screens. Accel Numerator: 0 0 Accel Denominator: Accel Threshold: If the acceleration values for the virtual mouse have been changed by a different process, particularly when quitting an older game, then you might want to reset the acceleration values used by the virtual mouse. Reset Acceleration Delay: Verzögerung: Profi&le Directory: ms ms Rate: Rate: times/s mal/s Below is a list of the custom mappings that have been saved. You can use the following table to delete mappings or have mappings temporarily disabled. You can also disable mappings that are included with SDL; just insert a new row with the appropriate joystick GUID and check disable. Settings will not take affect until you either refresh all joysticks or unplug that particular joystick. Unten finden Sie eine Liste der benutzerdefinierten Zuordnungen, die gespeichert werden können. Sie können die folgende Tabelle verwenden, um Zuordnungen zu löschen bzw. Zuordnungen vorübergehend zu deaktivieren. Sie können auch Abbildungendeaktivieren, die in SDL enthalten sind, nur eine neue Zeile einfügen mit dem entsprechenden Joystick-GUID und prüfen deaktivieren. Die Einstellungen werden nicht wirksam werden, bis Sie entweder alle Joysticks aktualisieren oder diesen bestimmten Joystick trennen. GUID GUID Mapping String Zuweisungsstring Disable? Deaktivieren? Delete Löschen Insert Einfügen Default Standard Brazilian Portuguese Brasilianisches Portugiesisch English Englisch German Deutsch Active Aktiv Devices: Geräte: All Alles Device Gerät Profile Profil Default? Standard? Add Hinzufügen Edit Editieren Also, Windows users who want to use a low value should also check the "Disable Enhance Pointer Precision" checkbox if you haven't disabled the option in Windows. Außerdem, Windows-Nutzer die einen geringen Wert nutzen möchten, sollten auch das "Deaktiviere 'Zeigerbeschleunigung verbessern'" Kontrollkästchen aktivieren, wenn die Option nicht in Windows deaktiviert ist. Select Default Profile Directory Wähle das Standard-Profil-Verzeichnis Are you sure you want to delete the profile? Sind Sie sicher, dass Sie das Profil löschen möchten? MainWindow No Joysticks have been found. Please plug in a joystick and then choose the "Update Joysticks" option in the main menu Keine Joysticks gefunden. Stecken Sie eine Joystick ein und wählen Sie dann die Option "Joysticks aktualisieren" im Hauptmenü aus &App &Anwendung Stick/Pad Assign Stick/Pad Zuweisung &Options &Optionen antimicro If events are not seen by a game, please click here to run this application as the Adminstrator. Wenn die Ereignisse nicht erkannt werden, klicken Sie hier um als Administrator neuzustarten. &Help &Hilfe &Quit B&eenden Ctrl+Q Strg+Q &Update Joysticks &Joysticks aktualisieren Ctrl+U Strg+U &Hide &Verstecken Ctrl+H Strg+H &About Ü&ber Ctrl+A Strg+A About Qt Über Qt Properties Eigenschaften Key Checker Tastenkontrolle Home Page Webseite GitHub Page GitHub-Webseite Game Controller Mapping Gamecontroller-Zuweisung Settings Einstellungen Wiki Could not find a proper controller identifier. Exiting. (%1) (%1) Open File Datei öffnen &Restore &Wiederherstellen Run as Administrator? Als Administrator ausführen? Are you sure that you want to run this program as Adminstrator? Some games run as Administrator which will cause events generated by antimicro to not be used by those games unless antimicro is also run as the Adminstrator. This is due to permission problems caused by User Account Control (UAC) options in Windows Vista and later. Sind Sie sicher, dass Sie das Programm als Administrator ausführen wollen? Manche Spiele laufen als Administrator, weshalb manche Ereignisse durch antimicro nicht von diesen Spielen erkannt werden, wenn antimicro nicht auch als Administrator ausgeführt wird. Dies geschieht auf Grund von Erlaubnisproblemen durch Benutzerkontensteuerung (UAC) Einstellungen in Windows Vista und neuer. Failed to elevate program Berechtigungserhöhung fehlgeschlagen Failed to restart this program as the Administrator Neustart als Administrator ist fehlgeschlagen Could not find controller. Exiting. MouseAxisSettingsDialog Mouse Settings - Mauseinstellungen - Set %1 Set %1 MouseButtonSettingsDialog Mouse Settings - Mauseinstellungen - Set %1 Set %1 MouseControlStickSettingsDialog Mouse Settings Mauseinstellungen Set %1 Set %1 MouseDPadSettingsDialog Mouse Settings Mauseinstellungen Set %1 Set %1 MouseSettingsDialog Mouse Settings Mauseinstellungen Mouse Mode: Mausmodus: Cursor mode is used to move the mouse cursor around the screen relative to its current position depending on how much you move an axis or if a button is pressed. Spring mode is used to move the mouse cursor from the center of the screen depending on how much you move an axis. The mouse cursor will be returned to the center of the screen when the axis is moved back to the dead zone. Der Zeigermodus wird verwendet, um den Mauszeiger relativ zu der aktuellen Position auf dem Bildschirm zu bewegen je nachdem, wie viel Sie eine Achse bewegen oder wenn eine Taste gedrückt wird. Der Sprungmodus bewegt den Mauspfeil vom Mittelpunkt des Bildschirms je nach Bewegung einer Achse. Der Mauspfeil wandert zu seinem Mittelpunkt, wenn eine Achse zur Dead Zone zurück kehrt. Cursor Zeiger Spring Sprung Acceleration: Beschleunigung: Enhanced Precision Verbesserte Präzision Linear linear Quadratic quadratisch Cubic kubisch Quadratic Extreme extrem quadratisch Power Function Power Funktion Easing Quadratic Easing Cubic Mouse Speed Settings Einstellungen der Mausgeschwindigkeit Enable to change the horizontal and vertical speed boxes at the same time. Aktivieren, um die horizontale und vertikale Geschwindigkeitseinstellungen zur gleichen Zeit zu ändern. Change Together Zusammen ändern Options for adding more acceleration to the mouse movement beyond what the acceleration curve would produce. Acceleration is added based on how quickly an axis is moved in one gamepad poll. This is meant to help work around some of the issues of the very limited input range available using typical gamepad analog sticks. Delta Acceleration &Multiplier: Mi&n Threshold: Horizontal Speed: Geschw. horizontal: 1 = 20 pps 1 = 20 pps Vertical Speed: Geschw. vertikal: Wheel Hori. Speed: Rad-Gesch. horizontal: Set the speed used for horizontal mouse wheel movement according to number of simulated notches per second. Stellen Sie die Geschwindigkeit für die horizontale Mausrad-Bewegung entsprechend der Anzahl der simulierten Raster pro Sekunde ein. Set the speed used for vertical mouse wheel movement according to number of simulated notches per second. Stellen Sie die Geschwindigkeit für die vertikale Mausrad-Bewegung entsprechend der Anzahl der simulierten Raster pro Sekunde ein. Sensitivit&y: For Power Function acceleration curve. Specifies the factor to use for curve sensitivity. When the value is above 1.0, the mouse movement will be accelerated faster at the low end of an axis. Easing Duration: s Extra Acceleration Zusätzliche Beschleunigung Multiplier: Multiplikator: Highest value to accelerate mouse movement by x Start %: Acceleration begins at this percentage of the base multiplier Minimum amount of axis travel required for acceleration to begin Max Threshold: Maximum axis travel before acceleration has reached the multiplier value E&xtra Duration: Curve: Ease Out Sine Ease Out Quad Ease Out Cubic Release Radius: Specifies that the spring area will be relative to the mouse position set by a non-relative spring. Wenn aktiviert, Besagt, dass das Ursprungs-arreal durch ein nicht-relativen Ursprung relativ zur Mausposition sein wird. Relative Relativ Mouse Status X: X: 0 (0 pps) Y: Y: 1 = 1 notch(es)/s 1 = 1 Raste Enhanced: Three tier curve that makes the mouse move slow on the low end of an axis and fast on the high end. Linear: Mouse moves proportionally to axis. Quadratic: Mouse accelerates slowly on low end. Cubic: Mouse accelerates slower than Quadratic. Quadratic Extreme: Raises mouse speed 1.5 times once 95% axis travel has been reached. Power Function: Allows for a more custom curve option. Easing Quadratic: Axis high end is gradually accelerated over a period of time using a Quadratic curve. Easing Cubic: Axis high end is gradually accelerated over a period of time using a Cubic curve. Hori&zontal Speed: &Vertical Speed: Wheel Vert. Speed: Rad-Gesch vertikal: Sensitivity: Empfindlichkeit: Specifies the amount of time (in seconds) that will be required before the mouse is fully accelerated after reaching the high end of an axis. % Extend the time that extra acceleration is applied. Axis travel will be taken into account. A slower flick will decrease the actual time that extra acceleration will be applied. Spring Settings Sprungeinstellungen Spring Width: Sprungweite: Changes the width of the region that the cursor can move in spring mode. 0 will use the entire width of your screen. Ändert die Breite der Region, die der Mauszeiger im Sprungmodus zurück legt. 0 wird die gesamte Breite auf Ihrem Bildschirm nutzen. Spring Height: Sprunghöhe: Changes the height of the region that the cursor can move in spring mode. 0 will use the entire height of your screen. Ändert die Höhe der Region, die der Mauszeiger im Sprungmodus zurück legt. 0 wird die gesamte Höhe auf Ihrem Bildschirm nutzen. %n notch(es)/s %n notch/s %n notches/s QKeyDisplayDialog Key Checker Tastenkontrolle <html><head/><body><p>Press a key on your keyboard to see how the key is detected by this application. The window will show the system native key value, the original value given by Qt (if applicable), and the custom value used by antimicro.</p><p>The antimicro key value and the Qt key value will usually be the same. antimicro tries to use the key values defined in Qt when possible. Check the page <a href="https://doc.qt.io/qt-4.8/qt.html#Key-enum"><span style=" text-decoration: underline; color:#0057ae;">https://doc.qt.io/qt-4.8/qt.html#Key-enum</span></a> for a list of values defined by Qt. If you discover that a key is not natively supported by this program, please report the problem to antimicro's <a href="https://github.com/AntiMicro/antimicro"><span style=" text-decoration: underline; color:#0057ae;">GitHub page</span></a> so that the program can be edited to support it directly. As it is, a custom prefix is added to unknown values so they can still be used; the main problem is that the profile will no longer be portable.</p></body></html> Event Handler: Native Key Value: Nativer Tastenwert: 0x00000000 0x00000000 Qt Key Value: Qt-Tastenwert: antimicro Key Value: QObject Super Super Menu Menü Mute Stummschalten Vol+ Vol- Play/Pause Wiedergabe/Pause Play Wiedergabe Pause Prev Zurück Next Vor Mail EMail Home Pos1 Media Search Suche Daemon launched Dienst gestartet Failed to launch daemon Dienst konnte nicht gestartet werden Launching daemon Starte Dienst Display string "%1" is not valid. Failed to set a signature id for the daemon Signatur-ID konnte für den Dienst nicht gesetzt werden Failed to change working directory to / Arbeitsverzeichnis konnte nicht gesetzt werden zu / Quitting Program Beende Programm # of joysticks found: %1 # an Joysticks gefunden: %1 List Joysticks: --------------- Joystick %1: Index: %1 GUID: %1 Name: %1 Yes Ja No Nein Game Controller: %1 # of Axes: %1 # der Achsen: %1 # of Buttons: %1 # der Knöpfe: %1 # of Hats: %1 # der Hats: %1 Attempting to use fallback option %1 for event generation. Versuche Fallback-Option %1 zur Ereignisgenerierung. Failed to open event generator. Exiting. Öffnen des Ereignisgenerators fehlgeschlagen. Breche ab. Using %1 as the event generator. Nutze %1 als Ereignisgenerator. Could not raise process priority. Konnte Prozesspriorität nicht erhöhen. QuickSetDialog Quick Set Schnellkonfiguration <html><head/><body><p>Please press a button or move an axis on %1 (<span style=" font-weight:600;">%2</span>).<br/>A dialog window will then appear which will<br/>allow you to make an assignment.</p></body></html> <html><head/><body><p>Bitte drücken Sie eine Taste oder bewegen Sie eine Achse auf %1 (<span style=" font-weight:600;">%2</span>).<br/>Dann erscheint ein Dialogfenter, dass Ihnen <br>erlaubt eine Zuordnung zu machen.</p></body></html> Quick Set %1 Schnellkonfiguration %1 SetAxisThrottleDialog Throttle Change Schubänderung The throttle setting for Axis %1 has been changed. Would you like to distribute this throttle change to all sets? Auf Achse %1 wurde der Schub verändert. Möchten Sie die Änderungen an alle Sets übertragen? SetJoystick Set %1: %2 Set %1: %2 Set %1 Set %1 SetNamesDialog Set Name Settings Setnameneinstellungen Set 1 Set 1 Set 2 Set 2 Set 3 Set 3 Set 4 Set 4 Set 5 Set 5 Set 6 Set 6 Set 7 Set 7 Set 8 Set 8 Name Name SimpleKeyGrabberButton Mouse Maus SpringModeRegionPreview Spring Mode Preview Sprungmodus-Vorschau UInputEventHandler Could not find a valid uinput device file. Please check that you have the uinput module loaded. lsmod | grep uinput Konnte keine gültiges uinput Gerätedatei finden. Bitte überprüfen Sie, ob das uinput Modul geladen ist. lsmod | grep uinput Could not open uinput device file Please check that you have permission to write to the device Konnte nicht uinput Gerätedatei öffnen Bitte überprüfen Sie ob Sie die Berechtigung haben auf dieses Gerät zu schreiben Using uinput device file %1 Nutze uinput Gerätedatei %1 UInputHelper a b c d e f g h i j k l m n o p q r s t u v w x y z Esc F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 ` 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 0 0 - = BackSpace Rücktaste Tab Tabulator [ ] \ CapsLock Feststell ; ' Enter Eingabe Shift_L Umschalt_L , . / Ctrl_L Strg_L Super_L Super_L Alt_L Alt_L Space Leertaste Alt_R Alt_R Menu Menü Ctrl_R Strg_R Shift_R Umschalt_R Up Hoch Left Links Down Runter Right Rechts PrtSc Druck Ins Einfg Del Entf Home Pos1 End Ende PgUp Bild ↑ PgDn Bild ↓ NumLock * + KP_Enter KP_1 KP_2 KP_3 KP_4 KP_5 KP_6 KP_7 KP_8 KP_9 KP_0 SCLK Rol ↓ Pause Pause Super_R Mute Stumm VolDn Vol- VolUp Vol+ Play Wiedergabe Stop Prev Zurück Next Vor [NO KEY] [KEINE TASTE] UnixWindowInfoDialog Captured Window Properties Erkannte Fenstereigenschaften Information About Window Informationen über das Fenster Class: Klasse: TextLabel Title: Titel: Path: Pfad: Match By Properties Class Klasse Title Titel Path Pfad VDPad VDPad VDPad VirtualKeyPushButton Space Leertaste Tab Shift (L) Umschalt (L) Shift (R) Umschalt (R) Ctrl (L) Strg (L) Ctrl (R) Strg (R) Alt (L) Alt (L) Alt (R) Alt (R) ` ~ - = [ ] \ Caps Feststell ; ' , . / ESC PRTSC Drucken SCLK Rollen INS Einfg PGUP Bild ↑ DEL Entf PGDN Bild ↓ 1 2 3 4 5 6 7 8 9 0 NUM LK NUM LOCK * + E N T E R E I N G A B E < : Super (L) Menu Menü Up Hoch Down Runter Left Links Right Rechts VirtualKeyboardMouseWidget Keyboard Tastatur Mouse Maus Mouse Settings Mauseinstellungen Left Mouse Links Up Mouse Hoch Left Button Mouse Linke Taste Middle Button Mouse Mittlere Taste Right Button Mouse Rechte Taste Wheel Up Mouse Mausrad hoch Wheel Left Mouse Mausrad links Wheel Right Mouse Mausrad rechts Wheel Down Mouse Mausrad runter Down Mouse Runter Right Mouse Rechts Button 4 Mouse Taste 4 Mouse 8 Mouse Taste 8 Button 5 Mouse Taste 5 Mouse 9 Mouse Taste 9 NONE KEINE Applications Browser Back Browser Favorites Browser Forward Browser Home Browser Refresh Browser Search Browser Stop Calc Email Media Media Next Media Play Media Previous Media Stop Search Suche Volume Down Volume Mute Volume Up VirtualMousePushButton INVALID UNGÜLTIG WinAppProfileTimerDialog Capture Application Wähle Applikation After pressing the "Capture Application" button, please select the application window that you want to have a profile associated with. The active application will be captured after the selected number of seconds. Wählen Sie das Fenster aus mit dem Sie das Profil assozieren möchten, nachdem Sie auf den "Wähle Applikation" Button geklickt haben. Die aktive Applikation wird nach der angegebenen Zahl an Sekunden ausgewählt. Timer: Seconds Sekunden Cancel Abbrechen WinExtras [NO KEY] [KEINE TASTE] AntiMicro Profile X11Extras ESC Tab Tabulator Space Leertaste DEL Entf Return Eingabe KP_Enter Backspace Rücktaste xinput extension was not found. No mouse acceleration changes will occur. xinput Erweiterung wurde nicht gefunden. Es wird keine Mausbeschleunigungsänderungen geben. xinput version must be at least 2.0. No mouse acceleration changes will occur. xinput Version muss mindestens 2.0 sein. Es wird keine Mausbeschleunigungsänderungen geben. Virtual pointer found with id=%1. Virtueller Mauszeiger mit id=%1 gefunden. PtrFeedbackClass was not found for virtual pointer.No change to mouse acceleration will occur for device with id=%1 PtrFeedbackCalls wurde nicht für den virtuellen Mauszeiger gefunden. Es wird keine Mausbeschleunigungsänderungen für das Gerät mit id=%1 geben Changing mouse acceleration for device with id=%1 Ändere Mausbeschleunigung für Gerät der id=%1 XMLConfigReader Could not write updated profile XML to file %1. Konnte aktuelles Profil nicht als XML in Datei %1 schreiben. XMLConfigWriter Could not write to profile at %1. Konnte Profil nicht schreiben in %1. antimicro-2.23/share/antimicro/translations/antimicro_en.ts000066400000000000000000011263521300750276700242750ustar00rootroot00000000000000 AboutDialog About Version <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Originally developed by Travis Nickles &lt;nickles.travis@gmail.com&gt;, now maintained by the AntiMicro group at https://github.com/AntiMicro.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Contributors:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;"><br /></span>Zerro Alvein</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">aybe</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jeff Backus &lt;jeff.backus@gmail.com&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Arthur Moore<br />Anton Tornqvist &lt;antont@inbox.lv&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7185</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">DarkStarSword</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">est31</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ProfessorKaos64</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">qwerty12</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA0</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Translators:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VaGNaroK &lt;vagnarokalkimist@gmail.com&gt; - Brazilian Portuguese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx - Chinese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Belleguic Terence &lt;hizo@free.fr&gt; - French</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Leonard Koenig &lt;leonard.r.koenig@googlemail.com&gt; - German</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phob - German</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">tou omiya - Japanese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Dmitriy Koshel &lt;form.eater@gmail.com&gt; - Russian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jay Alexander Fleming &lt;tito.nehru.naser@gmail.com&gt; - Serbian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">burunduk - Ukrainian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Flavio HR &lt;flavio.hrx@gmail.com&gt; - Spanish</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA - wazaaaaa00&lt;@&gt;gmail&lt;.&gt;com - Italian</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> Info Changelog Since December 30, 2012, I have been working on antimicro in my spare time. What originally started as a fork of QJoyPad and a way to learn proper event-driven programming has turned into something much bigger than I originally intended. Although I have spent a lot of time learning new techniques, finding out more about the domain of KB+M emulation, and spending Friday nights bashing my head against my keyboard, it has been a fun and enriching experience overall. The need for this program came from me using similar programs on Windows to play several games that did not provide native controller support. Although some alternatives existed on Linux, there wasn't really anything that I felt was good enough in terms of functionality or in-game controls in order to really enjoy games that I wanted to play with using KB+M emulation. QJoyPad was the main program that I had used in the past although it had aged a lot and it didn't provide some basic functionality that I thought was essential. The project was dead as it had not been updated in several years so I decided to make my own. Since then, I have tried to find out what the other programs do right and then improve upon it. I have also discovered some neat tricks along the way and I have learned more about how native gamepad controls are implemented in some games than I ever really wanted to know. Although there are definitely areas where this program could improve, I find that this program offers the best in-game control experience for playing older, and some newer, games that do not provide native controller support. Development of this program is not as high of a priority for me anymore. This is mainly due to the fact that the Steam Controller works pretty well for the task of playing PC games compared to using an Xbox 360 controller. However, it does look like there is still a reason for this program to exist for a while. Copyright: 2013 - 2016 Credits antimicro <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">GNU GENERAL PUBLIC LICENSE</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Version 3, 29 June 2007</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Preamble</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Developers that use the GNU GPL protect your rights with two steps:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">(1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The precise terms and conditions for copying, distribution and modification follow.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">TERMS AND CONDITIONS</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">0. Definitions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;This License&quot; refers to version 3 of the GNU General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Copyright&quot; also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;The Program&quot; refers to any copyrightable work licensed under this License. Each licensee is addressed as &quot;you&quot;. &quot;Licensees&quot; and &quot;recipients&quot; may be individuals or organizations.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;modify&quot; a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a &quot;modified version&quot; of the earlier work or a work &quot;based on&quot; the earlier work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;covered work&quot; means either the unmodified Program or a work based on the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;propagate&quot; a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;convey&quot; a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An interactive user interface displays &quot;Appropriate Legal Notices&quot; to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">1. Source Code.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;source code&quot; for a work means the preferred form of the work for making modifications to it. &quot;Object code&quot; means any non-source form of a work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;Standard Interface&quot; means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;System Libraries&quot; of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A &quot;Major Component&quot;, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;Corresponding Source&quot; for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source for a work in source code form is that same work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">2. Basic Permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">3. Protecting Users' Legal Rights From Anti-Circumvention Law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">4. Conveying Verbatim Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">5. Conveying Modified Source Versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) The work must carry prominent notices stating that you modified it, and giving a relevant date.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to &quot;keep intact all notices&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an &quot;aggregate&quot; if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">6. Conveying Non-Source Forms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;User Product&quot; is either (1) a &quot;consumer product&quot;, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, &quot;normally used&quot; refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Installation Information&quot; for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">7. Additional Terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Additional permissions&quot; are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Limiting the use for publicity purposes of names of licensors or authors of the material; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All other non-permissive additional terms are considered &quot;further restrictions&quot; within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">8. Termination.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">9. Acceptance Not Required for Having Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">10. Automatic Licensing of Downstream Recipients.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An &quot;entity transaction&quot; is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">11. Patents.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;contributor&quot; is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's &quot;contributor version&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A contributor's &quot;essential patent claims&quot; are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, &quot;control&quot; includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">In the following three paragraphs, a &quot;patent license&quot; is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To &quot;grant&quot; such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. &quot;Knowingly relying&quot; means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A patent license is &quot;discriminatory&quot; if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">12. No Surrender of Others' Freedom.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">13. Use with the GNU Affero General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">14. Revised Versions of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License &quot;or any later version&quot; applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">15. Disclaimer of Warranty.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM &quot;AS IS&quot; WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">16. Limitation of Liability.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">17. Interpretation of Sections 15 and 16.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.</span></p></body></html> About Development License Program Version %1 Program Compiled on %1 at %2 Built Against SDL %1 Running With SDL %1 Using Qt %1 Using Event Handler: %1 AddEditAutoProfileDialog Auto Profile Dialog Profile: Browse Window: Select Window. Click on the appropriate application window and the application file path will be populated in the form. Detect Window Properties Class: Title: Application: Select Devices: Select this profile to be the default loaded for the specified device. The selection will be used instead of the all default profile option. Set as Default for Controller A different profile is already selected as the default for this device. Current (%1) Open Config Select Program Programs (*.exe) Please use the main default profile selection. Please select a window by using the mouse. Press Escape if you want to cancel. Capture Application Window Could not obtain information for the selected window. Application Capture Failed Profile file path is invalid. No window matching property was specified. Program path is invalid or not executable. File is not an .exe file. No window matching property was selected. AdvanceButtonDialog Advanced Assignments Toggle Turbo Set Selector Blank or KB/M Hold Pause Cycle Distance Insert Delete Clear All Time: 0.01s 0s Insert a pause that occurs in between key presses. Release Insert a new blank slot. Delete a slot. Clear all currently assigned slots. Specify the duration of an inserted Pause or Hold slot. 0m &Mouse Speed Mod: Specify the range past an axis dead zone in which a sequence of actions will execute. Distance: % Mouse Mod Press Time Delay Execute Load Set Change Text Entry Placeholder 0 Set the percentage that mouse speeds will be modified by. Auto Reset Cycle After seconds Executable: ... Arguments: Enabled Mode: <html><head/><body><p>Normal: Repeatedly press and release a button by the chosen rate.</p><p>Gradient: Modify the button press and button release delay based on how far an axis has been moved. The rate will remain the same.</p><p>Pulse: Modify how many times a button is pressed and released per second. The button delay will remain the same.</p></body></html> Normal Gradient Pulse Delay: 0.10s Rate: 10.0/s Disabled Select Set 1 One Way Select Set 1 Two Way Select Set 1 While Held Select Set 2 One Way Select Set 2 Two Way Select Set 2 While Held Select Set 3 One Way Select Set 3 Two Way Select Set 3 While Held Select Set 4 One Way Select Set 4 Two Way Select Set 4 While Held Select Set 5 One Way Select Set 5 Two Way Select Set 5 While Held Select Set 6 One Way Select Set 6 Two Way Select Set 6 While Held Select Set 7 One Way Select Set 7 Two Way Select Set 7 While Held Select Set 8 One Way Select Set 8 Two Way Select Set 8 While Held sec. /sec. Set %1 Select Set %1 One Way Two Way While Held Choose Executable Slots past a Cycle action will be executed on the next button press. Multiple cycles can be added in order to create partitions in a sequence. Delays the time that the next slot is activated by the time specified. Slots activated before the delay will remain active after the delay time has passed. Distance action specifies that the slots afterwards will only be executed when an axis is moved a certain range past the designated dead zone. Insert a hold action. Slots after the action will only be executed if the button is held past the interval specified. Chose a profile to load when this slot is activated. Mouse mod action will modify all mouse speed settings by a specified percentage while the action is being processed. This can be useful for slowing down the mouse while sniping. Specify the time that keys past this slot should be held down. Insert a release action. Slots after the action will only be executed after a button release if the button was held past the interval specified. Change to selected set once slot is activated. Full string will be typed when a slot is activated. Execute program when slot is activated. Choose Profile Config Files (*.amgp *.xml) AdvanceStickAssignmentDialog Stick/Pad Assignment Sticks DPads %1 (Joystick %2) Stick 1 Enabled Assign X Axis: Y Axis: Stick 2 Number of Physical DPads: %1 Virtual DPad 1 Up: Down: Note: This window is meant for backwards compatibility with profiles made before antimicro 2.0. Since version 2.0, use of the Game Controller Mapping window is preferred. Left: Right: Axis %1 Axis %1 - Axis %1 + Button %1 Move stick 1 along the X axis Move stick 1 along the Y axis Move stick 2 along the X axis Move stick 2 along the Y axis Press a button or move an axis AxisEditDialog Axis Mouse (Horizontal) Mouse (Inverted Horizontal) Mouse (Vertical) Mouse (Inverted Vertical) Arrows: Up | Down Arrows: Left | Right Keys: W | S Keys: A | D NumPad: KP_8 | KP_2 NumPad: KP_4 | KP_6 None Set the value to use as the limit for an axis. Useful for a worn out analog stick. Negative Half Throttle Positive Half Throttle Name: Specify the name of an axis. Mouse Settings Set the value of the dead zone for an axis. Presets: Dead Zone: Max Zone: [NO KEY] Throttle setting that determines the behavior of how to interpret an axis hold or release. Negative Throttle Normal Positive Throttle Current Value: Set Set %1 Left Mouse Button Right Mouse Button ButtonEditDialog Dialog To make a new assignment, press any keyboard key or click a button in the Keyboard or Mouse tab Placeholder Toggle Enables a key press or release to only occur when a controller button is pressed. Enables rapid key presses and releases. Turbo controller. Turbo Current: Slots Na&me: Specify the name of a button. Action: Specify the action that will be performed in game while this button is being used. Advanced Set Set %1 CapturedWindowInfoDialog Captured Window Properties Information About Window Class: TextLabel Title: Path: Match By Properties Class Title Path Full Path File Name CommandLineUtility Profile location %1 is not an XML file. Profile location %1 does not exist. An invalid set number '%1' was specified. Controller identifier '%s'' is not a valid value. No display string was specified. Controller identifier is not a valid value. No set number was specified. No controller was specified. An invalid event generator was specified. No event generator string was specified. Qt style flag was detected but no style was specified. No log level specified. antimicro version Usage: antimicro [options...] [profile] Options Print help text. Print version information. Launch program in system tray only. Launch program with the tray menu disabled. Launch program without the main window displayed. Launch program with the configuration file selected as the default for selected controllers. Defaults to all controllers. Apply configuration file to a specific controller. Value can be a controller index, name, or GUID. Unload currently enabled profile(s). Value can be a controller index, name, or GUID. Start joysticks on a specific set. Value can be a controller index, name, or GUID. Advance profile loading set options. Launch program as a daemon. Enable logging. Use specified display for X11 calls. Useful for ssh. Choose between using XTest support and uinput support for event generation. Default: xtest. Choose between using SendInput and vmulti support for event generation. Default: sendinput. Print information about joysticks detected by SDL. Open game controller mapping window of selected controller. Value can be a controller index or GUID. DPadContextMenu Mouse (Normal) Mouse (Inverted Horizontal) Mouse (Inverted Vertical) Mouse (Inverted Horizontal + Vertical) Arrows Keys: W | A | S | D NumPad None Standard Eight Way 4 Way Cardinal 4 Way Diagonal Mouse Settings DPadEditDialog Dialog Presets: Mouse (Normal) Mouse (Inverted Horizontal) Mouse (Inverted Vertical) Mouse (Inverted Horizontal + Vertical) Arrows Keys: W | A | S | D NumPad None Dpad Mode: &Name: 4 Way Cardinal 4 Way Diagonal DPad Delay: Time lapsed before a direction change is taken into effect. s Specify the name of a dpad. Mouse Settings Standard Standard: 8 region dpad with two direction buttons active when the dpad is in a diagonal region. Eight Way: 8 region dpad with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region dpad with regions corresponding to the cardinal directions of the dpad. Useful for menus. 4 Way Diagonal: 4 region dpad with each region corresponding to a diagonal zone. Eight Way Set Set %1 EditAllDefaultAutoProfileDialog Default Profile Profile: Browse Open Config Profile file path is invalid. ExtraProfileSettingsDialog Extra Profile Settings Key Press Time: 0.00 ms Profile Name: s GameController Game Controller GameControllerDPad DPad GameControllerMappingDialog Game Controller Mapping <html><head/><body><p>antimicro makes use of the <a href="https://wiki.libsdl.org/CategoryGameController"><span style=" text-decoration: underline; color:#0057ae;">Game Controller API</span></a> provided by SDL 2 in order to abstract various gamepads to fit a unified standard. In order to make a button assignment, please highlight the mapping cell for the appropriate button row below. You can then press a button or move an axis on your gamepad and the cell will update with the physical button or axis that will be used.</p><p>antimicro will use the mapping that you specify to save a mapping string that will be loaded into SDL.</p></body></html> A B X Y Back Start Guide Left Shoulder Right Shoulder Left Stick Click Right Stick Click Left Stick X Left Stick Y Right Stick X Right Stick Y Left Trigger Right Trigger DPad Up DPad Left DPad Down DPad Right Mapping SDL 2 Game Controller Mapping String Last Axis Event: Current Axis Detection Dead Zone: 5000 10000 15000 20000 25000 30000 32000 Game Controller Mapping (%1) (#%2) Discard Controller Mapping? Discard mapping for this controller? If discarded, the controller will be reverted to a joystick once you refresh all joysticks. GameControllerSet Back Guide Start LS Click RS Click L Shoulder R Shoulder L Trigger R Trigger GameControllerTrigger Trigger JoyAxis Axis JoyAxisButton Negative Positive Unknown Button JoyAxisContextMenu Mouse (Horizontal) Mouse (Inverted Horizontal) Mouse (Vertical) Mouse (Inverted Vertical) Arrows: Up | Down Arrows: Left | Right Keys: W | S Keys: A | D NumPad: KP_8 | KP_2 NumPad: KP_4 | KP_6 None Mouse Settings Left Mouse Button Right Mouse Button JoyButton Processing turbo for #%1 - %2 Finishing turbo for button #%1 - %2 Processing press for button #%1 - %2 Processing release for button #%1 - %2 Distance change for button #%1 - %2 Button [NO KEY] [Set %1 1W] [Set %1 2W] [Set %1 WH] JoyButtonContextMenu Toggle Turbo Clear Set Select Disabled Set %1 Set %1 1W Set %1 2W Set %1 WH JoyButtonSlot Mouse Up Down Left Right LB MB RB B4 B5 Pause Hold Cycle Distance Release Mouse Mod Press Time Delay Load %1 Set Change %1 [Text] %1 [Exec] %1 [NO KEY] JoyControlStick Stick JoyControlStickButton Up Down Left Right Button JoyControlStickContextMenu Mouse (Normal) Mouse (Inverted Horizontal) Mouse (Inverted Vertical) Mouse (Inverted Horizontal + Vertical) Arrows Keys: W | A | S | D NumPad None Standard Eight Way 4 Way Cardinal 4 Way Diagonal Mouse Settings JoyControlStickEditDialog Dialog X: 0 Y: Distance: Presets: Mouse (Normal) Mouse (Inverted Horizontal) Mouse (Inverted Vertical) Mouse (Inverted Horizontal + Vertical) Arrows Keys: W | A | S | D NumPad None Stick Mode: Standard: 8 region stick with two direction buttons active when the stick is in a diagonal region. Eight Way: 8 region stick with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region stick with regions corresponding to the cardinal directions of the stick. Useful for menus. 4 Way Diagonal: 4 region stick with each region corresponding to a diagonal zone of the stick. 4 Way Cardinal 4 Way Diagonal Dead zone value to use for an analog stick. Value when an analog stick is considered moved 100%. The area (in degrees) that each diagonal region occupies. Square Stick: Percentage to modify a square stick coordinates to confine values to a circle % Stick Delay: Time lapsed before a direction change is taken into effect. s Modifier: Edit button that is active while the stick is active. This button is useful for assigning zones with modifier keys that can be used to assign walk/run functionality to an analog stick. PushButton Name: Specify the name of an analog stick. Mouse Settings Standard Bearing: % Safe Zone: Eight Way Dead Zone: Max Zone: Diagonal Range: Set Set %1 JoyControlStickModifierButton Modifier JoyDPad DPad JoyDPadButton Up Down Left Right Button JoyTabWidget <New> Remove Remove configuration from recent list. Load Load configuration file. Save Save changes to configuration file. Save As Save changes to a new configuration file. Sets Copy from Set Settings Set 1 Set 2 Set 3 Set 4 Set 5 Set 6 Set 7 Set 8 Stick/Pad Assign Controller Mapping Quick Set Names Toggle button name displaying. Pref Change global profile settings. Reset Revert changes to the configuration. Reload configuration file. Open Config Config Files (*.amgp *.xml) Config File (*.%1.amgp) Save Profile Changes? Changes to the new profile have not been saved. Would you like to save or discard the current profile? Changes to the profile "%1" have not been saved. Would you like to save or discard changes to the current profile? Sticks DPads No buttons have been assigned. Please use Quick Set to assign keys to buttons or disable hiding empty buttons. Set %1: %2 Set %1 Copy Set Assignments Are you sure you want to copy the assignments and device properties from %1? Save Config Set Joystick Joystick JoystickStatusWindow Properties Details Name: %1 Number: Axes: Buttons: Hats: GUID: Game Controller: Axes Buttons Hats %1 (#%2) Properties Axis %1 Hat %1 No Yes MainSettingsDialog Edit Settings General Controller Mappings Language Auto Profile Mouse <html><head/><body><p>Specify the default directory that the program should use in file dialogs when loading a profile or saving a new profile.</p></body></html> Recent Profile Count: <html><head/><body><p>Number of profiles that can be placed in recent profile list. 0 will result in the program not enforcing a limit on the number of profiles displayed.</p></body></html> Gamepad Poll Rate: Change the poll rate that the program uses to discover new events from gamepads. Defaults to 10 ms. Reducing the poll rate value could cause the application to use more CPU power so please test the setting that you use before using antimicro unattended. Hide main window when the main window close button is clicked instead of quitting the program. Close To Tray Have Windows start antimicro at system startup. Launch At Windows Startup Display recent profiles for all controllers as a single list in the tray menu. Defaults to using sub-menus. Single Profile List in Tray Have the program minimize to the taskbar. By default, the program minimizes to the system tray if available. Minimize to Taskbar This option will cause the program to hide all buttons that have no slots assigned to them. The Quick Set dialog window will have to be used to bring up the edit dialog for gamepad buttons. Hide Empty Buttons When the program is launched, open the last known profile that was opened during the previous session. Auto Load Last Opened Profile Only show the system tray icon when the program first launches. Launch in Tray Associate .amgp files with antimicro in Windows Explorer. Associate Profiles Key Repeat Active keys will be repeatedly pressed when this option is enabled. Enable Specifies how much time should elapse before key repeating begins. Specifies how many times key presses will be performed per seconds. <html><head/><body><p>antimicro has been translated into many different languages by contributors. By default, the program will choose an appropriate translation based on your system's locale setting. However, you can make antimicro load a different translation depending on the language that you choose from the list below.</p></body></html> French Italian Japanese Russian Serbian Simplified Chinese Ukrainian Class Title Program Disable the "Enhanced Pointer Precision" Windows setting while antimicro is running. Disabling "Enhanced Pointer Precision" will allow mouse movement within antimicro to be more precise. Disable Enhance Pointer Precision Smoothing Histor&y Size: Weight &Modifier: Refresh Rate: The refresh rate is the amount of time that will elapse in between mouse events. Please be cautious when editing this setting as it will cause the program to use more CPU power. Setting this value too low can cause system instability. Please test the setting before using it unattended. Spring Screen: Utilize the specified screen for spring mode. On Linux, the default is to use the primary screen. On Windows, the default is to use all available screens. Accel Numerator: 0 Accel Denominator: Accel Threshold: If the acceleration values for the virtual mouse have been changed by a different process, particularly when quitting an older game, then you might want to reset the acceleration values used by the virtual mouse. Reset Acceleration Delay: Profi&le Directory: ms Rate: times/s Below is a list of the custom mappings that have been saved. You can use the following table to delete mappings or have mappings temporarily disabled. You can also disable mappings that are included with SDL; just insert a new row with the appropriate joystick GUID and check disable. Settings will not take affect until you either refresh all joysticks or unplug that particular joystick. GUID Mapping String Disable? Delete Insert Default Brazilian Portuguese English German Active Devices: All Device Profile Default? Add Edit Also, Windows users who want to use a low value should also check the "Disable Enhance Pointer Precision" checkbox if you haven't disabled the option in Windows. Select Default Profile Directory Are you sure you want to delete the profile? MainWindow antimicro No Joysticks have been found. Please plug in a joystick and then choose the "Update Joysticks" option in the main menu If events are not seen by a game, please click here to run this application as the Adminstrator. &App &Options &Help &Quit Ctrl+Q &Update Joysticks Ctrl+U &Hide Ctrl+H &About Ctrl+A About Qt Properties Key Checker Home Page GitHub Page Game Controller Mapping Settings Stick/Pad Assign Wiki Could not find a proper controller identifier. Exiting. (%1) Open File &Restore Run as Administrator? Are you sure that you want to run this program as Adminstrator? Some games run as Administrator which will cause events generated by antimicro to not be used by those games unless antimicro is also run as the Adminstrator. This is due to permission problems caused by User Account Control (UAC) options in Windows Vista and later. Failed to elevate program Failed to restart this program as the Administrator Could not find controller. Exiting. MouseAxisSettingsDialog Mouse Settings - Set %1 MouseButtonSettingsDialog Mouse Settings - Set %1 MouseControlStickSettingsDialog Mouse Settings Set %1 MouseDPadSettingsDialog Mouse Settings Set %1 MouseSettingsDialog Mouse Settings Mouse Mode: Cursor mode is used to move the mouse cursor around the screen relative to its current position depending on how much you move an axis or if a button is pressed. Spring mode is used to move the mouse cursor from the center of the screen depending on how much you move an axis. The mouse cursor will be returned to the center of the screen when the axis is moved back to the dead zone. Cursor Spring Acceleration: Enhanced Precision Linear Quadratic Cubic Quadratic Extreme Power Function Easing Quadratic Easing Cubic Mouse Speed Settings Enable to change the horizontal and vertical speed boxes at the same time. Change Together Options for adding more acceleration to the mouse movement beyond what the acceleration curve would produce. Acceleration is added based on how quickly an axis is moved in one gamepad poll. This is meant to help work around some of the issues of the very limited input range available using typical gamepad analog sticks. Delta Acceleration &Multiplier: Mi&n Threshold: 1 = 20 pps Wheel Hori. Speed: Set the speed used for horizontal mouse wheel movement according to number of simulated notches per second. Set the speed used for vertical mouse wheel movement according to number of simulated notches per second. Sensitivit&y: For Power Function acceleration curve. Specifies the factor to use for curve sensitivity. When the value is above 1.0, the mouse movement will be accelerated faster at the low end of an axis. Easing Duration: s Highest value to accelerate mouse movement by x Start %: Acceleration begins at this percentage of the base multiplier Minimum amount of axis travel required for acceleration to begin Max Threshold: Maximum axis travel before acceleration has reached the multiplier value E&xtra Duration: Curve: Ease Out Sine Ease Out Quad Ease Out Cubic Release Radius: Specifies that the spring area will be relative to the mouse position set by a non-relative spring. Relative Mouse Status X: 0 (0 pps) Y: 1 = 1 notch(es)/s Enhanced: Three tier curve that makes the mouse move slow on the low end of an axis and fast on the high end. Linear: Mouse moves proportionally to axis. Quadratic: Mouse accelerates slowly on low end. Cubic: Mouse accelerates slower than Quadratic. Quadratic Extreme: Raises mouse speed 1.5 times once 95% axis travel has been reached. Power Function: Allows for a more custom curve option. Easing Quadratic: Axis high end is gradually accelerated over a period of time using a Quadratic curve. Easing Cubic: Axis high end is gradually accelerated over a period of time using a Cubic curve. Hori&zontal Speed: &Vertical Speed: Wheel Vert. Speed: Specifies the amount of time (in seconds) that will be required before the mouse is fully accelerated after reaching the high end of an axis. % Extend the time that extra acceleration is applied. Axis travel will be taken into account. A slower flick will decrease the actual time that extra acceleration will be applied. Spring Settings Spring Width: Changes the width of the region that the cursor can move in spring mode. 0 will use the entire width of your screen. Spring Height: Changes the height of the region that the cursor can move in spring mode. 0 will use the entire height of your screen. %n notch(es)/s %n notch/s %n notches/s QKeyDisplayDialog Key Checker <html><head/><body><p>Press a key on your keyboard to see how the key is detected by this application. The window will show the system native key value, the original value given by Qt (if applicable), and the custom value used by antimicro.</p><p>The antimicro key value and the Qt key value will usually be the same. antimicro tries to use the key values defined in Qt when possible. Check the page <a href="https://doc.qt.io/qt-4.8/qt.html#Key-enum"><span style=" text-decoration: underline; color:#0057ae;">https://doc.qt.io/qt-4.8/qt.html#Key-enum</span></a> for a list of values defined by Qt. If you discover that a key is not natively supported by this program, please report the problem to antimicro's <a href="https://github.com/AntiMicro/antimicro"><span style=" text-decoration: underline; color:#0057ae;">GitHub page</span></a> so that the program can be edited to support it directly. As it is, a custom prefix is added to unknown values so they can still be used; the main problem is that the profile will no longer be portable.</p></body></html> Event Handler: Native Key Value: 0x00000000 Qt Key Value: antimicro Key Value: QObject Super Menu Mute Vol+ Vol- Play/Pause Play Pause Prev Next Mail Home Media Search Daemon launched Failed to launch daemon Launching daemon Display string "%1" is not valid. Failed to set a signature id for the daemon Failed to change working directory to / Quitting Program # of joysticks found: %1 List Joysticks: --------------- Joystick %1: Index: %1 GUID: %1 Name: %1 Yes No Game Controller: %1 # of Axes: %1 # of Buttons: %1 # of Hats: %1 Attempting to use fallback option %1 for event generation. Failed to open event generator. Exiting. Using %1 as the event generator. Could not raise process priority. QuickSetDialog Quick Set <html><head/><body><p>Please press a button or move an axis on %1 (<span style=" font-weight:600;">%2</span>).<br/>A dialog window will then appear which will<br/>allow you to make an assignment.</p></body></html> Quick Set %1 SetAxisThrottleDialog Throttle Change The throttle setting for Axis %1 has been changed. Would you like to distribute this throttle change to all sets? SetJoystick Set %1: %2 Set %1 SetNamesDialog Set Name Settings Set 1 Set 2 Set 3 Set 4 Set 5 Set 6 Set 7 Set 8 Name SimpleKeyGrabberButton Mouse SpringModeRegionPreview Spring Mode Preview UInputEventHandler Could not find a valid uinput device file. Please check that you have the uinput module loaded. lsmod | grep uinput Could not open uinput device file Please check that you have permission to write to the device Using uinput device file %1 UInputHelper a b c d e f g h i j k l m n o p q r s t u v w x y z Esc F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 ` 1 2 3 4 5 6 7 8 9 0 - = BackSpace Tab [ ] \ CapsLock ; ' Enter Shift_L , . / Ctrl_L Super_L Alt_L Space Alt_R Menu Ctrl_R Shift_R Up Left Down Right PrtSc Ins Del Home End PgUp PgDn NumLock * + KP_Enter KP_1 KP_2 KP_3 KP_4 KP_5 KP_6 KP_7 KP_8 KP_9 KP_0 SCLK Pause Super_R Mute VolDn VolUp Play Stop Prev Next [NO KEY] UnixWindowInfoDialog Captured Window Properties Information About Window Class: TextLabel Title: Path: Match By Properties Class Title Path VDPad VDPad VirtualKeyPushButton Space Tab Shift (L) Shift (R) Ctrl (L) Ctrl (R) Alt (L) Alt (R) ` ~ - = [ ] \ Caps ; ' , . / ESC PRTSC SCLK INS PGUP DEL PGDN 1 2 3 4 5 6 7 8 9 0 NUM LK * + E N T E R < : Super (L) Menu Up Down Left Right VirtualKeyboardMouseWidget Keyboard Mouse Mouse Settings Left Mouse Up Mouse Left Button Mouse Middle Button Mouse Right Button Mouse Wheel Up Mouse Wheel Left Mouse Wheel Right Mouse Wheel Down Mouse Down Mouse Right Mouse Button 4 Mouse Mouse 8 Mouse Button 5 Mouse Mouse 9 Mouse NONE Applications Browser Back Browser Favorites Browser Forward Browser Home Browser Refresh Browser Search Browser Stop Calc Email Media Media Next Media Play Media Previous Media Stop Search Volume Down Volume Mute Volume Up VirtualMousePushButton INVALID WinAppProfileTimerDialog Capture Application After pressing the "Capture Application" button, please select the application window that you want to have a profile associated with. The active application will be captured after the selected number of seconds. Timer: Seconds Cancel WinExtras [NO KEY] AntiMicro Profile X11Extras ESC Tab Space DEL Return KP_Enter Backspace xinput extension was not found. No mouse acceleration changes will occur. xinput version must be at least 2.0. No mouse acceleration changes will occur. Virtual pointer found with id=%1. PtrFeedbackClass was not found for virtual pointer.No change to mouse acceleration will occur for device with id=%1 Changing mouse acceleration for device with id=%1 XMLConfigReader Could not write updated profile XML to file %1. XMLConfigWriter Could not write to profile at %1. antimicro-2.23/share/antimicro/translations/antimicro_es.ts000066400000000000000000012067451300750276700243070ustar00rootroot00000000000000 AboutDialog About sobre Version versión <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Originally developed by Travis Nickles &lt;nickles.travis@gmail.com&gt;, now maintained by the AntiMicro group at https://github.com/AntiMicro.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Contributors:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;"><br /></span>Zerro Alvein</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">aybe</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jeff Backus &lt;jeff.backus@gmail.com&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Arthur Moore<br />Anton Tornqvist &lt;antont@inbox.lv&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7185</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">DarkStarSword</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">est31</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ProfessorKaos64</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">qwerty12</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA0</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Translators:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VaGNaroK &lt;vagnarokalkimist@gmail.com&gt; - Brazilian Portuguese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx - Chinese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Belleguic Terence &lt;hizo@free.fr&gt; - French</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Leonard Koenig &lt;leonard.r.koenig@googlemail.com&gt; - German</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phob - German</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">tou omiya - Japanese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Dmitriy Koshel &lt;form.eater@gmail.com&gt; - Russian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jay Alexander Fleming &lt;tito.nehru.naser@gmail.com&gt; - Serbian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">burunduk - Ukrainian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Flavio HR &lt;flavio.hrx@gmail.com&gt; - Spanish</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA - wazaaaaa00&lt;@&gt;gmail&lt;.&gt;com - Italian</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> Info info Changelog Changelog Since December 30, 2012, I have been working on antimicro in my spare time. What originally started as a fork of QJoyPad and a way to learn proper event-driven programming has turned into something much bigger than I originally intended. Although I have spent a lot of time learning new techniques, finding out more about the domain of KB+M emulation, and spending Friday nights bashing my head against my keyboard, it has been a fun and enriching experience overall. The need for this program came from me using similar programs on Windows to play several games that did not provide native controller support. Although some alternatives existed on Linux, there wasn't really anything that I felt was good enough in terms of functionality or in-game controls in order to really enjoy games that I wanted to play with using KB+M emulation. QJoyPad was the main program that I had used in the past although it had aged a lot and it didn't provide some basic functionality that I thought was essential. The project was dead as it had not been updated in several years so I decided to make my own. Since then, I have tried to find out what the other programs do right and then improve upon it. I have also discovered some neat tricks along the way and I have learned more about how native gamepad controls are implemented in some games than I ever really wanted to know. Although there are definitely areas where this program could improve, I find that this program offers the best in-game control experience for playing older, and some newer, games that do not provide native controller support. Development of this program is not as high of a priority for me anymore. This is mainly due to the fact that the Steam Controller works pretty well for the task of playing PC games compared to using an Xbox 360 controller. However, it does look like there is still a reason for this program to exist for a while. Copyright: 2013 - 2016 Copyright: 2013 - 2016 {2013 ?} Since December 30, 2012, I have been working on antimicro in my spare time. What originally started as a fork of QJoyPad and a way to learn proper event-driven programming has turned into something much bigger than I originally intended. Although I have spent a lot of time learning new techniques, finding out more about the domain of KB+M emulation, and spending Friday nights bashing my head against my keyboard, it has been a fun and enriching experience overall. The need for this program came from me using similar programs on Windows to play several games that did not provide native controller support. Although some alternatives existed on Linux, there wasn't really anything that I felt was good enough in terms of functionality or in-game controls in order to really enjoy games that I wanted to play with using KB+M emulation. QJoyPad was the main program that I had used in the past although it had aged a lot and it didn't provide some basic functionality that I thought was essential. The project was dead as it had not been updated in several years so I decided to make my own. Since then, I have tried to find out what the other programs do right and then improve upon it. I have also discovered some neat tricks along the way and I have learned more about how native gamepad controls are implemented in some games than I ever really wanted to know. Although there are definitely areas where this program could improve, I find that this program offers the best in-game control experience for playing older, and some newer, games that do not provide native controller support. Once the Steam controller is finally released to the public, the need for this program might not exist anymore. Just based on the concept of the controller alone, the Steam controller would have so many advantages over using a program like this to provide KB+M emulation. Desde el 30 de diciembre de 2012, he estado trabajando en Antimicro en mi tiempo libre. Lo que originalmente comenzó como un fork de QJoyPad y una manera de aprender programación orientada a eventos adecuado se ha convertido en algo mucho más grande de lo que originalmente pretendía. Aunque he pasado mucho tiempo aprendiendo nuevas técnicas, saber más sobre el dominio de la emulación KB + M, y pasar las noches de viernes golpeando la cabeza contra mi teclado, ha sido una experiencia divertida y enriquecedora en general. La necesidad de este programa vino de mí usando programas similares en Windows para jugar varios juegos que no proporcionan soporte para el controlador nativo. Aunque existían algunas alternativas en Linux, no había realmente nada de lo que me pareció que era lo suficientemente bueno en términos de funcionalidad o controles en el juego con el fin de disfrutar realmente de juegos que quería jugar con el uso de la emulación KB + M. QJoyPad fue el programa principal que había utilizado en el pasado a pesar de que había envejecido mucho y no proporcionar alguna funcionalidad básica que yo pensaba que era esencial. El proyecto estaba muerto, ya que no había sido actualizado en varios años, así que decidí hacer mi propia. Desde entonces, he tratado de averiguar lo que los otros programas hacen la derecha y luego mejorarlo. También he descubierto algunos truquitos en el camino y he aprendido más acerca de cómo los controles del gamepad nativas se implementan en algunos juegos de lo que nunca realmente quería saber. Aunque sin duda hay áreas en las que este programa podría mejorar, me parece que este programa ofrece la mejor experiencia de control en el juego para jugar más, y algunos nuevos, juegos que no proporcionan soporte para el controlador nativo. Una vez que el control de Steam finalmente se lanzó al público, la necesidad de este programa no podría existir más. Sólo se basa en el concepto del controlador solamete, el controlador de Steam tendría tantas ventajas sobre el uso de un programa como este para proporcionar la emulación KB + M. Copyright: 2013 - 2016 Copyright: 2013 - 2016 Credits Créditos antimicro antimicro <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Travis Nickles &lt;nickles.travis@gmail.com&gt;</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Contributors:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;"><br /></span>Zerro Alvein</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">aybe</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jeff Backus &lt;jeff.backus@gmail.com&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Arthur Moore<br />Anton Tornqvist &lt;antont@inbox.lv&gt;</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Translators:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VaGNaroK &lt;vagnarokalkimist@gmail.com&gt; - Brazilian Portuguese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx - Chinese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Belleguic Terence &lt;hizo@free.fr&gt; - French</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Leonard Koenig &lt;leonard.r.koenig@googlemail.com&gt; - German</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phob - German</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">tou omiya - Japanese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Dmitriy Koshel &lt;form.eater@gmail.com&gt; - Russian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jay Alexander Fleming &lt;tito.nehru.naser@gmail.com&gt; - Serbian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">burunduk - Ukrainian</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Travis Nickles &lt;nickles.travis@gmail.com&gt;</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Contributors:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;"><br /></span>Zerro Alvein</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">aybe</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jeff Backus &lt;jeff.backus@gmail.com&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Arthur Moore<br />Anton Tornqvist &lt;antont@inbox.lv&gt;</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Translators:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VaGNaroK &lt;vagnarokalkimist@gmail.com&gt; - Brazilian Portuguese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx - Chinese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Flavio HR &lt;flavio.hrx@gmail.com&gt; - Español</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Belleguic Terence &lt;hizo@free.fr&gt; - French</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Leonard Koenig &lt;leonard.r.koenig@googlemail.com&gt; - German</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phob - German</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">tou omiya - Japanese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Dmitriy Koshel &lt;form.eater@gmail.com&gt; - Russian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jay Alexander Fleming &lt;tito.nehru.naser@gmail.com&gt; - Serbian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">burunduk - Ukrainian</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">GNU GENERAL PUBLIC LICENSE</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Version 3, 29 June 2007</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Preamble</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Developers that use the GNU GPL protect your rights with two steps:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">(1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The precise terms and conditions for copying, distribution and modification follow.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">TERMS AND CONDITIONS</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">0. Definitions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;This License&quot; refers to version 3 of the GNU General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Copyright&quot; also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;The Program&quot; refers to any copyrightable work licensed under this License. Each licensee is addressed as &quot;you&quot;. &quot;Licensees&quot; and &quot;recipients&quot; may be individuals or organizations.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;modify&quot; a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a &quot;modified version&quot; of the earlier work or a work &quot;based on&quot; the earlier work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;covered work&quot; means either the unmodified Program or a work based on the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;propagate&quot; a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;convey&quot; a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An interactive user interface displays &quot;Appropriate Legal Notices&quot; to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">1. Source Code.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;source code&quot; for a work means the preferred form of the work for making modifications to it. &quot;Object code&quot; means any non-source form of a work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;Standard Interface&quot; means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;System Libraries&quot; of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A &quot;Major Component&quot;, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;Corresponding Source&quot; for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source for a work in source code form is that same work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">2. Basic Permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">3. Protecting Users' Legal Rights From Anti-Circumvention Law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">4. Conveying Verbatim Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">5. Conveying Modified Source Versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) The work must carry prominent notices stating that you modified it, and giving a relevant date.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to &quot;keep intact all notices&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an &quot;aggregate&quot; if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">6. Conveying Non-Source Forms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;User Product&quot; is either (1) a &quot;consumer product&quot;, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, &quot;normally used&quot; refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Installation Information&quot; for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">7. Additional Terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Additional permissions&quot; are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Limiting the use for publicity purposes of names of licensors or authors of the material; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All other non-permissive additional terms are considered &quot;further restrictions&quot; within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">8. Termination.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">9. Acceptance Not Required for Having Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">10. Automatic Licensing of Downstream Recipients.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An &quot;entity transaction&quot; is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">11. Patents.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;contributor&quot; is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's &quot;contributor version&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A contributor's &quot;essential patent claims&quot; are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, &quot;control&quot; includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">In the following three paragraphs, a &quot;patent license&quot; is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To &quot;grant&quot; such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. &quot;Knowingly relying&quot; means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A patent license is &quot;discriminatory&quot; if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">12. No Surrender of Others' Freedom.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">13. Use with the GNU Affero General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">14. Revised Versions of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License &quot;or any later version&quot; applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">15. Disclaimer of Warranty.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM &quot;AS IS&quot; WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">16. Limitation of Liability.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">17. Interpretation of Sections 15 and 16.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.</span></p></body></html> About Development Sobre el desenvolvimiento License Licencia Program Version %1 Versión del programa %1 Program Compiled on %1 at %2 Programa compilado en %1 a %2 Built Against SDL %1 Running With SDL %1 Using Qt %1 Usando Qt %1 Using Event Handler: %1 Usando Gestor de Eventos: %1 AddEditAutoProfileDialog Auto Profile Dialog Profile: Perfil: Browse Navegar Window: ventana: Select Window. Click on the appropriate application window and the application file path will be populated in the form. Detect Window Properties Class: Clase: Title: Título: Application: Aplicación: Select seleccione Devices: Dispositivos: Select this profile to be the default loaded for the specified device. The selection will be used instead of the all default profile option. Set as Default for Controller A different profile is already selected as the default for this device. Current (%1) Open Config Abrir Config Select Program Seleccionar Programa Programs (*.exe) Programas (*.exe) Please use the main default profile selection. Por favor, utilice la selección principal perfil predeterminado. Please select a window by using the mouse. Press Escape if you want to cancel. Por favor, seleccione una ventana utilizando el ratón. Presione Escape si desea cancelar. Capture Application Window Could not obtain information for the selected window. Application Capture Failed Profile file path is invalid. La ruta de archivo de perfil es invalido. No window matching property was specified. Program path is invalid or not executable. File is not an .exe file. El Archivo no es un .exe. No window matching property was selected. AdvanceButtonDialog Advanced Avanzado Assignments Asignamientos Toggle Alternar Turbo Turbo Set Selector Selector de Set Blank or KB/M Vacio o KB/M Hold Mantener Pause Pausa Cycle Ciclo Distance Distancia Insert Inserir Delete Borrar Clear All Limpiar todo Time: Tiempo: 0.01s 0.01s 0s 0s Insert a pause that occurs in between key presses. Insertar una pausa que se produce en la introducción de la tecla. Release Soltar Insert a new blank slot. Inserte una nueva ranura en blanco. Delete a slot. Borrar ranura. Clear all currently assigned slots. Limpiar todos los slots asignados actualmente. Specify the duration of an inserted Pause or Hold slot. Especificar la duración de una ranura de pausa o de retención insertado. 0m 0m &Mouse Speed Mod: Specify the range past an axis dead zone in which a sequence of actions will execute. Especificar el rango más allá de una zona muerta eje en el que una secuencia de acciones se ejecutará. Distance: Distancia: % % Mouse Mod Raton Mod Press Time Tiempo de presionado Delay Retraso Execute Ejecutar Load Cargar Set Change Definir Cambio Text Entry Entrada de texto Placeholder marcador de posición 0 0 Mouse Speed Mod: Velovidad de Ratón Mod: Set the percentage that mouse speeds will be modified by. Establecer el porcentaje que las velocidades de ratón serán modificadas por. Auto Reset Cycle After Auto Resetear Ciclos Después seconds segundos Executable: ... ... Arguments: Enabled Habilitado Mode: Modo: <html><head/><body><p>Normal: Repeatedly press and release a button by the chosen rate.</p><p>Gradient: Modify the button press and button release delay based on how far an axis has been moved. The rate will remain the same.</p><p>Pulse: Modify how many times a button is pressed and released per second. The button delay will remain the same.</p></body></html> <html><head/><body><p>Normal:. Pulse y suelte repetidamente un botón por la tasa elegido </p><p> Gradiente: Modificar el retraso y liberación de un botón de acuerdo con la distancia de un eje se ha movido. La tasa seguirá siendo el mismo </p><p>Pulso:. Modifica como muchas veces un botón es presionado y liberado por segundo. El retraso botón seguirá siendo el mismo.</p></body></html> Normal Normal Gradient Gradiente Pulse Pulso Delay: Retraso: 0.10s 0.10s Rate: Taza: 10.0/s 10.0/s Disabled Inhabilitado Select Set 1 One Way Seleccione Set 1 Unidireccional Select Set 1 Two Way Seleccione Set 1 Bidireccional Select Set 1 While Held Seleccione Set 1 Mientras se Mantiene Select Set 2 One Way Seleccionar Set 2 Unidireccional Select Set 2 Two Way Seleccionar Set 2 Bidireccional Select Set 2 While Held Seleccionar Set 2 Mientras se Mantiene Select Set 3 One Way Seleccionar Set 3 Unidireccional Select Set 3 Two Way Seleccionar Set 3 Bidireccional Select Set 3 While Held Seleccionar Set 3 Mientras se Mantiene Select Set 4 One Way Seleccionar Set 4 Unidireccional Select Set 4 Two Way Seleccionar Set 4 Bidireccional Select Set 4 While Held Seleccionar Set 4 Mientras se Mantiene Select Set 5 One Way Seleccionar Set 5 Unidireccional Select Set 5 Two Way Seleccionar Set 5 Bidireccional Select Set 5 While Held Seleccionar Set 5 Mientras se Mantiene Select Set 6 One Way Seleccionar Set 6 Unidireccional Select Set 6 Two Way Seleccionar Set 6 Bidireccional Select Set 6 While Held Seleccionar Set 6 Mientras se Mantiene Select Set 7 One Way Seleccionar Set 7 Unidireccional Select Set 7 Two Way Seleccionar Set 7 Bidireccional Select Set 7 While Held Seleccionar Set 7 Mientras se Mantiene Select Set 8 One Way Seleccionar Set 8 Unidireccional Select Set 8 Two Way Seleccionar Set 8 Bidireccional Select Set 8 While Held Seleccionar Set 8 Mientras se Mantiene sec. Seg. /sec. /seg. Set %1 Set %1 Select Set %1 Seleccionar Set %1 One Way Unidireccional Two Way Bidireccional While Held Mientras se Mantiene Choose Executable Escojer Ejecutable Slots past a Cycle action will be executed on the next button press. Multiple cycles can be added in order to create partitions in a sequence. Las ranuras mas allá de un Ciclo de acción podrán ser ejecutados en la proxima vez que se presione el botón. ciclos múltiples se pueden agregar con el fin de crear particiones en una secuencia. Delays the time that the next slot is activated by the time specified. Slots activated before the delay will remain active after the delay time has passed. Retrasa el momento en que la siguiente ranura es activado por el tiempo especificado. Las ranuras activadas antes de que el retraso se mantendrá activa una vez transcurrido el tiempo de retardo. Distance action specifies that the slots afterwards will only be executed when an axis is moved a certain range past the designated dead zone. Distancia acción especifica que las ranuras después sólo se ejecutan cuando un eje se mueve de un cierto rango más allá de la zona muerta designada. Insert a hold action. Slots after the action will only be executed if the button is held past the interval specified. Inserte una acción de retención. Las ranuras después de la acción sólo se ejecutarán si el botón se mantiene más allá del intervalo especificado. Chose a profile to load when this slot is activated. Elija un perfil para cargar cuando se activa esta ranura. Mouse mod action will modify all mouse speed settings by a specified percentage while the action is being processed. This can be useful for slowing down the mouse while sniping. El Mod de acción del ratón va a modificar todos los ajustes de velocidad del ratón en un porcentaje especificado, mientras que la acción se está procesando. Esto puede ser útil para ralentizar el ratón para francotiradores. Specify the time that keys past this slot should be held down. Especificar el tiempo que las teclas pasan en esta ranura deben mantenerse presionadas. Insert a release action. Slots after the action will only be executed after a button release if the button was held past the interval specified. Insertar una acción de liberación. Las ranuras después de la acción sólo se ejecutarán después de la liberación del botón si este fue presionado más allá del intervalo especificado. Change to selected set once slot is activated. Cambiar al set seleccionado una vez que se activa la ranura. Full string will be typed when a slot is activated. La cadena completa se tecleará cuando se activa una ranura. Execute program when slot is activated. Ejecutar el programa cuando se activa la ranura. Choose Profile Elegir Perfil Config Files (*.amgp *.xml) Archivos de Config (*.amgp *.xml) AdvanceStickAssignmentDialog Stick/Pad Assignment Asignamiento de Palanca/Pad Sticks Palancas DPads DPads %1 (Joystick %2) %1 (Mando %2) Stick 1 Palanca 1 Enabled Habilitar Assign Asignar X Axis: Eje X: Y Axis: Eje Y: Stick 2 Palanca 2 Number of Physical DPads: %1 Numero de DPads físicos: %1 Virtual DPad 1 DPad 1 Virtual Up: Arriba: Down: Abajo: Note: This window is meant for backwards compatibility with profiles made before antimicro 2.0. Since version 2.0, use of the Game Controller Mapping window is preferred. Nota: Esta ventana es para la retrocompatibilidad con los perfiles realizados antes Antimicro 2.0. Desde la versión 2.0, se prefiere el uso de la ventana de juego Mapeo controlador. Left: Izquierda: Right: Derecha: Axis %1 Ejes %1 Axis %1 - Ejes %1 - Axis %1 + Ejes %1 + Button %1 Botón %1 Move stick 1 along the X axis Mueva la palanca 1 a lo largo del eje X Move stick 1 along the Y axis Mueva la palanca 1 a lo largo del eje Y Move stick 2 along the X axis Mueva la palanca 2 a lo largo del eje X Move stick 2 along the Y axis Mueva la palanca 2 a lo largo del eje Y Press a button or move an axis Presione un botón o mueva un eje AxisEditDialog Axis Ejes Mouse (Horizontal) Ratón (Horizontal) Mouse (Inverted Horizontal) Ratón (Horizontal Invertido) Mouse (Vertical) Ratón (Vertical) Mouse (Inverted Vertical) Ratón (Vertical Invertido) Arrows: Up | Down Direccionales: Arriba | Abajo Arrows: Left | Right Direccionales: Izquierda | Derecha Keys: W | S Teclas: W | S Keys: A | D Teclas: A | D NumPad: KP_8 | KP_2 Teclado Num: 8 | 2 NumPad: KP_4 | KP_6 Teclado Num: 4 | 6 None Nada Set the value to use as the limit for an axis. Useful for a worn out analog stick. Establecer el valor a utilizar como límite para un eje. Útil para una palancas analógicas desgastadas. Negative Half Throttle Mitad de Acelerador Negativo Positive Half Throttle Mitad de Acelerador Positivo Name: Nombre: Specify the name of an axis. Especificar un nombre para un eje. Mouse Settings Configuraciones de Ratón Set the value of the dead zone for an axis. Establecer el valor de la zona muerta para un eje. Presets: Presets: Dead Zone: Zona Muerta: Max Zone: Zona Maxima: [NO KEY] [SIN TECLA] Throttle setting that determines the behavior of how to interpret an axis hold or release. Ajuste del acelerador la que determina el comportamiento de la forma de interpretar un eje de retención o liberación. Negative Throttle Acelerador Negativo Normal Normal Positive Throttle Acelerador Positivo Current Value: Valor Actual: Set Set %1 Left Mouse Button Botón Izquierdo del Ratón Right Mouse Button Botón Derecho del Ratón ButtonEditDialog Dialog Dialogo To make a new assignment, press any keyboard key or click a button in the Keyboard or Mouse tab Para realizar una nueva asignación, pulse cualquier tecla del teclado o haga clic en un botón en el teclado o en la pestaña ratón Placeholder marcador de posición Toggle Alternar Enables a key press or release to only occur when a controller button is pressed. Habilita la pulsación de una tecla o la liberación que sólo ocurren cuando se pulsa un botón del mando. Enables rapid key presses and releases. Turbo controller. Permite a las pulsaciones de teclas rápidas y liberaciones. Controlador Turbo. Turbo Turbo Current: Presente: Slots Ranuras Na&me: No&mbre: Specify the name of a button. Especifique el nombre de un botón. Action: Acción: Specify the action that will be performed in game while this button is being used. Especificar la acción que se llevará a cabo en juego, mientras se está utilizando este botón. Advanced Avanzado Set Set Set %1 Set %1 CapturedWindowInfoDialog Captured Window Properties Information About Window Class: Clase: TextLabel Title: Titulo: Path: Camino: Match By Properties Class Clase Title Titulo Path Camino Full Path File Name CommandLineUtility Profile location %1 is not an XML file. Localización de Perfil %1 no es un archivo XML válido. Profile location %1 does not exist. Localización de Perfil %1 No existe. An invalid set number '%1' was specified. Un numero de Set inválido '%1' fué especificado. Controller identifier '%s'' is not a valid value. Controlador idendificado '%s'' no es un valor válido (valga la redundancia). No display string was specified. Ninguna cadena de exibición fué especificado. Controller identifier is not a valid value. No set number was specified. No controller was specified. An invalid event generator was specified. No event generator string was specified. Qt style flag was detected but no style was specified. No log level specified. antimicro version Usage: antimicro [options...] [profile] Options Print help text. Print version information. Launch program in system tray only. Launch program with the tray menu disabled. Launch program without the main window displayed. Launch program with the configuration file selected as the default for selected controllers. Defaults to all controllers. Apply configuration file to a specific controller. Value can be a controller index, name, or GUID. Unload currently enabled profile(s). Value can be a controller index, name, or GUID. Start joysticks on a specific set. Value can be a controller index, name, or GUID. Advance profile loading set options. Launch program as a daemon. Enable logging. Use specified display for X11 calls. Useful for ssh. Choose between using XTest support and uinput support for event generation. Default: xtest. Choose between using SendInput and vmulti support for event generation. Default: sendinput. Print information about joysticks detected by SDL. Open game controller mapping window of selected controller. Value can be a controller index or GUID. DPadContextMenu Mouse (Normal) Ratón (Normal) Mouse (Inverted Horizontal) Ratón (Horizontal Invertido) Mouse (Inverted Vertical) Ratón (Vertical Invertido) Mouse (Inverted Horizontal + Vertical) Ratón (Horizontal+Vertical Invertido) Arrows Direccionales Keys: W | A | S | D Teclas: W | A | S | D NumPad Teclado Num None Nada Standard Estándar Eight Way Ocho Vías 4 Way Cardinal 4 Vias Cardinal 4 Way Diagonal 4 Vias Diagonal Mouse Settings Configuracion de Ratón DPadEditDialog Dialog Dialogo Presets: Presets: Mouse (Normal) Ratón (Normal) Mouse (Inverted Horizontal) Ratón (Horizontal Invertido) Mouse (Inverted Vertical) Ratón (Vertical Invertido) Mouse (Inverted Horizontal + Vertical) Ratón (Horizontal+Vertical Invertido) Arrows Direccionales Keys: W | A | S | D Teclas: W | A | S | D NumPad Teclado Num None Nada Dpad Mode: Modo Dpad: &Name: &Nombre: 4 Way Cardinal 4 Vias Cardinal 4 Way Diagonal 4 Vias Diagonal DPad Delay: Retraso de Dpad: Time lapsed before a direction change is taken into effect. Tiempo transcurrido antes de un cambio de dirección se tenga en efecto. s s Specify the name of a dpad. Especificar un nombre para Dpad. Mouse Settings Configuracion de Ratón Standard Estándar Standard: 8 region dpad with two direction buttons active when the dpad is in a diagonal region. Eight Way: 8 region dpad with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region dpad with regions corresponding to the cardinal directions of the dpad. Useful for menus. 4 Way Diagonal: 4 region dpad with each region corresponding to a diagonal zone. Estándar: Dpad de 8 regiones con dos botones de dirección activa cuando el dpad está en una región diagonal. Ocho manera: Dpad de 8 regiones con cada dirección que tiene su botón dedicado propio. Sólo un botón está siempre activo en en el momento. Útil para los juegos rougelike. 4 Way cardenal: Dpad de 4 regiones con las regiones correspondientes a los puntos cardinales de la DPAD. Útil para los menús. 4 Way Diagonal: Dpad de 4 regiones con cada región que corresponde a una zona de diagonal. Eight Way Ocho Vías Set Set Set %1 Set %1 EditAllDefaultAutoProfileDialog Default Profile Perfil por Defecto Profile: Perfil: Browse Navegar Open Config Abrir Config Profile file path is invalid. La ruta de archivo de perfil es invalido. ExtraProfileSettingsDialog Extra Profile Settings Configuraciones Extra de Perfil Key Press Time: Tiempo de presionado de Tecla: 0.00 ms 0.00 ms Profile Name: Nombre del Perfil: s s GameController Game Controller Controlador de juego GameControllerDPad DPad DPad GameControllerMappingDialog Game Controller Mapping Mapeo de Controles de Juego <html><head/><body><p>antimicro makes use of the <a href="https://wiki.libsdl.org/CategoryGameController"><span style=" text-decoration: underline; color:#0057ae;">Game Controller API</span></a> provided by SDL 2 in order to abstract various gamepads to fit a unified standard. In order to make a button assignment, please highlight the mapping cell for the appropriate button row below. You can then press a button or move an axis on your gamepad and the cell will update with the physical button or axis that will be used.</p><p>antimicro will use the mapping that you specify to save a mapping string that will be loaded into SDL.</p></body></html> A B X Y Back Start Guide Left Shoulder Right Shoulder Left Stick Click Right Stick Click Left Stick X Left Stick Y Right Stick X Right Stick Y Left Trigger Right Trigger DPad Up DPad Left DPad Down DPad Right Mapping SDL 2 Game Controller Mapping String Last Axis Event: Current Axis Detection Dead Zone: 5000 5000 10000 10000 15000 15000 20000 20000 25000 25000 30000 30000 32000 32000 Game Controller Mapping (%1) (#%2) Mapeo de Controles de Juego (%1) (#%2) Discard Controller Mapping? ¿Descartar Mapeo de Controlador? Discard mapping for this controller? If discarded, the controller will be reverted to a joystick once you refresh all joysticks. ¿Descartar Mapeo para este controlador? Si lo descarta, el controlador podrá revertirse a un mando una vez que se actualicen todos los mandos. GameControllerSet Back Guide Start LS Click RS Click L Shoulder R Shoulder L Trigger R Trigger GameControllerTrigger Trigger Gatillo JoyAxis Axis Ejes JoyAxisButton Negative Negativo Positive Positivo Unknown Desconocido Button Botón JoyAxisContextMenu Mouse (Horizontal) Ratón (Horizontal) Mouse (Inverted Horizontal) Ratón (Horizontal Invertido) Mouse (Vertical) Ratón (Vertical) Mouse (Inverted Vertical) Ratón (Vertical Invertido) Arrows: Up | Down Direccionales: Arriba | Abajo Arrows: Left | Right Direccionales: Izquierda | Derecha Keys: W | S Teclas: W | S Keys: A | D Teclas: A | D NumPad: KP_8 | KP_2 Teclado Num: 8 | 2 NumPad: KP_4 | KP_6 Teclado Num: 4 | 6 None Nada Mouse Settings Configuracion de Ratón Left Mouse Button Botón Izquierdo del Ratón Right Mouse Button Botón Derecho del Ratón JoyButton Processing turbo for #%1 - %2 Procesando turbo para #%1 - %2 Finishing turbo for button #%1 - %2 Finalizando turbo para botón #%1 - %2 Processing press for button #%1 - %2 Procesando de presionado para botón #%1 - %2 Processing release for button #%1 - %2 Procesando de liberacion de botón #%1 - %2 Distance change for button #%1 - %2 Distancia de cambio para botón #%1 - %2 Button Botón [NO KEY] [SIN TECLA] [Set %1 1W] [Set %1 1W] [Set %1 2W] [Set %1 2W] [Set %1 WH] [Set %1 WH] JoyButtonContextMenu Toggle Alternar Turbo Turbo Clear Limpiar Set Select Seleccionar Set Disabled Inhabilitado Set %1 Set %1 Set %1 1W Set %1 1W Set %1 2W Set %1 2W Set %1 WH Set %1 WH JoyButtonSlot Mouse Ratón Up Arriba Down Abajo Left Izquierda Right Derecha LB BI MB BM RB BD B4 B4 B5 B5 Pause Pausa Hold Mantener Cycle Ciclo Distance Distancia Release Soltar Mouse Mod Raton Mod Press Time Tiempo de presionado Delay Retraso Load %1 Cargar %1 Set Change %1 Cambiar Set %1 [Text] %1 [Texto] %1 [Exec] %1 [Ejec] %1 [NO KEY] [SIN TECLA] JoyControlStick Stick Palanca JoyControlStickButton Up Arriba Down Abajo Left Izquierda Right Derecha Button Botón JoyControlStickContextMenu Mouse (Normal) Ratón (Normal) Mouse (Inverted Horizontal) Ratón (Horizontal Invertido) Mouse (Inverted Vertical) Ratón (Vertical Invertido) Mouse (Inverted Horizontal + Vertical) Ratón (Horizontal+Vertical Invertido) Arrows Direccionales Keys: W | A | S | D Teclas: W | A | S | D NumPad Teclado Num None Nada Standard Estándar Eight Way Ocho Vías 4 Way Cardinal 4 Vias Cardinal 4 Way Diagonal 4 Vias Diagonal Mouse Settings Configuracion de Ratón JoyControlStickEditDialog Dialog Dialogo X: 0 0 Y: Distance: Distancia: Presets: Presets: Mouse (Normal) Ratón (Normal) Mouse (Inverted Horizontal) Ratón (Horizontal Invertido) Mouse (Inverted Vertical) Ratón (Vertical Invertido) Mouse (Inverted Horizontal + Vertical) Ratón (Horizontal+Vertical Invertido) Arrows Direccionales Keys: W | A | S | D Teclas: W | A | S | D NumPad Teclado Num None Nada Stick Mode: Modo Palanca: Standard: 8 region stick with two direction buttons active when the stick is in a diagonal region. Eight Way: 8 region stick with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region stick with regions corresponding to the cardinal directions of the stick. Useful for menus. 4 Way Diagonal: 4 region stick with each region corresponding to a diagonal zone of the stick. Estándar: Dpad de 8 regiones con dos botones de dirección activa cuando el dpad está en una región diagonal. Ocho manera: Dpad de 8 regiones con cada dirección que tiene su botón dedicado propio. Sólo un botón está siempre activo en en el momento. Útil para los juegos rougelike. 4 Way cardenal: Dpad de 4 regiones con las regiones correspondientes a los puntos cardinales de la DPAD. Útil para los menús. 4 Way Diagonal: Dpad de 4 regiones con cada región que corresponde a una zona de diagonal. 4 Way Cardinal 4 Vias Cardinal 4 Way Diagonal 4 Vias Diagonal Dead zone value to use for an analog stick. Valores de Zona Muerta usadas para una palanca analogica. Value when an analog stick is considered moved 100%. Valor cuando una palanca analogica se considera que se movió al 100%. The area (in degrees) that each diagonal region occupies. El área (en grados) que cada región ocupa. Square Stick: Palanca cuadrada: Percentage to modify a square stick coordinates to confine values to a circle Porcentaje para modificar las coordenadas de la palanca cuadrada para confinar valores para el ciclo % % Stick Delay: Retraso de Palanca: Time lapsed before a direction change is taken into effect. Tiempo transcurrido antes de un cambio de dirección tomado en efecto. s s Modifier: Modificador: Edit button that is active while the stick is active. This button is useful for assigning zones with modifier keys that can be used to assign walk/run functionality to an analog stick. PushButton Presione un Botón Name: Nombre: Specify the name of an analog stick. Especificar un nombre para una palanca analogica. Mouse Settings Configuraciones de Ratón Standard Estándar Bearing: % Safe Zone: % Zona Segura: Eight Way Ocho Vías Dead Zone: Zona Muerta: Max Zone: Zona Maxima: Diagonal Range: Rango Diagonal: Set Set Set %1 Set %1 JoyControlStickModifierButton Modifier Modificador JoyDPad DPad DPad JoyDPadButton Up Arriba Down Abajo Left Izquierda Right Derecha Button Botón JoyTabWidget <New> Remove Remove configuration from recent list. Load Cargar Load configuration file. Save Save changes to configuration file. Save As Save changes to a new configuration file. Sets Copy from Set Settings Configuraciones Set 1 Set 1 Set 2 Set 2 Set 3 Set 3 Set 4 Set 4 Set 5 Set 5 Set 6 Set 6 Set 7 Set 7 Set 8 Set 8 Stick/Pad Assign Asignación de Palanca/Pad Controller Mapping Quick Set Configuración rápida Names Toggle button name displaying. Pref Change global profile settings. Reset Revert changes to the configuration. Reload configuration file. Open Config Abrir Config Config Files (*.amgp *.xml) Archivos de Config (*.amgp *.xml) Config File (*.%1.amgp) Save Profile Changes? Changes to the new profile have not been saved. Would you like to save or discard the current profile? Changes to the profile "%1" have not been saved. Would you like to save or discard changes to the current profile? Sticks Palancas DPads DPads No buttons have been assigned. Please use Quick Set to assign keys to buttons or disable hiding empty buttons. Set %1: %2 Set %1: %2 Set %1 Set %1 Copy Set Assignments Are you sure you want to copy the assignments and device properties from %1? Save Config Set Set Joystick Joystick Mando JoystickStatusWindow Properties Propiedades Details Detalles Name: Nombre: %1 %1 Number: Numero: Axes: Ejes: Buttons: Botones: Hats: Hats: GUID: GUID: Game Controller: Controlador de Juego: Axes Ejes Buttons Botones Hats Hats %1 (#%2) Properties %1 (#%2) Propiedades Axis %1 Ejes %1 Hat %1 Hat %1 No No Yes Si MainSettingsDialog Edit Settings Editar Configuraciones General General Controller Mappings Mapeo de controles Language Lenguaje Auto Profile Auto Perfil Mouse Ratón <html><head/><body><p>Specify the default directory that the program should use in file dialogs when loading a profile or saving a new profile.</p></body></html> <html><head/><body><p>Especificar el directorio por defecto que el programa debe utilizar en los diálogos de archivo cuando se carga un perfil o guardar un nuevo perfil.</p></body></html> Recent Profile Count: Contaje de Perfiles Recientes: <html><head/><body><p>Number of profiles that can be placed in recent profile list. 0 will result in the program not enforcing a limit on the number of profiles displayed.</p></body></html> <html><head/><body><p>Número de perfiles que se puede colocar en la lista de perfil reciente. 0 dará lugar a que el programa no cumplir un límite en el número de perfiles que se muestran.</p></body></html> Gamepad Poll Rate: Taza de Sondeo de Mando: Change the poll rate that the program uses to discover new events from gamepads. Defaults to 10 ms. Reducing the poll rate value could cause the application to use more CPU power so please test the setting that you use before using antimicro unattended. Cambiar la velocidad de sondeo que el programa utiliza para descubrir nuevos eventos de mandos. El valor predeterminado es de 10 ms. La reducción del valor de velocidad de sondeo podría causar que la aplicación usar más energía de la CPU así que por favor probar la configuración que utilice antes de usar Antimicro desatendida. Hide main window when the main window close button is clicked instead of quitting the program. Ocultar ventana principal cuando el botón de la ventana principal es estrecha se hace clic en lugar de salir del programa. Close To Tray Cerrar para la bandeja del sistema Have Windows start antimicro at system startup. Hacer que Windows inicie Antimicro junto con el sistema. Launch At Windows Startup Iniciar junto con Windows Display recent profiles for all controllers as a single list in the tray menu. Defaults to using sub-menus. Mostrar perfiles más recientes de todos los mandos como una única lista en el menú de la bandeja. predeterminados a la utilización de los submenús. Single Profile List in Tray Lista única de perfiles en la bandeja de sistema Have the program minimize to the taskbar. By default, the program minimizes to the system tray if available. Hacer que el programa minimize la barra de tareas. Por defecto, el programa se minimiza en el sistema la bandeja si está disponible. Minimize to Taskbar Minimizar para la barra de tareas This option will cause the program to hide all buttons that have no slots assigned to them. The Quick Set dialog window will have to be used to bring up the edit dialog for gamepad buttons. Esta opción hará que el programa para ocultar todos los botones que no tienen ranuras asignadas. La ventana de diálogo de configuración rápida tendrá que ser utilizado para que aparezca el diálogo de edición para los botones del mando. Hide Empty Buttons Ocultar Botones Vacíos When the program is launched, open the last known profile that was opened during the previous session. Cuando el programa esté en marcha, abrir el último perfil conocido que se abrió durante la sesión anterior. Auto Load Last Opened Profile Auto Cargar el ultimo perfil abierto Only show the system tray icon when the program first launches. Solamente mostrar el icono en la bandeja de sistema cuando el programa inicie por primera vez. Launch in Tray Lanzar en la bandeja del sistema Associate .amgp files with antimicro in Windows Explorer. Asociar archivos .amgp con antimicro en Windows Explorer. Associate Profiles Asociar Perfiles Key Repeat Repetición de Tecla Active keys will be repeatedly pressed when this option is enabled. Las teclas activadas serán presionadas repetidamente cuando esta opción esté activada. Enable Habilitar Specifies how much time should elapse before key repeating begins. Especifica cuánto tiempo debe transcurrir antes de repetión de tecla comienza. Specifies how many times key presses will be performed per seconds. Especifica cuántas veces se llevarán a cabo las pulsaciones de teclas por segundo. <html><head/><body><p>antimicro has been translated into many different languages by contributors. By default, the program will choose an appropriate translation based on your system's locale setting. However, you can make antimicro load a different translation depending on the language that you choose from the list below.</p></body></html> <html><head/><body><p>Antimicro ha sido traducido a muchos idiomas diferentes por los contribuyentes. Por defecto, el programa elegirá una traducción apropiada basada en la configuración regional de su sistema. Sin embargo, puede hacer que la carga Antimicro una traducción diferente en función del idioma que elija en la lista siguiente.</p></body></html> French Francés Italian Japanese Japonés Russian Ruso Serbian Serbio Simplified Chinese Chino Simplificado Ukrainian Ucraniano Class Clase Title Titulo Program Programa Disable the "Enhanced Pointer Precision" Windows setting while antimicro is running. Disabling "Enhanced Pointer Precision" will allow mouse movement within antimicro to be more precise. Deshabilitar la configuración de Windows "mejorada precisión del puntero" mientras Antimicro se está ejecutando. La desactivación "mejorada precisión del puntero" permitirá el movimiento del ratón dentro de Antimicro a ser más preciso. Disable Enhance Pointer Precision Desactivar la precisión del puntero mejorado Smoothing suavizado Histor&y Size: Tamaño del &Historial: Weight &Modifier: &Modificador de peso: Refresh Rate: Taza de Actualizacion: The refresh rate is the amount of time that will elapse in between mouse events. Please be cautious when editing this setting as it will cause the program to use more CPU power. Setting this value too low can cause system instability. Please test the setting before using it unattended. La frecuencia de actualización es la cantidad de tiempo que transcurrirá entre los eventos del ratón. Por favor tenga cuidado cuando la edición de este ajuste ya que esto haría que el programa utilice más potencia de CPU. Un valor demasiado bajo puede causar inestabilidad del sistema. Por favor, probar la configuración antes de usar sin vigilancia. Spring Spring Screen: Pantalla: Utilize the specified screen for spring mode. On Linux, the default is to use the primary screen. On Windows, the default is to use all available screens. Utilizar la pantalla especificada para el modo spring. En Linux, el por defecto es el uso de la pantalla principal. En Windows, el valor por defecto es utilizar todas las pantallas disponibles. Accel Numerator: Numerador de Aceleración: 0 0 Accel Denominator: Denominador de Aceleración: Accel Threshold: Límite de Aceleración: If the acceleration values for the virtual mouse have been changed by a different process, particularly when quitting an older game, then you might want to reset the acceleration values used by the virtual mouse. Si los valores de aceleración para el ratón virtual han sido cambiados por un proceso diferente, particularmente cuando se cierra un juego antiguo, entonces es posible que desee restablecer la aceleración Los valores utilizados por el ratón virtual. Reset Acceleration Resetear Aceleración Delay: Retraso: Profi&le Directory: Directorio de Perfi&l: ms ms Rate: Taza: times/s tiempo/s Below is a list of the custom mappings that have been saved. You can use the following table to delete mappings or have mappings temporarily disabled. You can also disable mappings that are included with SDL; just insert a new row with the appropriate joystick GUID and check disable. Settings will not take affect until you either refresh all joysticks or unplug that particular joystick. A continuación se muestra una lista de las asignaciones personalizados que se han guardado. Puede usar la siguiente tabla para eliminar las asignaciones o tienen asignaciones temporalmente deshabilitados. También puede desactivar las asignaciones que se incluyen con SDL; sólo tiene que insertar una nueva fila con el GUID de la palanca de mando correspondiente y vaya desactivar. Los ajustes no tendrán efecto hasta que actualizar todos los mandos o desenchufar el mando en particular. GUID GUID Mapping String Cadena de Mapeo Disable? Inhabilitar? Delete Borrar Insert Insertar Default Por Defecto Brazilian Portuguese Portugués de Brasil English Inglés German Alemán Active Activo Devices: Dispositivos: All Todo Device Dispositivo Profile Perfil Default? Por Defecto? Add Agregar Edit Editar Also, Windows users who want to use a low value should also check the "Disable Enhance Pointer Precision" checkbox if you haven't disabled the option in Windows. Además, los usuarios de Windows que deseen utilizar un valor bajo,pueden tambien marcarl "Desactivar el puntero de precisión" en caso de que no haya desactivado la opción en Windows. Select Default Profile Directory Seleccionar el Directorio de Perfil por defecto Are you sure you want to delete the profile? Está seguro que quiere borrar el perfil? MainWindow antimicro antimicro No Joysticks have been found. Please plug in a joystick and then choose the "Update Joysticks" option in the main menu Ningún Mando fue encontrado Por favor conecte un Mando y elija la opción "Actualizar Mandos" en el menu principal If events are not seen by a game, please click here to run this application as the Adminstrator. Si los eventos no son vistos por un juego, por favor haga clic aquí para ejecutar esta aplicación como administrador. &App &App &Options &Opciones &Help A&yuda &Quit S&alir Ctrl+Q Ctrl+Q &Update Joysticks Act&ualizar Mandos Ctrl+U Ctrl+U &Hide O&cultar Ctrl+H Ctrl+H &About So&bre Ctrl+A Ctrl+A About Qt Sobre Qt Properties Propiedades Key Checker Verificador de Teclas Home Page Home Page GitHub Page Página GitHub Game Controller Mapping Mapeo de Controles de Juego Settings Configuraciones Stick/Pad Assign Asignación de Palanca/Pad Wiki Wiki Could not find a proper controller identifier. Exiting. No se pudo encontrar un identificador de controlador apropiado.Saliendo. (%1) (%1) Open File Abrir Archivo &Restore &Restaurar Run as Administrator? ¿Ejecutar como Administrador? Are you sure that you want to run this program as Adminstrator? Some games run as Administrator which will cause events generated by antimicro to not be used by those games unless antimicro is also run as the Adminstrator. This is due to permission problems caused by User Account Control (UAC) options in Windows Vista and later. ¿Estás seguro de que desea ejecutar este programa como Adminstrator? Algunos juegos se ejecutan como administrador lo que hará que los eventos generados por Antimicro para no ser utilizado por aquellos juegos a menos Antimicro también se ejecuta como el Adminstrator. Esto se debe a problemas de permisos causadas por las opciones de Control de cuentas de usuario (UAC) en Windows Vista y versiones posteriores. Failed to elevate program Fallo al elevar el programa Failed to restart this program as the Administrator Fallo al reiniciar este programa como administrador Could not find controller. Exiting. No se pudo encontrar un controlador. Saliendo. MouseAxisSettingsDialog Mouse Settings - Configuraciones de Ratón - Set %1 Set %1 MouseButtonSettingsDialog Mouse Settings - Configuraciones de Ratón - Set %1 Set %1 MouseControlStickSettingsDialog Mouse Settings Configuraciones de Ratón Set %1 Set %1 MouseDPadSettingsDialog Mouse Settings Configuraciones de Ratón Set %1 Set %1 MouseSettingsDialog Mouse Settings Configuracion de Ratón Mouse Mode: Modo Ratón: Cursor mode is used to move the mouse cursor around the screen relative to its current position depending on how much you move an axis or if a button is pressed. Spring mode is used to move the mouse cursor from the center of the screen depending on how much you move an axis. The mouse cursor will be returned to the center of the screen when the axis is moved back to the dead zone. Cursor Cursor Spring Spring Acceleration: Aceleración: Enhanced Precision Puntero Mejorado Linear Quadratic Cubic Quadratic Extreme Power Function Easing Quadratic Easing Cubic Mouse Speed Settings Enable to change the horizontal and vertical speed boxes at the same time. Change Together Options for adding more acceleration to the mouse movement beyond what the acceleration curve would produce. Acceleration is added based on how quickly an axis is moved in one gamepad poll. This is meant to help work around some of the issues of the very limited input range available using typical gamepad analog sticks. Delta Acceleration &Multiplier: Mi&n Threshold: Horizontal Speed: Velocidad Horizontal: 1 = 20 pps Vertical Speed: Velocidad Vertical: Wheel Hori. Speed: Set the speed used for horizontal mouse wheel movement according to number of simulated notches per second. Set the speed used for vertical mouse wheel movement according to number of simulated notches per second. Sensitivit&y: For Power Function acceleration curve. Specifies the factor to use for curve sensitivity. When the value is above 1.0, the mouse movement will be accelerated faster at the low end of an axis. Easing Duration: s s Extra Acceleration Aceleración Extra Multiplier: Multiplicador: Highest value to accelerate mouse movement by x Start %: Acceleration begins at this percentage of the base multiplier La aceleración comienza en este porcentaje de la base de multiplicador Min Threshold: Límite Mínimo: Minimum amount of axis travel required for acceleration to begin cantidad mínima de recorrido del eje requerido para la aceleración a comenzar Max Threshold: Límite Máximo: Maximum axis travel before acceleration has reached the multiplier value El recorrido máximo del eje antes de la aceleración ha alcanzado el valor del multiplicador E&xtra Duration: Curve: Curva: Ease Out Sine Ease Out Quad Ease Out Cubic Release Radius: Specifies that the spring area will be relative to the mouse position set by a non-relative spring. Relative Mouse Status X: 0 (0 pps) Y: 1 = 1 notch(es)/s Enhanced: Three tier curve that makes the mouse move slow on the low end of an axis and fast on the high end. Linear: Mouse moves proportionally to axis. Quadratic: Mouse accelerates slowly on low end. Cubic: Mouse accelerates slower than Quadratic. Quadratic Extreme: Raises mouse speed 1.5 times once 95% axis travel has been reached. Power Function: Allows for a more custom curve option. Easing Quadratic: Axis high end is gradually accelerated over a period of time using a Quadratic curve. Easing Cubic: Axis high end is gradually accelerated over a period of time using a Cubic curve. Hori&zontal Speed: &Vertical Speed: Wheel Vert. Speed: Specifies the amount of time (in seconds) that will be required before the mouse is fully accelerated after reaching the high end of an axis. % % Extend the time that extra acceleration is applied. Axis travel will be taken into account. A slower flick will decrease the actual time that extra acceleration will be applied. Spring Settings Spring Width: Changes the width of the region that the cursor can move in spring mode. 0 will use the entire width of your screen. Spring Height: Changes the height of the region that the cursor can move in spring mode. 0 will use the entire height of your screen. %n notch(es)/s %n notch/s %n notches/s QKeyDisplayDialog Key Checker Verificador de Teclas <html><head/><body><p>Press a key on your keyboard to see how the key is detected by this application. The window will show the system native key value, the original value given by Qt (if applicable), and the custom value used by antimicro.</p><p>The antimicro key value and the Qt key value will usually be the same. antimicro tries to use the key values defined in Qt when possible. Check the page <a href="https://doc.qt.io/qt-4.8/qt.html#Key-enum"><span style=" text-decoration: underline; color:#0057ae;">https://doc.qt.io/qt-4.8/qt.html#Key-enum</span></a> for a list of values defined by Qt. If you discover that a key is not natively supported by this program, please report the problem to antimicro's <a href="https://github.com/AntiMicro/antimicro"><span style=" text-decoration: underline; color:#0057ae;">GitHub page</span></a> so that the program can be edited to support it directly. As it is, a custom prefix is added to unknown values so they can still be used; the main problem is that the profile will no longer be portable.</p></body></html> <html><head/><body><p>Presione una tecla del teclado para ver cómo se detecta la tecla por esta aplicación. La ventana mostrará el valor de la tecla del sistema nativo, el valor original dada por Qt (si es el caso), y el valor personalizado utilizado por Antimicro. </p><p> El valor de la tecla Antimicro y el valor de tecla Qt generalmente es la misma . Antimicro intenta utilizar los valores de las claves definidas en Qt cuando sea posible. Vea la página <a href="https://doc.qt.io/qt-4.8/qt.html#Key-enum"><span style=" text-decoration: underline; color:#0057ae;">https://doc.qt.io/qt-4.8/qt.html#Key-enum</span></a> para una lista de valores definidos por Qt. Si descubre que la tecla no es compatible de forma nativa por este programa, por favor informa del problema al estilo de Antimicro <a href="https://github.com/AntiMicro/antimicro"><span style=" text-decoration: underline; color:#0057ae;">GitHub page</span></a> para que el programa pueda editarlo para soportarlo directamente. Tal como es, se añade un prefijo personalizado para valores desconocidos por lo que todavía se pueden utilizar; el principal problema es que el perfil ya no será portátil.</p></body></html> Event Handler: Controlador de eventos: Native Key Value: Valor de tecla nativo: 0x00000000 0x00000000 Qt Key Value: Valor QT de Tecla: antimicro Key Value: Valor Antimicro de Tecla: QObject Super Menu Menu Mute Vol+ Vol- Play/Pause Play Pause Pausa Prev Next Mail Home Media Media Search Buscar Daemon launched Failed to launch daemon Launching daemon Display string "%1" is not valid. Failed to set a signature id for the daemon Failed to change working directory to / Quitting Program Saliendo del Programa # of joysticks found: %1 # de mandos econtrados: %1 List Joysticks: Lista de Mandos: --------------- Joystick %1: Index: %1 GUID: %1 GUID: %1 Name: %1 Nombre: %1 Yes Si No No Game Controller: %1 Controlador de Juego: %1 # of Axes: %1 # of Buttons: %1 # of Hats: %1 Attempting to use fallback option %1 for event generation. Failed to open event generator. Exiting. Using %1 as the event generator. Could not raise process priority. QuickSetDialog Quick Set Configuración rápida <html><head/><body><p>Please press a button or move an axis on %1 (<span style=" font-weight:600;">%2</span>).<br/>A dialog window will then appear which will<br/>allow you to make an assignment.</p></body></html> <html><head/><body><p>Por favor, pulse un botón o mueva un eje en %1 (<span style=" font-weight:600;">%2</span>).<br/>una ventana de diálogo aparecerá entonces<br/>permitirá crear una asignación.</p></body></html> Quick Set %1 Configuración rápida %1 SetAxisThrottleDialog Throttle Change Cambio del acelerador The throttle setting for Axis %1 has been changed. Would you like to distribute this throttle change to all sets? La posición del acelerador para el Eje %1 ha sido cambiado ¿Le gustaría distribuir este cambio acelerador para todos los sets? SetJoystick Set %1: %2 Set %1: %2 Set %1 Set %1 SetNamesDialog Set Name Settings Config Nombre de Set Set 1 Set 1 Set 2 Set 2 Set 3 Set 3 Set 4 Set 4 Set 5 Set 5 Set 6 Set 6 Set 7 Set 7 Set 8 Set 8 Name Nombre SimpleKeyGrabberButton Mouse Ratón SpringModeRegionPreview Spring Mode Preview Vista previa de modo Spring UInputEventHandler Could not find a valid uinput device file. Please check that you have the uinput module loaded. lsmod | grep uinput No se pudo encontrar un archivo de dispositivo uinput válida. Por favor, compruebe que tiene el módulo uinput cargado. lsmod | grep uinput Could not open uinput device file Please check that you have permission to write to the device No se pudo abrir archivo de dispositivo uinput Por favor, compruebe que tiene permiso para escribir en el dispositivo Using uinput device file %1 El uso de archivos del dispositivo uinput %1 UInputHelper a b c d e f g h i j k l m n o p q r s s t u v w x y z Esc F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 ` ` 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 0 0 - - = = BackSpace Tab [ [ ] ] \ \ CapsLock ; ; ' ' Enter Shift_L , , . . / / Ctrl_L Super_L Alt_L Space Alt_R Menu Menu Ctrl_R Shift_R Up Arriba Left Izquierda Down Abajo Right Derecha PrtSc Ins Del Home End PgUp PgDn NumLock * * + + KP_Enter Enter_Num KP_1 KP_2 KP_3 KP_4 KP_5 KP_6 KP_7 KP_8 KP_9 KP_0 SCLK SCLK Pause Pausa Super_R Mute VolDn VolUp Play Stop Prev Next [NO KEY] [SIN TECLA] UnixWindowInfoDialog Captured Window Properties Information About Window Class: Clase: TextLabel Title: Titulo: Path: Camino: Match By Properties Class Clase Title Titulo Path Camino VDPad VDPad VDPad VirtualKeyPushButton Space Espaciador Tab Tabulador Shift (L) Mayus (Izq) Shift (R) Mayus (Der) Ctrl (L) Ctrl (Izq) Ctrl (R) Ctrl (Der) Alt (L) Alt (Izq) Alt (R) Alt (Der) ` ` ~ ~ - - = = [ [ ] ] \ \ Caps Caps ; ; ' ' , , . . / / ESC ESC PRTSC PRTSC SCLK SCLK INS INS PGUP RePag DEL SUPR PGDN AvPag 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 0 0 NUM LK BLOCK NUM * * + + E N T E R E N T E R < < : : Super (L) Super (Izq) Menu Menu Up Arriba Down Abajo Left Izquierda Right Derecha VirtualKeyboardMouseWidget Keyboard Teclado Mouse Ratón Mouse Settings Configuraciones de Ratón Left Mouse Ratón Izquierda Up Mouse Ratón Arriba Left Button Mouse Ratón Boton Izquierdo Middle Button Mouse Ratón Boton del Medio Right Button Mouse Ratón Botón Derecho Wheel Up Mouse Ratón Rueda Arriba Wheel Left Mouse Ratón Rueda Izquierda Wheel Right Mouse Ratón Rueda Derecha Wheel Down Mouse Ratón Rueda Abajo Down Mouse Ratón Abajo Right Mouse Ratón Derecha Button 4 Mouse Ratón Botón 4 Mouse 8 Mouse Ratón Ratón 8 Button 5 Mouse Ratón Botón 5 Mouse 9 Mouse Ratón Ratón 9 NONE NADA Applications Aplicaciones Browser Back Navegador Atrás Browser Favorites Navegador Favoritos Browser Forward Navegador Adelante Browser Home Navegador Inicio Browser Refresh Navegador Actualizar Browser Search Navegador Busca Browser Stop Navegador Parar Calc Calc Email Email Media Media Media Next Media Próximo Media Play Media Reproduzir Media Previous Media Anterior Media Stop Media Parar Search Buscar Volume Down Volume Bajar Volume Mute Volume Mudo Volume Up Volume Subir VirtualMousePushButton INVALID INVALIDO WinAppProfileTimerDialog Capture Application Solicitación de Captura After pressing the "Capture Application" button, please select the application window that you want to have a profile associated with. The active application will be captured after the selected number of seconds. Después de pulsar el botón "Solicitud de captura", por favor, seleccione la ventana de la aplicación que desea tener un perfil asociado. La aplicación activa será capturado después del número de segundos seleccionado. Timer: Temporizador: Seconds Segundos Cancel Cancelar WinExtras [NO KEY] [SIN TECLA] AntiMicro Profile Perfil AntiMicro X11Extras ESC ESC Tab Tab Space espaciador DEL SUPR Return ENTER KP_Enter Enter_Num Backspace Backspace xinput extension was not found. No mouse acceleration changes will occur. No se ha encontrado la extensión xinput. no se producirán cambios en la aceleración del ratón. xinput version must be at least 2.0. No mouse acceleration changes will occur. La versión xinput debe ser al menos 2,0. no se producirán cambios en la aceleración del ratón. Virtual pointer found with id=%1. Puntero virtual encontrado con el id=%1. PtrFeedbackClass was not found for virtual pointer.No change to mouse acceleration will occur for device with id=%1 PeerFeedback clase no se encontró para el puntero virtual. Ningún cambio en la aceleración del ratón se producirá para el dispositivo con el id=%1 Changing mouse acceleration for device with id=%1 Cambiando la aceleración del ratón para el dispositivo con id=%1 XMLConfigReader Could not write updated profile XML to file %1. No se puede escribir XML del perfil actualizado en el archivo %1. XMLConfigWriter Could not write to profile at %1. No se pudo escribir al perfil en %1. antimicro-2.23/share/antimicro/translations/antimicro_fr.ts000066400000000000000000011364251300750276700243040ustar00rootroot00000000000000 AboutDialog About À propos Version <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Originally developed by Travis Nickles &lt;nickles.travis@gmail.com&gt;, now maintained by the AntiMicro group at https://github.com/AntiMicro.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Contributors:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;"><br /></span>Zerro Alvein</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">aybe</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jeff Backus &lt;jeff.backus@gmail.com&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Arthur Moore<br />Anton Tornqvist &lt;antont@inbox.lv&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7185</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">DarkStarSword</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">est31</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ProfessorKaos64</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">qwerty12</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA0</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Translators:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VaGNaroK &lt;vagnarokalkimist@gmail.com&gt; - Brazilian Portuguese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx - Chinese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Belleguic Terence &lt;hizo@free.fr&gt; - French</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Leonard Koenig &lt;leonard.r.koenig@googlemail.com&gt; - German</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phob - German</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">tou omiya - Japanese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Dmitriy Koshel &lt;form.eater@gmail.com&gt; - Russian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jay Alexander Fleming &lt;tito.nehru.naser@gmail.com&gt; - Serbian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">burunduk - Ukrainian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Flavio HR &lt;flavio.hrx@gmail.com&gt; - Spanish</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA - wazaaaaa00&lt;@&gt;gmail&lt;.&gt;com - Italian</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> Info Changelog Since December 30, 2012, I have been working on antimicro in my spare time. What originally started as a fork of QJoyPad and a way to learn proper event-driven programming has turned into something much bigger than I originally intended. Although I have spent a lot of time learning new techniques, finding out more about the domain of KB+M emulation, and spending Friday nights bashing my head against my keyboard, it has been a fun and enriching experience overall. The need for this program came from me using similar programs on Windows to play several games that did not provide native controller support. Although some alternatives existed on Linux, there wasn't really anything that I felt was good enough in terms of functionality or in-game controls in order to really enjoy games that I wanted to play with using KB+M emulation. QJoyPad was the main program that I had used in the past although it had aged a lot and it didn't provide some basic functionality that I thought was essential. The project was dead as it had not been updated in several years so I decided to make my own. Since then, I have tried to find out what the other programs do right and then improve upon it. I have also discovered some neat tricks along the way and I have learned more about how native gamepad controls are implemented in some games than I ever really wanted to know. Although there are definitely areas where this program could improve, I find that this program offers the best in-game control experience for playing older, and some newer, games that do not provide native controller support. Development of this program is not as high of a priority for me anymore. This is mainly due to the fact that the Steam Controller works pretty well for the task of playing PC games compared to using an Xbox 360 controller. However, it does look like there is still a reason for this program to exist for a while. Copyright: 2013 - 2016 Credits Crédits antimicro <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">GNU GENERAL PUBLIC LICENSE</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Version 3, 29 June 2007</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Preamble</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Developers that use the GNU GPL protect your rights with two steps:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">(1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The precise terms and conditions for copying, distribution and modification follow.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">TERMS AND CONDITIONS</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">0. Definitions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;This License&quot; refers to version 3 of the GNU General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Copyright&quot; also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;The Program&quot; refers to any copyrightable work licensed under this License. Each licensee is addressed as &quot;you&quot;. &quot;Licensees&quot; and &quot;recipients&quot; may be individuals or organizations.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;modify&quot; a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a &quot;modified version&quot; of the earlier work or a work &quot;based on&quot; the earlier work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;covered work&quot; means either the unmodified Program or a work based on the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;propagate&quot; a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;convey&quot; a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An interactive user interface displays &quot;Appropriate Legal Notices&quot; to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">1. Source Code.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;source code&quot; for a work means the preferred form of the work for making modifications to it. &quot;Object code&quot; means any non-source form of a work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;Standard Interface&quot; means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;System Libraries&quot; of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A &quot;Major Component&quot;, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;Corresponding Source&quot; for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source for a work in source code form is that same work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">2. Basic Permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">3. Protecting Users' Legal Rights From Anti-Circumvention Law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">4. Conveying Verbatim Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">5. Conveying Modified Source Versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) The work must carry prominent notices stating that you modified it, and giving a relevant date.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to &quot;keep intact all notices&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an &quot;aggregate&quot; if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">6. Conveying Non-Source Forms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;User Product&quot; is either (1) a &quot;consumer product&quot;, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, &quot;normally used&quot; refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Installation Information&quot; for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">7. Additional Terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Additional permissions&quot; are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Limiting the use for publicity purposes of names of licensors or authors of the material; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All other non-permissive additional terms are considered &quot;further restrictions&quot; within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">8. Termination.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">9. Acceptance Not Required for Having Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">10. Automatic Licensing of Downstream Recipients.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An &quot;entity transaction&quot; is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">11. Patents.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;contributor&quot; is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's &quot;contributor version&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A contributor's &quot;essential patent claims&quot; are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, &quot;control&quot; includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">In the following three paragraphs, a &quot;patent license&quot; is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To &quot;grant&quot; such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. &quot;Knowingly relying&quot; means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A patent license is &quot;discriminatory&quot; if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">12. No Surrender of Others' Freedom.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">13. Use with the GNU Affero General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">14. Revised Versions of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License &quot;or any later version&quot; applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">15. Disclaimer of Warranty.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM &quot;AS IS&quot; WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">16. Limitation of Liability.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">17. Interpretation of Sections 15 and 16.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.</span></p></body></html> About Development License License Program Version %1 Program Compiled on %1 at %2 Built Against SDL %1 Running With SDL %1 Using Qt %1 Using Event Handler: %1 AddEditAutoProfileDialog Auto Profile Dialog Profile: Browse Window: Select Window. Click on the appropriate application window and the application file path will be populated in the form. Detect Window Properties Class: Title: Application: Select Devices: Select this profile to be the default loaded for the specified device. The selection will be used instead of the all default profile option. Set as Default for Controller A different profile is already selected as the default for this device. Current (%1) Open Config Charger un fichier de configuration Select Program Programs (*.exe) Please use the main default profile selection. Please select a window by using the mouse. Press Escape if you want to cancel. Capture Application Window Could not obtain information for the selected window. Application Capture Failed Profile file path is invalid. No window matching property was specified. Program path is invalid or not executable. File is not an .exe file. No window matching property was selected. AdvanceButtonDialog Advanced Avancé Assignments Assignements Toggle Maintient de la pression Turbo Turbo Set Selector Séléction de réglage Blank or KB/M Hold Maintenir Pause Pause Cycle Cycle Distance Distance Insert Insérer Delete Supprimer Clear All Nettoyer Time: Temps : 0.01s 0,01s 0s 0s Insert a pause that occurs in between key presses. Insére une pause de la durée indiquée entre la pression des touches. Release Relâchement Insert a new blank slot. Insere un nouvel emplacement vide. Delete a slot. Supprime un emplacement. Clear all currently assigned slots. Supprime tous les emplacements assignés. Specify the duration of an inserted Pause or Hold slot. Spécifie la durée de Pause ou de Maintien. 0m 0m &Mouse Speed Mod: Specify the range past an axis dead zone in which a sequence of actions will execute. Spécifie la distance par rapport à la zone morte pour exécuter la suite des actions. Distance: Distance : % % Mouse Mod Mode de la Souris Press Time Delay Execute Load Charger Set Change Text Entry Placeholder Espace réservé 0 0 Mouse Speed Mod: Vitesse du Mode de la Souris : Set the percentage that mouse speeds will be modified by. Régler toutes les vitesses de la souris avec le pourcentage spécifié. Auto Reset Cycle After seconds Executable: ... Arguments: Enabled Activé Mode: <html><head/><body><p>Normal: Repeatedly press and release a button by the chosen rate.</p><p>Gradient: Modify the button press and button release delay based on how far an axis has been moved. The rate will remain the same.</p><p>Pulse: Modify how many times a button is pressed and released per second. The button delay will remain the same.</p></body></html> Normal Normal Gradient Pulse Delay: Intervalle : 0.10s 0,10s Rate: Taux : 10.0/s 10,0/s Disabled Désactivé Select Set 1 One Way Séléction du réglage N°1 : Aller Select Set 1 Two Way Séléction du réglage N°1 : Aller-Retour Select Set 1 While Held Séléction du réglage N°1 : Pendant la pression Select Set 2 One Way Séléction du réglage N°2 : Aller Select Set 2 Two Way Séléction du réglage N°2 : Aller-Retour Select Set 2 While Held Séléction du réglage N°2 : Pendant la pression Select Set 3 One Way Séléction du réglage N°3 : Aller Select Set 3 Two Way Séléction du réglage N°3 : Aller-Retour Select Set 3 While Held Séléction du réglage N°3 : Pendant la pression Select Set 4 One Way Séléction du réglage N°4 : Aller Select Set 4 Two Way Séléction du réglage N°4 : Aller-Retour Select Set 4 While Held Séléction du réglage N°4 : Pendant la pression Select Set 5 One Way Séléction du réglage N°5 : Aller Select Set 5 Two Way Séléction du réglage N°5 : Aller-Retour Select Set 5 While Held Séléction du réglage N°5 : Pendant la pression Select Set 6 One Way Séléction du réglage N°6 : Aller Select Set 6 Two Way Séléction du réglage N°6 : Aller-Retour Select Set 6 While Held Séléction du réglage N°6 : Pendant la pression Select Set 7 One Way Séléction du réglage N°7 : Aller Select Set 7 Two Way Séléction du réglage N°7 : Aller-Retour Select Set 7 While Held Séléction du réglage N°7 : Pendant la pression Select Set 8 One Way Séléction du réglage N°8 : Aller Select Set 8 Two Way Séléction du réglage N°8 : Aller-Retour Select Set 8 While Held Séléction du réglage N°8 : Pendant la pression sec. /sec. Set %1 Select Set %1 One Way Two Way While Held Choose Executable Slots past a Cycle action will be executed on the next button press. Multiple cycles can be added in order to create partitions in a sequence. Delays the time that the next slot is activated by the time specified. Slots activated before the delay will remain active after the delay time has passed. Distance action specifies that the slots afterwards will only be executed when an axis is moved a certain range past the designated dead zone. Insert a hold action. Slots after the action will only be executed if the button is held past the interval specified. Chose a profile to load when this slot is activated. Mouse mod action will modify all mouse speed settings by a specified percentage while the action is being processed. This can be useful for slowing down the mouse while sniping. Specify the time that keys past this slot should be held down. Insert a release action. Slots after the action will only be executed after a button release if the button was held past the interval specified. Change to selected set once slot is activated. Full string will be typed when a slot is activated. Execute program when slot is activated. Choose Profile Config Files (*.amgp *.xml) AdvanceStickAssignmentDialog Stick/Pad Assignment Assignement du Stick/Pad Sticks Sticks DPads DPads %1 (Joystick %2) %1 (Manette %2) Stick 1 Stick 1 Enabled Activé Assign Assigner X Axis: Axe X : Y Axis: Axe Y : Stick 2 Stick 2 Number of Physical DPads: %1 Numéro du DPads Physique : %1 Virtual DPad 1 DPad Virtuel 1 Up: Haut : Down: Bas : Note: This window is meant for backwards compatibility with profiles made before antimicro 2.0. Since version 2.0, use of the Game Controller Mapping window is preferred. Left: Gauche : Right: Droite : Axis %1 Axe %1 Axis %1 - Axe %1 - Axis %1 + Axe %1 + Button %1 Bouton %1 Move stick 1 along the X axis Déplacer le stick 1 selon l'axe X Move stick 1 along the Y axis Déplacer le stick 1 selon l'axe Y Move stick 2 along the X axis Déplacer le stick 2 selon l'axe X Move stick 2 along the Y axis Déplacer le stick 1 selon l'axe Y Press a button or move an axis Presser un bouton ou bouger un axe AxisEditDialog Axis Axe Mouse (Horizontal) Souris (Horizontal) Mouse (Inverted Horizontal) Souris (Horizontal Inversé) Mouse (Vertical) Souris (Vertical) Mouse (Inverted Vertical) Souris (Vertical Inversé) Arrows: Up | Down Flèches : Haut | Bas Arrows: Left | Right Flèches : Gauche | Droite Keys: W | S Touches : W | S Keys: A | D Touches : A | D NumPad: KP_8 | KP_2 Pavé Numérique : KP_8 | KP_2 NumPad: KP_4 | KP_6 Pavé Numérique : KP_4 | KP_6 None Aucun Set the value to use as the limit for an axis. Useful for a worn out analog stick. Negative Half Throttle Demie accélération négative Positive Half Throttle Demie accélération positive Name: Nom : Specify the name of an axis. Indiquer le nom d'un axe. Mouse Settings Configurations de la Souris Set the value of the dead zone for an axis. Régler la valeur de la zone morte pour un axe. Presets: Pré-réglages : Dead Zone: Zone morte : Max Zone: Zone maximale : [NO KEY] [AUCUNE TOUCHE] Throttle setting that determines the behavior of how to interpret an axis hold or release. Configure l’accélération qui détermine le comportement de maintien ou de relâchement d'un axe. Negative Throttle Accélération négative Normal Normal Positive Throttle Accélération positive Current Value: Valeur actuelle : Set Configuration Set %1 Left Mouse Button Right Mouse Button ButtonEditDialog Dialog Dialogue To make a new assignment, press any keyboard key or click a button in the Keyboard or Mouse tab Pour assigner une touche à ce bouton, presser celle-ci ou cliquer sur son équivalent graphique dans les onglets clavier et souris Placeholder Espace réservé Toggle Pression continue Enables a key press or release to only occur when a controller button is pressed. Permet d'appuyer ou de relâcher une touche uniquement lorsqu'un bouton est pressé. Enables rapid key presses and releases. Turbo controller. Permet d'appuyer et de relâcher très rapidement une touche en maintenant pressé un bouton. Contrôle du Turbo. Turbo Turbo Current: Actuellement : Slots Emplacements Na&me: Specify the name of a button. Indiquer le nom d'un bouton. Action: Action : Specify the action that will be performed in game while this button is being used. Indiquer l'action qui sera exécutée pendnt le jeu lorsque que ce bouton est utilisé. Advanced Avancé Set Configuration Set %1 CapturedWindowInfoDialog Captured Window Properties Information About Window Class: TextLabel Title: Path: Match By Properties Class Title Path Full Path File Name CommandLineUtility Profile location %1 is not an XML file. Le fichier profile %1 n'est pas un fichier XML. Profile location %1 does not exist. Le fichier profile %1 n'existe pas. An invalid set number '%1' was specified. Controller identifier '%s'' is not a valid value. No display string was specified. Controller identifier is not a valid value. L'identifiant du contrôleur n'est pas une valeur valide. No set number was specified. No controller was specified. An invalid event generator was specified. No event generator string was specified. Qt style flag was detected but no style was specified. No log level specified. antimicro version Usage: antimicro [options...] [profile] Options Options Print help text. Affiche le texte d'aide. Print version information. Affiche des informations sur la version. Launch program in system tray only. Lance le logiciel directement dans la zone de notification. Launch program with the tray menu disabled. Lance le logiciel avec le menu de la zone de notification désactivé. Launch program without the main window displayed. Lance le logiciel sans afficher la fenêtre principale. Launch program with the configuration file selected as the default for selected controllers. Defaults to all controllers. Lance le programme avec le fichier de configuration séléctionné par défaut pour le contrôleur choisi. Par défaut, tous les contrôleurs. Apply configuration file to a specific controller. Value can be a controller index, name, or GUID. Appliquer le fichier de configuration à un contrôleur specifique. La valeur peut être un index, un nom ou le GUID d'un controleur. Unload currently enabled profile(s). Value can be a controller index, name, or GUID. Déchargé le(s) profil(s) actuellement activés. La valeur peut être un index, un nom ou le GUID d'un controleur. Start joysticks on a specific set. Value can be a controller index, name, or GUID. Advance profile loading set options. Launch program as a daemon. Enable logging. Use specified display for X11 calls. Useful for ssh. Choose between using XTest support and uinput support for event generation. Default: xtest. Choose between using SendInput and vmulti support for event generation. Default: sendinput. Print information about joysticks detected by SDL. Open game controller mapping window of selected controller. Value can be a controller index or GUID. DPadContextMenu Mouse (Normal) Souris (Normal) Mouse (Inverted Horizontal) Souris (Horizontal Inversé) Mouse (Inverted Vertical) Souris (Vertical Inversé) Mouse (Inverted Horizontal + Vertical) Souris (Vertical et Horizontal Inversés) Arrows Flèches Keys: W | A | S | D Touches :W | A | S | D NumPad None Standard Standard Eight Way Eight Way 4 Way Cardinal 4 Way Diagonal Mouse Settings Configurations de la Souris DPadEditDialog Dialog Dialogue Presets: Pré-réglages : Mouse (Normal) Souris (Normal) Mouse (Inverted Horizontal) Souris (Horizontal Inversé) Mouse (Inverted Vertical) Souris (Vertical Inversé) Mouse (Inverted Horizontal + Vertical) Souris (Vertical et Horizontal Inversés) Arrows Flèches Keys: W | A | S | D Touches :W | A | S | D NumPad Pavé Numérique None Aucun Dpad Mode: Mode Dpad : &Name: 4 Way Cardinal 4 Way Diagonal DPad Delay: Time lapsed before a direction change is taken into effect. s Specify the name of a dpad. Indiquer le nom d'un dpad. Mouse Settings Configurations de la Souris Standard Standard Standard: 8 region dpad with two direction buttons active when the dpad is in a diagonal region. Eight Way: 8 region dpad with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region dpad with regions corresponding to the cardinal directions of the dpad. Useful for menus. 4 Way Diagonal: 4 region dpad with each region corresponding to a diagonal zone. Eight Way Eight Way Set Configuration Set %1 EditAllDefaultAutoProfileDialog Default Profile Profile: Browse Open Config Charger un fichier de configuration Profile file path is invalid. ExtraProfileSettingsDialog Extra Profile Settings Key Press Time: 0.00 ms Profile Name: s GameController Game Controller GameControllerDPad DPad GameControllerMappingDialog Game Controller Mapping Cartographie de contrôleur de jeu <html><head/><body><p>antimicro makes use of the <a href="https://wiki.libsdl.org/CategoryGameController"><span style=" text-decoration: underline; color:#0057ae;">Game Controller API</span></a> provided by SDL 2 in order to abstract various gamepads to fit a unified standard. In order to make a button assignment, please highlight the mapping cell for the appropriate button row below. You can then press a button or move an axis on your gamepad and the cell will update with the physical button or axis that will be used.</p><p>antimicro will use the mapping that you specify to save a mapping string that will be loaded into SDL.</p></body></html> A B X Y Back Retour Start Guide Left Shoulder Latéral gauche Right Shoulder Latéral droit Left Stick Click Clic Stick Gauche Right Stick Click Clic Stick Droite Left Stick X Stick Gauche X Left Stick Y Stick Gauche Y Right Stick X Stick Droit X Right Stick Y Stick Droit Y Left Trigger Gachette gauche Right Trigger Gachette droite DPad Up DPad Haut DPad Left DPad Gauche DPad Down DPad Bas DPad Right DPad Droit Mapping Cartographie SDL 2 Game Controller Mapping String Last Axis Event: Current Axis Detection Dead Zone: 5000 5000 10000 10000 15000 15000 20000 20000 25000 25000 30000 30000 32000 32000 Game Controller Mapping (%1) (#%2) Discard Controller Mapping? Désactivé la cartographie de contrôleur de jeu ? Discard mapping for this controller? If discarded, the controller will be reverted to a joystick once you refresh all joysticks. Eliminer la cartographie pour ce contrôleur ? S'il est éliminé, le contrôleur redeviendra un joystick une fois tous les joysticks mis à jour. GameControllerSet Back Retour Guide Start LS Click RS Click L Shoulder R Shoulder L Trigger R Trigger GameControllerTrigger Trigger Gachette JoyAxis Axis Axe JoyAxisButton Negative Négatif Positive Positif Unknown Inconnu Button Bouton JoyAxisContextMenu Mouse (Horizontal) Souris (Horizontal) Mouse (Inverted Horizontal) Souris (Horizontal Inversé) Mouse (Vertical) Souris (Vertical) Mouse (Inverted Vertical) Souris (Vertical Inversé) Arrows: Up | Down Flèches : Haut | Bas Arrows: Left | Right Flèches : Gauche | Droite Keys: W | S Touches : W | S Keys: A | D Touches : A | D NumPad: KP_8 | KP_2 Pavé Numérique : KP_8 | KP_2 NumPad: KP_4 | KP_6 Pavé Numérique : KP_4 | KP_6 None Mouse Settings Configurations de la Souris Left Mouse Button Right Mouse Button JoyButton Processing turbo for #%1 - %2 Finishing turbo for button #%1 - %2 Processing press for button #%1 - %2 Processing release for button #%1 - %2 Distance change for button #%1 - %2 Button Bouton [NO KEY] [AUCUNE TOUCHE] [Set %1 1W] [Set %1 2W] [Set %1 WH] JoyButtonContextMenu Toggle Turbo Turbo Clear Set Select Disabled Désactivé Set %1 Set %1 1W Set %1 2W Set %1 WH JoyButtonSlot Mouse Souris Up Haut Down Bas Left Gauche Right Droite LB BG MB BC RB BD B4 B4 B5 B5 Pause Pause Hold Maintenir Cycle Cycle Distance Distance Release Relâchement Mouse Mod Mode de la Souris Press Time Delay Load %1 Set Change %1 [Text] %1 [Exec] %1 [NO KEY] [AUCUNE TOUCHE] JoyControlStick Stick JoyControlStickButton Up Haut Down Bas Left Gauche Right Droite Button Bouton JoyControlStickContextMenu Mouse (Normal) Souris (Normal) Mouse (Inverted Horizontal) Souris (Horizontal Inversé) Mouse (Inverted Vertical) Souris (Vertical Inversé) Mouse (Inverted Horizontal + Vertical) Souris (Vertical et Horizontal Inversés) Arrows Flèches Keys: W | A | S | D Touches :W | A | S | D NumPad None Standard Standard Eight Way Eight Way 4 Way Cardinal 4 Way Diagonal Mouse Settings Configurations de la Souris JoyControlStickEditDialog Dialog Dialogue X: X : 0 0 Y: Y : Distance: Distance : Presets: Pré-réglages : Mouse (Normal) Souris (Normal) Mouse (Inverted Horizontal) Souris (Horizontal Inversé) Mouse (Inverted Vertical) Souris (Vertical Inversé) Mouse (Inverted Horizontal + Vertical) Souris (Vertical et Horizontal Inversés) Arrows Flèches Keys: W | A | S | D Touches :W | A | S | D NumPad NumPad None Aucub Stick Mode: Mode du Stick : Standard: 8 region stick with two direction buttons active when the stick is in a diagonal region. Eight Way: 8 region stick with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region stick with regions corresponding to the cardinal directions of the stick. Useful for menus. 4 Way Diagonal: 4 region stick with each region corresponding to a diagonal zone of the stick. 4 Way Cardinal 4 Way Diagonal Dead zone value to use for an analog stick. Value when an analog stick is considered moved 100%. The area (in degrees) that each diagonal region occupies. Square Stick: Percentage to modify a square stick coordinates to confine values to a circle % % Stick Delay: Time lapsed before a direction change is taken into effect. s Modifier: Edit button that is active while the stick is active. This button is useful for assigning zones with modifier keys that can be used to assign walk/run functionality to an analog stick. PushButton Name: Nom : Specify the name of an analog stick. Indiquer le nom d'un stick analogue. Mouse Settings Configurations de la Souris Standard Standard Bearing: % Safe Zone: Eight Way Eight Way Dead Zone: Zone morte : Max Zone: Zone maximale : Diagonal Range: Valleur de diagonale : Set Configuration Set %1 JoyControlStickModifierButton Modifier JoyDPad DPad JoyDPadButton Up Haut Down Bas Left Gauche Right Droite Button Bouton JoyTabWidget <New> <Nouveau> Remove Supprimer Remove configuration from recent list. Supprimer la configuration depuis la liste des recents. Load Charger Load configuration file. Charger un fichier de configuration. Save Enregistrer Save changes to configuration file. Enregistrer les modifications dans le fichier de configuration. Save As Enregistrer Sous Save changes to a new configuration file. Enregistrer les modifications dans un nouveau fichier de configuration. Sets Copy from Set Settings Set 1 Set 2 Set 3 Set 4 Set 5 Set 6 Set 7 Set 8 Stick/Pad Assign Assignement du Stick/Pad Controller Mapping Quick Set Configuration Rapide Names Noms Toggle button name displaying. Alterner nom du bouton d'affichage. Pref Change global profile settings. Reset Réinitialiser Revert changes to the configuration. Reload configuration file. Annuler les changements de configuration. Recharger le fichier de configuration. Open Config Charger un fichier de configuration Config Files (*.amgp *.xml) Config File (*.%1.amgp) Save Profile Changes? Changes to the new profile have not been saved. Would you like to save or discard the current profile? Changes to the profile "%1" have not been saved. Would you like to save or discard changes to the current profile? Sticks Sticks DPads DPads No buttons have been assigned. Please use Quick Set to assign keys to buttons or disable hiding empty buttons. Set %1: %2 Set %1 Copy Set Assignments Are you sure you want to copy the assignments and device properties from %1? Save Config Enregistrer le fichier de configuration Set Configuration Joystick Joystick Manette JoystickStatusWindow Properties Propriétés Details Détails Name: Nom : %1 %1 Number: Nombre : Axes: Axes : Buttons: Boutons : Hats: Hats : GUID: GUID : Game Controller: Axes Axes Buttons Boutons Hats Hats %1 (#%2) Properties %1 (#%2) Propriétés Axis %1 Axe %1 Hat %1 Hat %1 No Yes MainSettingsDialog Edit Settings Modifier les paramètres General Controller Mappings Cartographie de contrôleur Language Auto Profile Mouse Souris <html><head/><body><p>Specify the default directory that the program should use in file dialogs when loading a profile or saving a new profile.</p></body></html> Recent Profile Count: <html><head/><body><p>Number of profiles that can be placed in recent profile list. 0 will result in the program not enforcing a limit on the number of profiles displayed.</p></body></html> Gamepad Poll Rate: Change the poll rate that the program uses to discover new events from gamepads. Defaults to 10 ms. Reducing the poll rate value could cause the application to use more CPU power so please test the setting that you use before using antimicro unattended. Hide main window when the main window close button is clicked instead of quitting the program. Close To Tray Have Windows start antimicro at system startup. Launch At Windows Startup Display recent profiles for all controllers as a single list in the tray menu. Defaults to using sub-menus. Single Profile List in Tray Have the program minimize to the taskbar. By default, the program minimizes to the system tray if available. Minimize to Taskbar This option will cause the program to hide all buttons that have no slots assigned to them. The Quick Set dialog window will have to be used to bring up the edit dialog for gamepad buttons. Hide Empty Buttons When the program is launched, open the last known profile that was opened during the previous session. Auto Load Last Opened Profile Only show the system tray icon when the program first launches. Launch in Tray Associate .amgp files with antimicro in Windows Explorer. Associate Profiles Key Repeat Active keys will be repeatedly pressed when this option is enabled. Enable Specifies how much time should elapse before key repeating begins. Specifies how many times key presses will be performed per seconds. <html><head/><body><p>antimicro has been translated into many different languages by contributors. By default, the program will choose an appropriate translation based on your system's locale setting. However, you can make antimicro load a different translation depending on the language that you choose from the list below.</p></body></html> French Italian Japanese Russian Serbian Simplified Chinese Ukrainian Class Title Program Disable the "Enhanced Pointer Precision" Windows setting while antimicro is running. Disabling "Enhanced Pointer Precision" will allow mouse movement within antimicro to be more precise. Disable Enhance Pointer Precision Smoothing Histor&y Size: Weight &Modifier: Refresh Rate: The refresh rate is the amount of time that will elapse in between mouse events. Please be cautious when editing this setting as it will cause the program to use more CPU power. Setting this value too low can cause system instability. Please test the setting before using it unattended. Spring Ressort Screen: Utilize the specified screen for spring mode. On Linux, the default is to use the primary screen. On Windows, the default is to use all available screens. Accel Numerator: 0 0 Accel Denominator: Accel Threshold: If the acceleration values for the virtual mouse have been changed by a different process, particularly when quitting an older game, then you might want to reset the acceleration values used by the virtual mouse. Reset Acceleration Delay: Intervalle : Profi&le Directory: ms Rate: Taux : times/s Below is a list of the custom mappings that have been saved. You can use the following table to delete mappings or have mappings temporarily disabled. You can also disable mappings that are included with SDL; just insert a new row with the appropriate joystick GUID and check disable. Settings will not take affect until you either refresh all joysticks or unplug that particular joystick. Voici une liste des cartographies personnalisées qui ont été enregistrées. Utiliser le tableau suivant pour supprimer les cartographies ou désactiver temporairement une cartographie. Il est également possible de désactiver les cartographies qui sont inclus avec SDL, il suffit d'insérer une nouvelle ligne avec le GUID du manette approprié et cocher la case désactiver. Les paramètres ne prennent effet que lors de la prochaine réactualisation des joysticks ou en débranchant la manette spécifique. GUID Mapping String Chaîne de cartographie Disable? Désactiver ? Delete Supprimer Insert Insérer Default Brazilian Portuguese English German Active Devices: All Device Profile Default? Add Edit Also, Windows users who want to use a low value should also check the "Disable Enhance Pointer Precision" checkbox if you haven't disabled the option in Windows. Select Default Profile Directory Are you sure you want to delete the profile? MainWindow No Joysticks have been found. Please plug in a joystick and then choose the "Update Joysticks" option in the main menu Aucune manette n'a été détéctée. Merci de brancher une manette et de choisir l'option "Mettre à jour les manettes" du menu principal &App Stick/Pad Assign Assignement du Stick/Pad &Options &Options antimicro If events are not seen by a game, please click here to run this application as the Adminstrator. &Help &Aide &Quit &Quitter Ctrl+Q Ctrl+Q &Update Joysticks &Mettre à jour les manettes Ctrl+U Ctrl+U &Hide &Masquer Ctrl+H Ctrl+H &About &À propos Ctrl+A Ctrl+A About Qt À propos de Qt Properties Propriétés Key Checker Vérificateur de clé Home Page Page d'accueil GitHub Page Page GitHub Game Controller Mapping Cartographie de contrôleur de jeu Settings Wiki Could not find a proper controller identifier. Exiting. (%1) Open File Ouvrir fichier &Restore &Restaurer Run as Administrator? Are you sure that you want to run this program as Adminstrator? Some games run as Administrator which will cause events generated by antimicro to not be used by those games unless antimicro is also run as the Adminstrator. This is due to permission problems caused by User Account Control (UAC) options in Windows Vista and later. Failed to elevate program Failed to restart this program as the Administrator Could not find controller. Exiting. MouseAxisSettingsDialog Mouse Settings - Configurations de la Souris - Set %1 MouseButtonSettingsDialog Mouse Settings - Configurations de la Souris - Set %1 MouseControlStickSettingsDialog Mouse Settings Configurations de la Souris Set %1 MouseDPadSettingsDialog Mouse Settings Configurations de la Souris Set %1 MouseSettingsDialog Mouse Settings Configurations de la Souris Mouse Mode: Mode de la Souris : Cursor mode is used to move the mouse cursor around the screen relative to its current position depending on how much you move an axis or if a button is pressed. Spring mode is used to move the mouse cursor from the center of the screen depending on how much you move an axis. The mouse cursor will be returned to the center of the screen when the axis is moved back to the dead zone. Le mode "curseur" est utilisé pour déplacer le curseur de la souris autour de l'écran par rapport à sa position actuelle en fonction de la pression d'un axe ou d'un bouton. Le mode "ressort" est utilisé pour déplacer la souris depuis le centre de l'écran en fonction de la pression d'un axe. Le curseur de la souris retourne au centre de l'écran quand l'axe est déplacé vers la zone morte. Cursor Curseur Spring Ressort Acceleration: Accélération : Enhanced Precision Linear Linéair Quadratic Quadratique Cubic Cubique Quadratic Extreme Quadratique Extreme Power Function Fonction Énergie Easing Quadratic Easing Cubic Mouse Speed Settings Configurations de la Vitesse de la Souris Enable to change the horizontal and vertical speed boxes at the same time. Activer la modification simultanée des boîtes de vitesse horizontale et verticale. Change Together Modifier en même temps Options for adding more acceleration to the mouse movement beyond what the acceleration curve would produce. Acceleration is added based on how quickly an axis is moved in one gamepad poll. This is meant to help work around some of the issues of the very limited input range available using typical gamepad analog sticks. Delta Acceleration &Multiplier: Mi&n Threshold: Horizontal Speed: Vitesse horizontale : 1 = 20 pps 1 = 20 pps Vertical Speed: Vitesse verticale : Wheel Hori. Speed: Molette Hori. Vitesse : Set the speed used for horizontal mouse wheel movement according to number of simulated notches per second. Set the speed used for vertical mouse wheel movement according to number of simulated notches per second. Sensitivit&y: For Power Function acceleration curve. Specifies the factor to use for curve sensitivity. When the value is above 1.0, the mouse movement will be accelerated faster at the low end of an axis. Easing Duration: s Highest value to accelerate mouse movement by x Start %: Acceleration begins at this percentage of the base multiplier Minimum amount of axis travel required for acceleration to begin Max Threshold: Maximum axis travel before acceleration has reached the multiplier value E&xtra Duration: Curve: Ease Out Sine Ease Out Quad Ease Out Cubic Release Radius: Specifies that the spring area will be relative to the mouse position set by a non-relative spring. Relative Mouse Status X: X : 0 (0 pps) Y: Y : 1 = 1 notch(es)/s 1 = 1 cran(s)/s Enhanced: Three tier curve that makes the mouse move slow on the low end of an axis and fast on the high end. Linear: Mouse moves proportionally to axis. Quadratic: Mouse accelerates slowly on low end. Cubic: Mouse accelerates slower than Quadratic. Quadratic Extreme: Raises mouse speed 1.5 times once 95% axis travel has been reached. Power Function: Allows for a more custom curve option. Easing Quadratic: Axis high end is gradually accelerated over a period of time using a Quadratic curve. Easing Cubic: Axis high end is gradually accelerated over a period of time using a Cubic curve. Hori&zontal Speed: &Vertical Speed: Wheel Vert. Speed: Molette Vert. Vitesse : Sensitivity: Sensibilité : Specifies the amount of time (in seconds) that will be required before the mouse is fully accelerated after reaching the high end of an axis. % % Extend the time that extra acceleration is applied. Axis travel will be taken into account. A slower flick will decrease the actual time that extra acceleration will be applied. Spring Settings Configuration du Ressort Spring Width: Largeur du Ressort : Changes the width of the region that the cursor can move in spring mode. 0 will use the entire width of your screen. Modifie la largeur de la région dans laquelle le curseur peut se déplacer en mode "ressort". 0 utilise toute la largeur de l'écran. Spring Height: Hauteur du Ressort : Changes the height of the region that the cursor can move in spring mode. 0 will use the entire height of your screen. Modifie la hauteur de la région dans laquelle le curseur peut se déplacer en mode "ressort". 0 utilise toute la hauteur de l'écran. %n notch(es)/s %n cran/s %n crans/s QKeyDisplayDialog Key Checker Vérificateur de touche <html><head/><body><p>Press a key on your keyboard to see how the key is detected by this application. The window will show the system native key value, the original value given by Qt (if applicable), and the custom value used by antimicro.</p><p>The antimicro key value and the Qt key value will usually be the same. antimicro tries to use the key values defined in Qt when possible. Check the page <a href="https://doc.qt.io/qt-4.8/qt.html#Key-enum"><span style=" text-decoration: underline; color:#0057ae;">https://doc.qt.io/qt-4.8/qt.html#Key-enum</span></a> for a list of values defined by Qt. If you discover that a key is not natively supported by this program, please report the problem to antimicro's <a href="https://github.com/AntiMicro/antimicro"><span style=" text-decoration: underline; color:#0057ae;">GitHub page</span></a> so that the program can be edited to support it directly. As it is, a custom prefix is added to unknown values so they can still be used; the main problem is that the profile will no longer be portable.</p></body></html> Event Handler: Native Key Value: Valeur native de la touche : 0x00000000 Qt Key Value: Valeur de la touche Qt : antimicro Key Value: QObject Super Super Menu Mute Vol+ Vol- Play/Pause Play Pause Pause Prev Next Suivant Mail Home Début Media Search Daemon launched Failed to launch daemon Launching daemon Display string "%1" is not valid. Failed to set a signature id for the daemon Failed to change working directory to / Quitting Program # of joysticks found: %1 List Joysticks: --------------- Joystick %1: Index: %1 GUID: %1 Name: %1 Yes No Game Controller: %1 # of Axes: %1 # of Buttons: %1 # of Hats: %1 Attempting to use fallback option %1 for event generation. Failed to open event generator. Exiting. Using %1 as the event generator. Could not raise process priority. QuickSetDialog Quick Set Configuration Rapide <html><head/><body><p>Please press a button or move an axis on %1 (<span style=" font-weight:600;">%2</span>).<br/>A dialog window will then appear which will<br/>allow you to make an assignment.</p></body></html> <html><head/><body><p>Merci de presser un bouton ou de bouger un axe de %1 (<span style=" font-weight:600;">%2</span>).<br/>Une fenêtre de dialogue va apparaître<br/>pour permettre de faire une assignation.</p></body></html> Quick Set %1 Configuration Rapide %1 SetAxisThrottleDialog Throttle Change Modifier l'accélération The throttle setting for Axis %1 has been changed. Would you like to distribute this throttle change to all sets? axes ou axe dans ce cas ? La configuration de l'accélération de l'axe %1 a été modifié. Faut-il appliquer cette valeur d'accélération à tous les réglages ? SetJoystick Set %1: %2 Set %1 SetNamesDialog Set Name Settings Set 1 Set 2 Set 3 Set 4 Set 5 Set 6 Set 7 Set 8 Name SimpleKeyGrabberButton Mouse Souris SpringModeRegionPreview Spring Mode Preview Aperçu du mode ressort UInputEventHandler Could not find a valid uinput device file. Please check that you have the uinput module loaded. lsmod | grep uinput Could not open uinput device file Please check that you have permission to write to the device Using uinput device file %1 UInputHelper a q b c d e f g h i j k l m , n o p q a r s t u v w z x y z w Esc F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 ` 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 0 0 - = BackSpace Retour Arrière Tab Tab [ ] \ CapsLock ; ' Enter Shift_L Maj_G , . / Ctrl_L Super_L Super_L Alt_L Alt_L Space Espace Alt_R Alt_R Menu Menu Ctrl_R Shift_R Maj_D Up Haut Left Gauche Down Bas Right Droite PrtSc Ins Del Home Début End End PgUp PgDn NumLock * + KP_Enter KP_Entrée KP_1 KP_2 KP_3 KP_4 KP_5 KP_6 KP_7 KP_8 KP_9 KP_0 SCLK Arrêt Defil Pause Pause Super_R Mute VolDn VolUp Play Stop Prev Next Suivant [NO KEY] [AUCUNE TOUCHE] UnixWindowInfoDialog Captured Window Properties Information About Window Class: TextLabel Title: Path: Match By Properties Class Title Path VDPad VDPad VirtualKeyPushButton Space Espace Tab Tab Shift (L) Maj (G) Shift (R) Maj (D) Ctrl (L) Ctrl (G) Ctrl (R) Ctrl (D) Alt (L) Alt (G) Alt (R) Alt (D) ` ~ - = [ ] \ Caps Verr Maj ; ' , . / ESC ECHAP PRTSC Impr Ecran SCLK Arrêt Defil INS INSER PGUP PGUP DEL SUPPR PGDN PGDN 1 2 3 4 5 6 7 8 9 0 NUM LK VERR NUM * + E N T E R E N T R É E < : Super (L) Super (G) Menu Up Haut Down Bas Left Gauche Right Droite VirtualKeyboardMouseWidget Keyboard Clavier Mouse Souris Mouse Settings Configurations de la Souris Left Mouse Gauche Up Mouse Haut Left Button Mouse Middle Button Mouse Right Button Mouse Wheel Up Mouse Molette bas Wheel Left Mouse Molette gauche Wheel Right Mouse Molette droite Wheel Down Mouse Molette bas Down Mouse Bas Right Mouse Droite Button 4 Mouse Bouton 4 Mouse 8 Mouse Souris 8 Button 5 Mouse Bouton 5 Mouse 9 Mouse Souris 9 NONE AUCUNE Applications Browser Back Browser Favorites Browser Forward Browser Home Browser Refresh Browser Search Browser Stop Calc Email Media Media Next Media Play Media Previous Media Stop Search Volume Down Volume Mute Volume Up VirtualMousePushButton INVALID INVALIDE WinAppProfileTimerDialog Capture Application After pressing the "Capture Application" button, please select the application window that you want to have a profile associated with. The active application will be captured after the selected number of seconds. Timer: Seconds Cancel WinExtras [NO KEY] [AUCUNE TOUCHE] AntiMicro Profile X11Extras ESC ECHAP Tab Tab Space Espace DEL SUPPR Return KP_Enter KP_Entrée Backspace Retour arrière xinput extension was not found. No mouse acceleration changes will occur. xinput version must be at least 2.0. No mouse acceleration changes will occur. Virtual pointer found with id=%1. PtrFeedbackClass was not found for virtual pointer.No change to mouse acceleration will occur for device with id=%1 Changing mouse acceleration for device with id=%1 XMLConfigReader Could not write updated profile XML to file %1. Impossible de mettre à jour le profil XML du fichier %1. XMLConfigWriter Could not write to profile at %1. Impossible d'écrire le profil %1. antimicro-2.23/share/antimicro/translations/antimicro_it.ts000066400000000000000000011615341300750276700243100ustar00rootroot00000000000000 AboutDialog About A proposito Version Versione <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Originally developed by Travis Nickles &lt;nickles.travis@gmail.com&gt;, now maintained by the AntiMicro group at https://github.com/AntiMicro.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Contributors:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;"><br /></span>Zerro Alvein</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">aybe</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jeff Backus &lt;jeff.backus@gmail.com&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Arthur Moore<br />Anton Tornqvist &lt;antont@inbox.lv&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7185</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">DarkStarSword</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">est31</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ProfessorKaos64</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">qwerty12</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA0</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Translators:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VaGNaroK &lt;vagnarokalkimist@gmail.com&gt; - Brazilian Portuguese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx - Chinese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Belleguic Terence &lt;hizo@free.fr&gt; - French</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Leonard Koenig &lt;leonard.r.koenig@googlemail.com&gt; - German</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phob - German</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">tou omiya - Japanese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Dmitriy Koshel &lt;form.eater@gmail.com&gt; - Russian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jay Alexander Fleming &lt;tito.nehru.naser@gmail.com&gt; - Serbian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">burunduk - Ukrainian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Flavio HR &lt;flavio.hrx@gmail.com&gt; - Spanish</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA - wazaaaaa00&lt;@&gt;gmail&lt;.&gt;com - Italian</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> Info Info Changelog Changelog Since December 30, 2012, I have been working on antimicro in my spare time. What originally started as a fork of QJoyPad and a way to learn proper event-driven programming has turned into something much bigger than I originally intended. Although I have spent a lot of time learning new techniques, finding out more about the domain of KB+M emulation, and spending Friday nights bashing my head against my keyboard, it has been a fun and enriching experience overall. The need for this program came from me using similar programs on Windows to play several games that did not provide native controller support. Although some alternatives existed on Linux, there wasn't really anything that I felt was good enough in terms of functionality or in-game controls in order to really enjoy games that I wanted to play with using KB+M emulation. QJoyPad was the main program that I had used in the past although it had aged a lot and it didn't provide some basic functionality that I thought was essential. The project was dead as it had not been updated in several years so I decided to make my own. Since then, I have tried to find out what the other programs do right and then improve upon it. I have also discovered some neat tricks along the way and I have learned more about how native gamepad controls are implemented in some games than I ever really wanted to know. Although there are definitely areas where this program could improve, I find that this program offers the best in-game control experience for playing older, and some newer, games that do not provide native controller support. Development of this program is not as high of a priority for me anymore. This is mainly due to the fact that the Steam Controller works pretty well for the task of playing PC games compared to using an Xbox 360 controller. However, it does look like there is still a reason for this program to exist for a while. Copyright: 2013 - 2016 Copyright: 2013 - 2016 {2013 ?} {2016?} Copyright: 2013 - 2016 Copyright: 2013 - 2016 Credits Ringraziamenti antimicro antimicro <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">GNU GENERAL PUBLIC LICENSE</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Version 3, 29 June 2007</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Preamble</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Developers that use the GNU GPL protect your rights with two steps:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">(1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The precise terms and conditions for copying, distribution and modification follow.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">TERMS AND CONDITIONS</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">0. Definitions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;This License&quot; refers to version 3 of the GNU General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Copyright&quot; also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;The Program&quot; refers to any copyrightable work licensed under this License. Each licensee is addressed as &quot;you&quot;. &quot;Licensees&quot; and &quot;recipients&quot; may be individuals or organizations.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;modify&quot; a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a &quot;modified version&quot; of the earlier work or a work &quot;based on&quot; the earlier work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;covered work&quot; means either the unmodified Program or a work based on the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;propagate&quot; a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;convey&quot; a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An interactive user interface displays &quot;Appropriate Legal Notices&quot; to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">1. Source Code.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;source code&quot; for a work means the preferred form of the work for making modifications to it. &quot;Object code&quot; means any non-source form of a work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;Standard Interface&quot; means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;System Libraries&quot; of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A &quot;Major Component&quot;, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;Corresponding Source&quot; for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source for a work in source code form is that same work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">2. Basic Permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">3. Protecting Users' Legal Rights From Anti-Circumvention Law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">4. Conveying Verbatim Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">5. Conveying Modified Source Versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) The work must carry prominent notices stating that you modified it, and giving a relevant date.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to &quot;keep intact all notices&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an &quot;aggregate&quot; if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">6. Conveying Non-Source Forms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;User Product&quot; is either (1) a &quot;consumer product&quot;, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, &quot;normally used&quot; refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Installation Information&quot; for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">7. Additional Terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Additional permissions&quot; are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Limiting the use for publicity purposes of names of licensors or authors of the material; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All other non-permissive additional terms are considered &quot;further restrictions&quot; within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">8. Termination.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">9. Acceptance Not Required for Having Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">10. Automatic Licensing of Downstream Recipients.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An &quot;entity transaction&quot; is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">11. Patents.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;contributor&quot; is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's &quot;contributor version&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A contributor's &quot;essential patent claims&quot; are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, &quot;control&quot; includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">In the following three paragraphs, a &quot;patent license&quot; is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To &quot;grant&quot; such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. &quot;Knowingly relying&quot; means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A patent license is &quot;discriminatory&quot; if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">12. No Surrender of Others' Freedom.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">13. Use with the GNU Affero General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">14. Revised Versions of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License &quot;or any later version&quot; applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">15. Disclaimer of Warranty.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM &quot;AS IS&quot; WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">16. Limitation of Liability.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">17. Interpretation of Sections 15 and 16.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.</span></p></body></html> About Development Informazioni sviluppo License Licenza Program Version %1 Versione programma %1 Program Compiled on %1 at %2 Programma compilato il %1 alle %2 Built Against SDL %1 Costruito con SDL %1 Running With SDL %1 Eseguito con SDL %1 Using Qt %1 Utilizzando Qt %1 Using Event Handler: %1 Gestore di eventi in uso: %1 AddEditAutoProfileDialog Auto Profile Dialog Finestra di auto-profilo Profile: Profilo: Browse Sfoglia Window: Finestra: Select Window. Click on the appropriate application window and the application file path will be populated in the form. Seleziona la finestra. Clicca la finestra giusta e il percorso al file dell'applicazione riempirà il campo. Detect Window Properties Rileva proprietà finestra Class: Classe: Title: Titolo: Application: Applicazione: Select Seleziona Devices: Dispositivi: Select this profile to be the default loaded for the specified device. The selection will be used instead of the all default profile option. Seleziona questo profilo per renderlo il predefinito per il dispositivo specificato. La selezione verrà usata al posto di qualsiasi altro profilo predefinito. Set as Default for Controller Imposta come controller predefinito A different profile is already selected as the default for this device. È già stato selezionato un altro profilo come predefinito per questo dispositivo. Current (%1) Corrente (%1) Open Config Apri configurazione Select Program Seleziona programma Programs (*.exe) Programmi (*.exe) Please use the main default profile selection. Per favore usa la selezione profilo predefinita principale. Please select a window by using the mouse. Press Escape if you want to cancel. Per favore seleziona una finestra utilizzando il mouse. Premi Esc se vuoi annullare. Capture Application Window Cattura finestra applicazione Could not obtain information for the selected window. Impossibile ottenere le informazioni della finestra selezionata. Application Capture Failed Cattura applicazione fallita Profile file path is invalid. Percorso del file di profilo invalida. No window matching property was specified. Non è stata specificata alcuna proprietà per identificare la finestra. Program path is invalid or not executable. Il programma è invalido o non è un eseguibile. File is not an .exe file. Il file non è un .exe. No window matching property was selected. Non è stata selezionata alcuna proprietà per identificare la finestra. AdvanceButtonDialog Advanced Avanzate Assignments Assegnazioni Toggle Cambio stato Turbo Turbo Set Selector Selezionatore set Blank or KB/M Vuoto o Tastiera/Mouse Hold Tieni Pause Pausa Cycle Ciclo Distance Distanza Insert Inserisci Delete Cancella Clear All Cancella tutto Time: Tempo: 0.01s 0.01s 0s 0s Insert a pause that occurs in between key presses. Inserisci una pausa tra un tasto e l'altro. Release Rilascia Insert a new blank slot. Inserisci un nuovo slot vuoto. Delete a slot. Cancella uno slot. Clear all currently assigned slots. Cancella tutti gli slot assegnati. Specify the duration of an inserted Pause or Hold slot. Specifica la durata di una Pausa inserita o di un Tieni. 0m 0m &Mouse Speed Mod: Specify the range past an axis dead zone in which a sequence of actions will execute. Specifica l'intervallo dopo la zona morta di un'asse in cui una sequenza di azioni verrà eseguita. Distance: Distanza: % % Mouse Mod Modifica mouse Press Time Tempo di pressione Delay Ritardo Execute Esegui Load Carica Set Change Cambio di set Text Entry Inserimento testo Placeholder Segnaposto 0 0 Mouse Speed Mod: Modifica velocità mouse: Set the percentage that mouse speeds will be modified by. Imposta la percentuale con cui le velocità del mouse verranno modificate. Auto Reset Cycle After Auto-resetta ciclo dopo seconds secondi Executable: ... ... Arguments: Enabled Attivato Mode: Modalità: <html><head/><body><p>Normal: Repeatedly press and release a button by the chosen rate.</p><p>Gradient: Modify the button press and button release delay based on how far an axis has been moved. The rate will remain the same.</p><p>Pulse: Modify how many times a button is pressed and released per second. The button delay will remain the same.</p></body></html> <html><head/><body><p>Normale: preme e rilascia ripetutamente un tasto a seconda del rapporto scelto.</p><p>Gradiente: modifica il tasto premuto e il ritardo di un tasto rilasciato a seconda di quanto è stata mossa un'asse. Il rapporto rimarrà lo stesso.</p><p>Pulsa: modifica quante volte un tasto viene premuto e rilasciato al secondo. Il ritardo del tasto rimarrà lo stesso.</p></body></html> Normal Normale Gradient Gradiente Pulse Pulsa Delay: Ritardo: 0.10s 0.10s Rate: Rapporto: 10.0/s 10.0/s Disabled Disattivato Select Set 1 One Way Selezione set 1 a una direzione Select Set 1 Two Way Selezione set 1 a due direzioni Select Set 1 While Held Selezione set 1 finché premuto Select Set 2 One Way Selezione set 2 a una direzione Select Set 2 Two Way Selezione set 2 a due direzioni Select Set 2 While Held Selezione set 2 finché premuto Select Set 3 One Way Selezione set 3 a una direzione Select Set 3 Two Way Selezione set 3 a due direzioni Select Set 3 While Held Selezione set 3 finché premuto Select Set 4 One Way Selezione set 4 a una direzione Select Set 4 Two Way Selezione set 4 a due direzioni Select Set 4 While Held Selezione set 4 finché premuto Select Set 5 One Way Selezione set 5 a una direzione Select Set 5 Two Way Selezione set 5 a due direzioni Select Set 5 While Held Selezione set 5 finché premuto Select Set 6 One Way Selezione set 6 a una direzione Select Set 6 Two Way Selezione set 6 a due direzioni Select Set 6 While Held Selezione set 6 finché premuto Select Set 7 One Way Selezione set 7 a una direzione Select Set 7 Two Way Selezione set 7 a due direzioni Select Set 7 While Held Selezione set 7 finché premuto Select Set 8 One Way Selezione set 8 a una direzione Select Set 8 Two Way Selezione set 8 a due direzioni Select Set 8 While Held Selezione set 8 finché premuto sec. sec. /sec. /sec. Set %1 Set %1 Select Set %1 Seleziona set %1 One Way a una direzione Two Way a due direzioni While Held finché premuto Choose Executable Scegli eseguibile Slots past a Cycle action will be executed on the next button press. Multiple cycles can be added in order to create partitions in a sequence. Gli slot dopo un'azione Ciclo verranno eseguiti al prossimo tasto premuto. Cicli multipli possono essere aggiunti per creare partizioni in sequenza. Delays the time that the next slot is activated by the time specified. Slots activated before the delay will remain active after the delay time has passed. Ritarda il tempo dopo il quale il prossimo slot viene attivato per il tempo specificato. Gli slot attivati prima del ritardo rimarranno attivi finché il ritardo non trascorre. Distance action specifies that the slots afterwards will only be executed when an axis is moved a certain range past the designated dead zone. L'azione Distanza specifica che gli slot successivi verranno eseguiti solo quando un'asse si muove oltre un certo intervallo dopo la zona morta. Insert a hold action. Slots after the action will only be executed if the button is held past the interval specified. Inserisce un'azione Tieni. Gli slot dopo l'azione verranno eseguiti solo se il tasto viene tenuto premuto oltre all'intervallo specificato. Chose a profile to load when this slot is activated. Scegli un profilo da caricare quando questo slot viene attivato. Mouse mod action will modify all mouse speed settings by a specified percentage while the action is being processed. This can be useful for slowing down the mouse while sniping. L'azione Modifica mouse modificherà tutte le impostazioni della velocità mouse di una percentuale specifica mentre l'azione viene processata. Questo può tornare utile per rallentare il mouse usando un fucile da cecchino. Specify the time that keys past this slot should be held down. Specifica il tempo in cui i tasti dopo questo slot debbano restare premuti. Insert a release action. Slots after the action will only be executed after a button release if the button was held past the interval specified. Inserisce un'azione di rilascio. Gli slot dopo l'azione verranno eseguiti solo dopo il rilascio di un tasto se il tasto è stato premuto dopo l'intervallo specificato. Change to selected set once slot is activated. Cambia il set selezionato quando lo slot viene attivato. Full string will be typed when a slot is activated. Una stringa verrà digitata quando uno slot viene attivato. Execute program when slot is activated. Esegue un programma quando lo slot viene attivato. Choose Profile Scegli profilo Config Files (*.amgp *.xml) File di configurazione (*.amgp *.xml) AdvanceStickAssignmentDialog Stick/Pad Assignment Assegnazioni analogico/pad Sticks Analogici DPads DPads %1 (Joystick %2) %1 (Joystick %2) Stick 1 Analogico 1 Enabled Attivato Assign Assegna X Axis: Asse X: Y Axis: Asse Y: Stick 2 Analogico 2 Number of Physical DPads: %1 Numero di DPad fisici: %1 Virtual DPad 1 DPad virtuale 1 Up: Su: Down: Giù: Note: This window is meant for backwards compatibility with profiles made before antimicro 2.0. Since version 2.0, use of the Game Controller Mapping window is preferred. Nota: questa finestra è destinata alla retrocompatibilità coi profili creati prima di antimicro 2.0. Dalla versione 2.0, è preferibile l'uso della finestra Mappatura controller di gioco. Left: Sinistra: Right: Destra: Axis %1 Asse %1 Axis %1 - Asse %1 - Axis %1 + Asse %1 + Button %1 Tasto %1 Move stick 1 along the X axis Muovere analogico 1 lungo l'asse X Move stick 1 along the Y axis Muovere analogico 1 lungo l'asse Y Move stick 2 along the X axis Muovere analogico 2 lungo l'asse X Move stick 2 along the Y axis Muovere analogico 2 lungo l'asse Y Press a button or move an axis Premere un tasto o muovere un'asse AxisEditDialog Axis Asse Mouse (Horizontal) Mouse (orizzontale) Mouse (Inverted Horizontal) Mouse (orizzontale invertito) Mouse (Vertical) Mouse (verticale) Mouse (Inverted Vertical) Mouse (verticale invertito) Arrows: Up | Down Frecce: Su | Giù Arrows: Left | Right Frecce: Sinistra | Destra Keys: W | S Tasti: W | S Keys: A | D Tasti: A | D NumPad: KP_8 | KP_2 TastNum: TN_8 | TN_2 NumPad: KP_4 | KP_6 TastNum: TN_4 | TN_6 None Niente Set the value to use as the limit for an axis. Useful for a worn out analog stick. Imposta il valore da usare come limite per un'asse. Utile per un analogico consumato. Negative Half Throttle Acceleratore negativo a metà Positive Half Throttle Acceleratore positivo a metà Name: Nome: Specify the name of an axis. Specifica il nome di un'asse. Mouse Settings Impostazioni mouse Set the value of the dead zone for an axis. Imposta il valore della zona morta per un'asse. Presets: Preimpostazioni: Dead Zone: Zona morta: Max Zone: Zona massima: [NO KEY] [NO TASTO] Throttle setting that determines the behavior of how to interpret an axis hold or release. Impostazione dell'acceleratore che determina come interpretare il rilascio o la pressione di un'asse. Negative Throttle Acceleratore negativo Normal Normale Positive Throttle Acceleratore positivo Current Value: Valore corrente: Set Set Set %1 Set %1 Left Mouse Button Tasto sinistro del mouse Right Mouse Button Tasto destro del mouse ButtonEditDialog Dialog Finestra di dialogo To make a new assignment, press any keyboard key or click a button in the Keyboard or Mouse tab Per assegnare un nuovo tasto, premere qualunque tasto della tastiera o cliccare un pulsante nella sezione Tastiera o Mouse Placeholder Segnaposto Toggle Cambio stato Enables a key press or release to only occur when a controller button is pressed. Abilita la pressione o il rilascio di un tasto solo quando il tasto di un controller viene premuto. Enables rapid key presses and releases. Turbo controller. Abilita la pressione e il rilascio rapidi di un tasto. Controller turbo. Turbo Turbo Current: Corrente: Slots Slot Na&me: Nome: Specify the name of a button. Specifica il nome di un tasto. Action: Azione: Specify the action that will be performed in game while this button is being used. Specifica l'azione che verrà eseguita in gioco mentre questo tasto viene usato. Advanced Avanzate Set Set Set %1 Set %1 CapturedWindowInfoDialog Captured Window Properties Proprietà finestra catturata Information About Window Informazioni sulla finestra Class: Classe: TextLabel etichetta di testo Title: Titolo: Path: Percorso: Match By Properties Trova per proprietà Class Classe Title Titolo Path Percorso Full Path Percorso completo File Name Nome file CommandLineUtility Profile location %1 is not an XML file. Il profilo in %1 non è un file XML. Profile location %1 does not exist. Il profilo in %1 non esiste. An invalid set number '%1' was specified. È stato specificato un numero di set '%1' invalido. Controller identifier '%s'' is not a valid value. L'identificatore controller '%s'' non è un valore valido. No display string was specified. Non è stata specificata una stringa di visualizzazione. Controller identifier is not a valid value. L'identificatore controller non è un valore valido. No set number was specified. Non è stato specificato un numero di set. No controller was specified. Non è stato specificato un controller. An invalid event generator was specified. È stato specificato un generatore di eventi invalido. No event generator string was specified. Nessuna stringa di generatore eventi è stata specificata. Qt style flag was detected but no style was specified. È stato rilevato il flag stile Qt ma non è stato specificato alcuno stile. No log level specified. Nessun livello di log specificato. antimicro version versione antimicro Usage: antimicro [options...] [profile] Utilizzo: antimicro [options...] [profile] Options Opzioni Print help text. Stampa testo di aiuto. Print version information. Stampa informazioni versione. Launch program in system tray only. Esegui programma solo nella barra di sistema. Launch program with the tray menu disabled. Esegui programma con la barra di sistema disattivata. Launch program without the main window displayed. Esegui programma senza visualizzare la finestra principale. Launch program with the configuration file selected as the default for selected controllers. Defaults to all controllers. Esegui programma con il file di configurazione selezionato come predefinito per i controller selezionati. Diventa il valore predefinito di tutti i controller. Apply configuration file to a specific controller. Value can be a controller index, name, or GUID. Applica file di configurazione ad un controller specifico. Il valore può essere un indice controller, nome, o GUID. Unload currently enabled profile(s). Value can be a controller index, name, or GUID. Libera profilo/i attivati. Il valore può essere un indice controller, nome, o GUID. Start joysticks on a specific set. Value can be a controller index, name, or GUID. Esegui joystick su un set specifico. Il valore può essere un indice controller, nome, o GUID. Advance profile loading set options. Avanza caricamento opzioni set profilo. Launch program as a daemon. Esegui programma come demone. Enable logging. Abilita logging. Use specified display for X11 calls. Useful for ssh. Usa il display specificato per le chiamate X11. Utile per l'SSH. Choose between using XTest support and uinput support for event generation. Default: xtest. Scegli se usare il supporto XTest o uinput per la generazione di eventi. Predefinito: xtest. Choose between using SendInput and vmulti support for event generation. Default: sendinput. Scegli se usare il supporto SentInput o vmulti per la generazione di eventi. Predefinito: sendinput. Print information about joysticks detected by SDL. Stampa informazioni riguardo i joystick rilevati da SDL. Open game controller mapping window of selected controller. Value can be a controller index or GUID. Apri finestra Mappatura controller di gioco del controller scelto. Il valore può essere un indice controller o GUID. DPadContextMenu Mouse (Normal) Mouse (normale) Mouse (Inverted Horizontal) Mouse (orizzontale invertito) Mouse (Inverted Vertical) Mouse (verticale invertito) Mouse (Inverted Horizontal + Vertical) Mouse (orizzontale + verticale invertito) Arrows Frecce Keys: W | A | S | D Tasti: W | A | S | D NumPad TastNum None Niente Standard Standard Eight Way 8 direzioni 4 Way Cardinal 4 direzioni cardinali 4 Way Diagonal 4 direzioni diagonali Mouse Settings Impostazioni mouse DPadEditDialog Dialog Finestra di dialogo Presets: Preimpostazioni: Mouse (Normal) Mouse (normale) Mouse (Inverted Horizontal) Mouse (orizzontale invertito) Mouse (Inverted Vertical) Mouse (verticale invertito) Mouse (Inverted Horizontal + Vertical) Mouse (orizzontale + verticale invertito) Arrows Frecce Keys: W | A | S | D Tasti: W | A | S | D NumPad TastNum None Niente Dpad Mode: Modalità DPad: &Name: Nome: 4 Way Cardinal 4 direzioni cardinali 4 Way Diagonal 4 direzioni diagonali DPad Delay: Ritardo DPad: Time lapsed before a direction change is taken into effect. Tempo trascorso prima che il cambiamento di una direzione abbia effetto. s s Specify the name of a dpad. Specifica il nome di un DPad. Mouse Settings Impostazioni mouse Standard Standard Standard: 8 region dpad with two direction buttons active when the dpad is in a diagonal region. Eight Way: 8 region dpad with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region dpad with regions corresponding to the cardinal directions of the dpad. Useful for menus. 4 Way Diagonal: 4 region dpad with each region corresponding to a diagonal zone. Standard: DPad a 8 regioni con due tasti direzionali attivi quando il DPad è in una regione diagonale. 8 direzioni: DPad a 8 regioni con ogni direzione che ha un tasto dedicato. Solo un tasto alla volta viene premuto. Utile per i giochi come Rogue. 4 direzioni cardinali: DPad a 4 regioni con regioni corrispondenti alla direzione cardinale del DPad. Utile per i menu. 4 direzioni diagonali: DPad a 4 regioni con ogni regione corrispondente alla zona diagonale del DPad. Eight Way 8 direzioni Set Set Set %1 Set %1 EditAllDefaultAutoProfileDialog Default Profile Profilo predefinito Profile: Profilo: Browse Sfoglia Open Config Apri configurazione Profile file path is invalid. Il percorso del profilo è invalido. ExtraProfileSettingsDialog Extra Profile Settings Altre impostazioni profilo Key Press Time: Tempo pressione tasto: 0.00 ms 0.00 ms Profile Name: Nome profilo: s s GameController Game Controller Controller di gioco GameControllerDPad DPad DPad GameControllerMappingDialog Game Controller Mapping Mappatura controller di gioco <html><head/><body><p>antimicro makes use of the <a href="https://wiki.libsdl.org/CategoryGameController"><span style=" text-decoration: underline; color:#0057ae;">Game Controller API</span></a> provided by SDL 2 in order to abstract various gamepads to fit a unified standard. In order to make a button assignment, please highlight the mapping cell for the appropriate button row below. You can then press a button or move an axis on your gamepad and the cell will update with the physical button or axis that will be used.</p><p>antimicro will use the mapping that you specify to save a mapping string that will be loaded into SDL.</p></body></html> <html><head/><body><p>antimicro utilizza la <a href="https://wiki.libsdl.org/CategoryGameController"><span style=" text-decoration: underline; color:#0057ae;">Game Controller API</span></a> fornita da SDL 2 per astrarre vari gamepad e adattarli a un unico standard. Per assegnare un tasto, per favore evidenzia la cella di mappatura per il tasto della riga giusta qui sotto. Dopodiché puoi premere un tasto o muovere un'asse sul tuo gamepad e la cella si aggiornerà con il tasto fisico o l'asse che verrà usata.</p><p>antimicro userà la mappatura che hai specificato per salvare una stringa di mappatura che verrà caricata in SDL.</p></body></html> A A B B X X Y Y Back Back Start Start Guide Guide Left Shoulder Dorsale sinistro Right Shoulder Dorsale destro Left Stick Click Click analogico sinistro Right Stick Click Click analogico destro Left Stick X Analogico sinistro X Left Stick Y Analogico sinistro Y Right Stick X Analogico destro X Right Stick Y Analogico destro Y Left Trigger Grilletto sinistro Right Trigger Grilletto destro DPad Up DPad su DPad Left DPad sinistra DPad Down DPad giù DPad Right DPad destra Mapping Mappatura SDL 2 Game Controller Mapping String Stringa di mappatura Game controller SDL 2 Last Axis Event: Ultimo evento asse: Current Axis Detection Dead Zone: Rilevamento corrente della zona morta dell'asse: 5000 5000 10000 10000 15000 15000 20000 20000 25000 25000 30000 30000 32000 32000 Game Controller Mapping (%1) (#%2) Mappatura controller di gioco (%1) (#%2) Discard Controller Mapping? Scartare mappatura controller? Discard mapping for this controller? If discarded, the controller will be reverted to a joystick once you refresh all joysticks. Scartare mappatura di questo controller? Scartandola, il controller tornerà ad essere un joystick una volta aggiornati tutti i joystick. GameControllerSet Back Indietro Guide Guida Start Start LS Click Click analog SX RS Click Click analog DX L Shoulder Dorsale SX R Shoulder Dorsale DX L Trigger Grilletto SX R Trigger Grilletto DX GameControllerTrigger Trigger Grilletto JoyAxis Axis Asse JoyAxisButton Negative Negativo Positive Positivo Unknown Sconosciuto Button Tasto JoyAxisContextMenu Mouse (Horizontal) Mouse (orizzontale) Mouse (Inverted Horizontal) Mouse (orizzontale invertito) Mouse (Vertical) Mouse (verticale) Mouse (Inverted Vertical) Mouse (verticale invertito) Arrows: Up | Down Frecce: Su | Giù Arrows: Left | Right Frecce: Sinistra | Destra Keys: W | S Tasti: W | S Keys: A | D Tasti: A | D NumPad: KP_8 | KP_2 TastNum: TN_8 | TN_2 NumPad: KP_4 | KP_6 TastNum: TN_4 | TN_6 None Niente Mouse Settings Impostazioni mouse Left Mouse Button Tasto sinistro del mouse Right Mouse Button Tasto destro del mouse JoyButton Processing turbo for #%1 - %2 Processando turbo per #%1 - %2 Finishing turbo for button #%1 - %2 Finendo turbo per tasto #%1 - %2 Processing press for button #%1 - %2 Processando pressione per tasto #%1 - %2 Processing release for button #%1 - %2 Processando rilascio per tasto #%1 - %2 Distance change for button #%1 - %2 Cambio di distanza per tasto #%1 - %2 Button Tasto [NO KEY] [NO TASTO] [Set %1 1W] [Set %1 1DIREZ] [Set %1 2W] [Set %1 2DIREZ] [Set %1 WH] [Set %1 PREMENDO] JoyButtonContextMenu Toggle Cambio stato Turbo Turbo Clear Cancella Set Select Seleziona set Disabled Disattivato Set %1 Set %1 Set %1 1W Set %1 1DIREZ Set %1 2W Set %1 2DIREZ Set %1 WH Set %1 PREMENDO JoyButtonSlot Mouse Mouse Up Su Down Giù Left Sinistra Right Destra LB TastoMouseSX MB TastoMouseCENTRO RB TastoMouseDX B4 Tasto4 B5 Tasto5 Pause Pausa Hold Tieni Cycle Ciclo Distance Distanza Release Rilascia Mouse Mod Modifica mouse Press Time Tempo di pressione Delay Ritardo Load %1 Carica %1 Set Change %1 Cambio di set %1 [Text] %1 [Testo] %1 [Exec] %1 [Esec] %1 [NO KEY] [NO TASTO] JoyControlStick Stick Analogico JoyControlStickButton Up Su Down Giù Left Sinistra Right Destra Button Tasto JoyControlStickContextMenu Mouse (Normal) Mouse (normale) Mouse (Inverted Horizontal) Mouse (orizzontale invertito) Mouse (Inverted Vertical) Mouse (verticale invertito) Mouse (Inverted Horizontal + Vertical) Mouse (orizzontale + verticale invertito) Arrows Frecce Keys: W | A | S | D Tasti: W | A | S | D NumPad TastNum None Niente Standard Standard Eight Way 8 direzioni 4 Way Cardinal 4 direzioni cardinali 4 Way Diagonal 4 direzioni diagonali Mouse Settings Impostazioni mouse JoyControlStickEditDialog Dialog Finestra di dialogo X: X: 0 0 Y: Y: Distance: Distanza: Presets: Preimpostazioni: Mouse (Normal) Mouse (normale) Mouse (Inverted Horizontal) Mouse (orizzontale invertito) Mouse (Inverted Vertical) Mouse (verticale invertito) Mouse (Inverted Horizontal + Vertical) Mouse (orizzontale + verticale invertito) Arrows Frecce Keys: W | A | S | D Tasti: W | A | S | D NumPad TastNum None Niente Stick Mode: Modalità analogico: Standard: 8 region stick with two direction buttons active when the stick is in a diagonal region. Eight Way: 8 region stick with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region stick with regions corresponding to the cardinal directions of the stick. Useful for menus. 4 Way Diagonal: 4 region stick with each region corresponding to a diagonal zone of the stick. Standard: analogico a 8 regioni con due tasti direzionali attivi quando l'analogico è in una regione diagonale. 8 direzioni: analogico a 8 regioni con ogni direzione che ha un tasto dedicato. Solo un tasto alla volta viene premuto. Utile per i giochi come Rogue. 4 direzioni cardinali: analogico a 4 regioni con regioni corrispondenti alla direzione cardinale dell'analogico. Utile per i menu. 4 direzioni diagonali: analogico a 4 regioni con ogni regione corrispondente alla zona diagonale dell'analogico. 4 Way Cardinal 4 direzioni cardinali 4 Way Diagonal 4 direzioni diagonali Dead zone value to use for an analog stick. Valore zona morta da usare per un analogico. Value when an analog stick is considered moved 100%. Valore in cui un analogico viene considerato spostato al 100%. The area (in degrees) that each diagonal region occupies. L'area (in gradi) che ogni regione diagonale occupa. Square Stick: Analogico quadrato: Percentage to modify a square stick coordinates to confine values to a circle Percentuale per modificare le coordinate di un analogico quadrato per confinare i valori ad un cerchio. % % Stick Delay: Ritardo analogico: Time lapsed before a direction change is taken into effect. Tempo trascorso prima che il cambio di una direzione entri in funzione. s s Modifier: Modificatore: Edit button that is active while the stick is active. This button is useful for assigning zones with modifier keys that can be used to assign walk/run functionality to an analog stick. Modifica tasto che è attivo mentre l'analogico è attivo. Questo tasto è utile per assegnare zone con tasti di modificatore che possono essere usate per assegnare funzionalità cammina/corri ad un analogico. PushButton PremiTasto Name: Nome: Specify the name of an analog stick. Specifica il nome di un analogico. Mouse Settings Impostazioni mouse Standard Standard Bearing: Tolleranza: % Safe Zone: % Zona sicura: Eight Way 8 direzioni Dead Zone: Zona morta: Max Zone: Zona massima: Diagonal Range: Raggio diagonale: Set Set Set %1 Set %1 JoyControlStickModifierButton Modifier Modificatore JoyDPad DPad DPad JoyDPadButton Up Su Down Giù Left Sinistra Right Destra Button Tasto JoyTabWidget <New> <Nuovo> Remove Rimuovi Remove configuration from recent list. Rimuovi configurazione dalla lista dei recenti. Load Carica Load configuration file. Carica file di configurazione. Save Salva Save changes to configuration file. Salva cambiamenti sul file di configurazione. Save As Salva come Save changes to a new configuration file. Salva cambiamenti su un nuovo file di configurazione. Sets Set Copy from Set Copia da Set Settings Impostazioni Set 1 Set 1 Set 2 Set 2 Set 3 Set 3 Set 4 Set 4 Set 5 Set 5 Set 6 Set 6 Set 7 Set 7 Set 8 Set 8 Stick/Pad Assign Assegna analogico/pad Controller Mapping Mappatura controller Quick Set Set rapido Names Nomi Toggle button name displaying. Aziona visualizzazione del nome del tasto. Pref Pref Change global profile settings. Cambia opzioni globali profilo. Reset Reset Revert changes to the configuration. Reload configuration file. Ripristina modifiche alla configurazione. Ricarica file di configurazione. Open Config Apri configurazione Config Files (*.amgp *.xml) File di configurazione (*.amgp *.xml) Config File (*.%1.amgp) File di configurazione (*.%1.amgp) Save Profile Changes? Salvare cambiamenti profilo? Changes to the new profile have not been saved. Would you like to save or discard the current profile? I cambiamenti del nuovo profilo non sono stati salvati. Vuoi salvare o scartare il profilo corrente? Changes to the profile "%1" have not been saved. Would you like to save or discard changes to the current profile? I cambiamenti del profilo "%1" non sono stati salvati. Vuoi salvare o scartare il profilo corrente? Sticks Analogici DPads DPads No buttons have been assigned. Please use Quick Set to assign keys to buttons or disable hiding empty buttons. Nessun tasto è stato assegnato. Per favore usa il Set rapido per assegnare funzioni ai tasti o disattiva il nascondimento dei tasti vuoti. Set %1: %2 Set %1: %2 Set %1 Set %1 Copy Set Assignments Copia assegnazioni set Are you sure you want to copy the assignments and device properties from %1? Sei sicuro di voler copiare le assegnazioni e le proprietà dispositivo da %1? Save Config Salva configurazione Set Set Joystick Joystick Joystick JoystickStatusWindow Properties Proprietà Details Dettagli Name: Nome: %1 %1 Number: Numero: Axes: Assi: Buttons: Tasti: Hats: Hat switch: GUID: GUID: Game Controller: Controller di gioco: Axes Assi Buttons Tasti Hats Hat switch %1 (#%2) Properties %1 (#%2) Proprietà Axis %1 Asse %1 Hat %1 Hat switch %1 No No Yes Sì MainSettingsDialog Edit Settings Modifica impostazioni General Generale Controller Mappings Mappatura controller Language Lingua Auto Profile Auto-profilo Mouse Mouse <html><head/><body><p>Specify the default directory that the program should use in file dialogs when loading a profile or saving a new profile.</p></body></html> <html><head/><body><p>Specifica la cartella predefinita che il programma deve usare nelle finestre di dialogo file mentre si carica un profilo o se ne salva uno nuovo.</p></body></html> Recent Profile Count: Conteggio profili recenti: <html><head/><body><p>Number of profiles that can be placed in recent profile list. 0 will result in the program not enforcing a limit on the number of profiles displayed.</p></body></html> <html><head/><body><p>Numero di profili che possono essere messi nella lista dei profili recenti. 0 significa che il programma non impone alcun limite sui profili visualizzati.</p></body></html> Gamepad Poll Rate: Velocità di polling del gamepad: Change the poll rate that the program uses to discover new events from gamepads. Defaults to 10 ms. Reducing the poll rate value could cause the application to use more CPU power so please test the setting that you use before using antimicro unattended. Cambia la velocità di polling che il programma usa per scoprire nuovi eventi dai gamepad. Predefinito: 10 ms. Ridurre la velocità di polling potrebbe causare un consumo di CPU maggiore quindi per favore esamina l'impostazione che userai. Hide main window when the main window close button is clicked instead of quitting the program. Nascondi finestra principale quando il tasto chiusura della finestra principale viene cliccato invece di uscire dal programma. Close To Tray Riduci nell'area di notifica Have Windows start antimicro at system startup. Avvia antimicro automaticamente all'avvio di Windows. Launch At Windows Startup Esegui all'avvio di Windows Display recent profiles for all controllers as a single list in the tray menu. Defaults to using sub-menus. Mostra profili recenti per tutti i controller come una lista singola nell'area di notifica. Di predefinito, usa i sottomenu. Single Profile List in Tray Lista profili singola nell'area di notifica Have the program minimize to the taskbar. By default, the program minimizes to the system tray if available. Riduci a icona il programma. Di predefinito, il programma si riduce a icona se possibile. Minimize to Taskbar Riduci a icona This option will cause the program to hide all buttons that have no slots assigned to them. The Quick Set dialog window will have to be used to bring up the edit dialog for gamepad buttons. Questa opzione farà nascondere tutti i tasti che non hanno slot assegnati. Bisognerà quindi usare la finestra di dialogo Set rapido per mostrare la finestra di dialogo di modifica per i tasti gamepad. Hide Empty Buttons Nascondi tasti vuoti When the program is launched, open the last known profile that was opened during the previous session. Quando il programma viene eseguito, apri l'ultimo profilo conosciuto usato nella precedente sessione. Auto Load Last Opened Profile Auto-carica l'ultimo profilo aperto Only show the system tray icon when the program first launches. Mostra solo l'icona dell'area di notifica quando il programma si apre la prima volta. Launch in Tray Esegui nell'area di notifica Associate .amgp files with antimicro in Windows Explorer. Associa file .amgp con antimicro in Windows Explorer. Associate Profiles Associa profili Key Repeat Ripetizione tasto Active keys will be repeatedly pressed when this option is enabled. I tasti attivi verranno premuti a ripetizione quando questa opzione è attivata. Enable Attiva Specifies how much time should elapse before key repeating begins. Specifica quanto tempo debba passare prima che cominci la ripetizione tasto. Specifies how many times key presses will be performed per seconds. Specifica quante volte al secondo verranno premuti i tasti. <html><head/><body><p>antimicro has been translated into many different languages by contributors. By default, the program will choose an appropriate translation based on your system's locale setting. However, you can make antimicro load a different translation depending on the language that you choose from the list below.</p></body></html> <html><head/><body><p>antimicro è stato tradotto in molte lingue da collaboratori. Di base, il programma sceglierà una traduzione adatta basandosi sulle impostazioni della lingua del tuo sistema. Tuttavia, puoi far caricare ad antimicro una lingua differente a seconda di quella che scegli nella lista qui sotto.</p></body></html> French Francese Italian Japanese Giapponese Russian Russo Serbian Serbo Simplified Chinese Cinese semplificato Ukrainian Ucraino Class Classe Title Titolo Program Programma Disable the "Enhanced Pointer Precision" Windows setting while antimicro is running. Disabling "Enhanced Pointer Precision" will allow mouse movement within antimicro to be more precise. Disabilita l'impostazione di Windows "Aumenta precisione puntatore" mentre antimicro è in esecuzione. Disattivare "Aumenta precisione puntatore" permetterà movimenti del mouse più precisi. Disable Enhance Pointer Precision Disattiva Aumenta precisione puntatore Smoothing Histor&y Size: Dimensioni storia: Weight &Modifier: Modificatore peso: Refresh Rate: Frequenza di aggiornamento: The refresh rate is the amount of time that will elapse in between mouse events. Please be cautious when editing this setting as it will cause the program to use more CPU power. Setting this value too low can cause system instability. Please test the setting before using it unattended. La frequenza di aggiornamento è la quantità di tempo che trascorre tra un evento mouse e l'altro. Per favore fai attenzione quando modifichi questa impostazione dato che farà consumare più CPU. Impostare un valore troppo basso può causare instabilità al sistema. Per favore esamina l'impostazione che userai. Spring Fonte Screen: Schermo: Utilize the specified screen for spring mode. On Linux, the default is to use the primary screen. On Windows, the default is to use all available screens. Utilizza lo schermo specificato per la modalità fonte. Su Linux, di predefinito viene usato lo schermo primario. Su Windows, di predefinito vengono usati tutti gli schermi disponibili. Accel Numerator: Numeratore accelerazione: 0 0 Accel Denominator: Denominatore accelerazione: Accel Threshold: Soglia accelerazione: If the acceleration values for the virtual mouse have been changed by a different process, particularly when quitting an older game, then you might want to reset the acceleration values used by the virtual mouse. Se i valori di accelerazione per il mouse virtuale sono stati cambiati da un altro processo, specialmente uscendo da un vecchio gioco, allora potresti voler resettare i valori di accelerazione usati dal mouse virtuale. Reset Acceleration Resetta accelerazione Delay: Ritardo: Profi&le Directory: Cartella profilo: ms ms Rate: Rapporto: times/s volte/s Below is a list of the custom mappings that have been saved. You can use the following table to delete mappings or have mappings temporarily disabled. You can also disable mappings that are included with SDL; just insert a new row with the appropriate joystick GUID and check disable. Settings will not take affect until you either refresh all joysticks or unplug that particular joystick. Qui sotto c'è una lista di mappature personalizzate salvate. Puoi utilizzare la seguente tabella per cancellare le mappature o disattivarle temporaneamente. Puoi anche disattivare le mappature incluse con SDL; basta inserire una nuova riga con il joystick GUID giusto e mettere la spunta su disattiva. Le impostazioni non avranno effetto finché non aggiorni tutti i joystick o disconnetti quel joystick in particolare. GUID GUID Mapping String Stringa di mappatura Disable? Disattivare? Delete Cancella Insert Inserisci Default Predefinito Brazilian Portuguese Portoghese brasiliano English Inglese German Tedesco Active Attivo Devices: Dispositivi: All Tutto Device Dispositivi Profile Profili Default? Predefinito? Add Aggiungi Edit Modifica Also, Windows users who want to use a low value should also check the "Disable Enhance Pointer Precision" checkbox if you haven't disabled the option in Windows. Inoltre, gli utenti Windows che vogliono usare un valore basso dovrebbero anche mettere la spunta su "Disattiva Aumenta precisione puntatore" se non hanno già disattivato tale opzione in Windows. Select Default Profile Directory Seleziona la cartella del profilo predefinito Are you sure you want to delete the profile? Sei sicuro di voler cancellare il profilo? MainWindow antimicro antimicro No Joysticks have been found. Please plug in a joystick and then choose the "Update Joysticks" option in the main menu Non è stato trovato alcun joystick. Per favore collega un joystick e scegli l'opzione "Aggiorna i joystick" dal menu principale If events are not seen by a game, please click here to run this application as the Adminstrator. Se gli eventi non vengono registrati dal gioco, clicca qui per eseguire l'applicazione da Amministratore. &App App &Options Opzioni &Help Aiuto &Quit Esci Ctrl+Q Ctrl+Q &Update Joysticks Aggiorna i joystick Ctrl+U Ctrl+U &Hide Nascondi Ctrl+H Ctrl+H &About A proposito Ctrl+A Ctrl+A About Qt A proposito di Qt Properties Proprietà Key Checker Controllo tasti Home Page Homepage GitHub Page Pagina GitHub Game Controller Mapping Mappatura controller di gioco Settings Impostazioni Stick/Pad Assign Assegna analogico/pad Wiki Wiki Could not find a proper controller identifier. Exiting. Impossibile trovare un identificatore controller adatto. Esco. (%1) (%1) Open File Apri file &Restore Ripristina Run as Administrator? Eseguire come amministratore? Are you sure that you want to run this program as Adminstrator? Some games run as Administrator which will cause events generated by antimicro to not be used by those games unless antimicro is also run as the Adminstrator. This is due to permission problems caused by User Account Control (UAC) options in Windows Vista and later. Sei sicuro di voler eseguire questo programma come Amministratore? Certi giochi vengono eseguiti come Amministratore, il che rende inutilizzabili certi eventi generati da antimicro a meno che anche antimicro venga eseguito come Amministratore. Questo succede per via dei problemi causati dalle opzioni del Controllo account utente (UAC) da Windows Vista in poi. Failed to elevate program Impossibile elevare il programma Failed to restart this program as the Administrator Impossibile riavviare questo programma come Amministratore Could not find controller. Exiting. Impossibile trovare controller. Esco. MouseAxisSettingsDialog Mouse Settings - Impostazioni mouse - Set %1 Set %1 MouseButtonSettingsDialog Mouse Settings - Impostazioni mouse - Set %1 Set %1 MouseControlStickSettingsDialog Mouse Settings Impostazioni mouse Set %1 Set %1 MouseDPadSettingsDialog Mouse Settings Impostazioni mouse Set %1 Set %1 MouseSettingsDialog Mouse Settings Impostazioni mouse Mouse Mode: Modalità mouse: Cursor mode is used to move the mouse cursor around the screen relative to its current position depending on how much you move an axis or if a button is pressed. Spring mode is used to move the mouse cursor from the center of the screen depending on how much you move an axis. The mouse cursor will be returned to the center of the screen when the axis is moved back to the dead zone. La modalità cursore viene usata per muovere il cursore del mouse sullo schermo in relazione alla sua posizione corrente a seconda di quanto muovi un'asse o se viene premuto un tasto. La modalità fonte viene usata per muovere il cursore del mouse dal centro dello schermo a seconda di quanto muovi un'asse. Il cursore del mouse tornerà al centro dello schermo quando l'asse torna nella la zona morta. Cursor Cursore Spring Fonte Acceleration: Accelerazione: Enhanced Precision Aumenta precisione Linear Lineare Quadratic Quadratico Cubic Cubico Quadratic Extreme Quadratico estremo Power Function Funzione di potenza Easing Quadratic Interpolazione quadratica Easing Cubic Interpolazione cubica Mouse Speed Settings Impostazioni velocità mouse Enable to change the horizontal and vertical speed boxes at the same time. Permette di modificare i campi di velocità orizzontale e verticale allo stesso tempo. Change Together Modifica insieme Options for adding more acceleration to the mouse movement beyond what the acceleration curve would produce. Acceleration is added based on how quickly an axis is moved in one gamepad poll. This is meant to help work around some of the issues of the very limited input range available using typical gamepad analog sticks. Delta Acceleration &Multiplier: Mi&n Threshold: Horizontal Speed: Velocità orizzontale: 1 = 20 pps 1 = 20 pixel/sec Vertical Speed: Velocità verticale: Wheel Hori. Speed: Velocità orizz. rotella: Set the speed used for horizontal mouse wheel movement according to number of simulated notches per second. Imposta la velocità usata per il movimento orizzontale della rotella del mouse a seconda del numero di tacche al secondo simulate. Set the speed used for vertical mouse wheel movement according to number of simulated notches per second. Imposta la velocità usata per il movimento verticale della rotella del mouse a seconda del numero di tacche al secondo simulate. Sensitivit&y: For Power Function acceleration curve. Specifies the factor to use for curve sensitivity. When the value is above 1.0, the mouse movement will be accelerated faster at the low end of an axis. Per la funzione di potenza della curva di accelerazione. Specifica il fattore da utilizzare per la sensibilità della curva. Quando il valore supera 1, il movimento del mouse verrà accelerato più velocemente nella parte bassa di un'asse. Easing Duration: Durata interpolazione: s s Extra Acceleration Accelerazione supplementare Multiplier: Moltiplicatore: Highest value to accelerate mouse movement by Il valore più grande per cui accelerare il mouse x x Start %: Inizio %: Start %: Acceleration begins at this percentage of the base multiplier L'accelerazione comincia da questa percentuale del moltiplicatore di base Min Threshold: Soglia minima: Minimum amount of axis travel required for acceleration to begin Valore minimo di spostamento asse richiesto per far sì che cominci l'accelerazione Max Threshold: Soglia massima: Maximum axis travel before acceleration has reached the multiplier value Valore massimo di spostamento asse prima che l'accelerazione raggiunga il valore del moltiplicatore E&xtra Duration: Curve: Curva: Ease Out Sine Sinusoidale graduale Ease Out Quad Quadratico graduale Ease Out Cubic Cubico graduale Release Radius: Raggio di rilascio: Specifies that the spring area will be relative to the mouse position set by a non-relative spring. Specifica che l'area della fonte sarà relativa alla posizione del mouse impostata da una fonte non relativa. Relative Relativa Mouse Status Stato mouse X: X: 0 (0 pps) 0 (0 pixel/sec) Y: Y: 1 = 1 notch(es)/s 1 = 1 tacca(tacche)/sec Enhanced: Three tier curve that makes the mouse move slow on the low end of an axis and fast on the high end. Linear: Mouse moves proportionally to axis. Quadratic: Mouse accelerates slowly on low end. Cubic: Mouse accelerates slower than Quadratic. Quadratic Extreme: Raises mouse speed 1.5 times once 95% axis travel has been reached. Power Function: Allows for a more custom curve option. Easing Quadratic: Axis high end is gradually accelerated over a period of time using a Quadratic curve. Easing Cubic: Axis high end is gradually accelerated over a period of time using a Cubic curve. Aumentato: curva a tre livelli che fa muovere il mouse lentamente verso la parte bassa di un'asse e velocemente nella parte alta. Lineare: il mouse si muove in modo proporzionale in un'asse. Quadratico: il mouse accelera lentamente nella parte bassa. Cubico: il mouse accelera più lentamente di Quadratico. Quadratico estremo: aumenta la velocità del mouse per 1.5 una volta che lo spostamento di un'asse raggiunge il 95%. Funzione di potenza: permette l'opzione di una curva più personalizzata. Interpolazione quadratica: la parte alta di un'asse viene gradualmente accelerata per un periodo di tempo usando una curva quadratica. Interpolazione cubica: la parte alta di un'asse viene gradualmente accelerata per un periodo di tempo usando una curva cubica. Hori&zontal Speed: &Vertical Speed: Wheel Vert. Speed: Velocità orizz. rotella: Sensitivity: Sensibilità: Specifies the amount of time (in seconds) that will be required before the mouse is fully accelerated after reaching the high end of an axis. Specifica il periodo di tempo (in secondi) che saranno necessari prima che il mouse sia pienamente accelerato dopo aver raggiunto la parte alta di un'asse. Options for adding extra acceleration to the mouse movement beyond what the acceleration curve would produce. This is meant to help work around some of the issues of the very limited input range available using typical gamepad analog sticks. Opzioni per aggiungere più accelerazione al movimento del mouse oltre a quello che la curva di accelerazione produrrebbe. Questo serve a risolvere alcuni problemi legati all'estremamente limitata gamma di input disponibili usando i tipici analogici dei gamepad. % % Extra Duration: Durata aggiuntiva: Extend the time that extra acceleration is applied. Axis travel will be taken into account. A slower flick will decrease the actual time that extra acceleration will be applied. Estende il tempo in cui l'accelerazione aggiuntiva viene applicata. Il percorso dell'asse verrà considerato. Un movimento più lento diminuirà il tempo effettivo in cui verrà applicata l'accelerazione supplementare. Spring Settings Impostazioni fonte Spring Width: Larghezza fonte: Changes the width of the region that the cursor can move in spring mode. 0 will use the entire width of your screen. Cambia la larghezza della regione in cui il cursore può muoversi in modalità fonte. 0 utilizzerà l'intera grandezza dello schermo. Spring Height: Altezza fonte: Changes the height of the region that the cursor can move in spring mode. 0 will use the entire height of your screen. Cambia l'altezza della regione in cui il cursore può muoversi in modalità fonte. 0 utilizzerà l'intera grandezza dello schermo. %n notch(es)/s %n notch/s %n notches/s QKeyDisplayDialog Key Checker Controllo tasti <html><head/><body><p>Press a key on your keyboard to see how the key is detected by this application. The window will show the system native key value, the original value given by Qt (if applicable), and the custom value used by antimicro.</p><p>The antimicro key value and the Qt key value will usually be the same. antimicro tries to use the key values defined in Qt when possible. Check the page <a href="https://doc.qt.io/qt-4.8/qt.html#Key-enum"><span style=" text-decoration: underline; color:#0057ae;">https://doc.qt.io/qt-4.8/qt.html#Key-enum</span></a> for a list of values defined by Qt. If you discover that a key is not natively supported by this program, please report the problem to antimicro's <a href="https://github.com/AntiMicro/antimicro"><span style=" text-decoration: underline; color:#0057ae;">GitHub page</span></a> so that the program can be edited to support it directly. As it is, a custom prefix is added to unknown values so they can still be used; the main problem is that the profile will no longer be portable.</p></body></html> <html><head/><body><p>Premi un tasto sulla tua tastiera per vedere come viene rilevato da questa applicazione. La finestra mostrerà il valore tasto nativo, il valore originale dato da Qt (se applicabile), e il valore personalizzato usato da antimicro.</p><p>Il valore tasto antimicro e il valore tasto Qt solitamente saranno gli stessi. antimicro cerca di i valori tasto definiti in Qt se possibile. Guarda la pagina <a href="https://doc.qt.io/qt-4.8/qt.html#Key-enum"><span style=" text-decoration: underline; color:#0057ae;">https://doc.qt.io/qt-4.8/qt.html#Key-enum</span></a> per una lista di valori definiti da Qt. Se scopri un tasto che non è supportato nativamente da questo programma, per favore segnala il problema alla <a href="https://github.com/AntiMicro/antimicro"><span style=" text-decoration: underline; color:#0057ae;">pagina GitHub</span></a> cosicché il programma possa essere modificato per supportarlo direttamente. In questo momento, un prefisso personalizzato viene aggiunto ai valori sconosciuti in modo che possano essere ancora utilizzati; il problema principale è che il profilo non sarà più portatile.</p></body></html> Event Handler: Gestore di eventi: Native Key Value: Valore tasto nativo: 0x00000000 0x00000000 Qt Key Value: Valore tasto Qt: antimicro Key Value: Valore tasto antimicro: QObject Super Super Menu Menu Mute Muto Vol+ Vol+ Vol- Vol- Play/Pause Play/Pausa Play Play Pause Pausa Prev Prec Next Succ Mail Mail Home Home Media Media Search Cerca Daemon launched Demone avviato Failed to launch daemon Impossibile avviare demone Launching daemon Avviando demone Display string "%1" is not valid. La stringa di display "%1" non è valida. Failed to set a signature id for the daemon Impossibile impostare un ID firma per il demone Failed to change working directory to / Impossibile cambiare la cartella di lavoro per / Quitting Program Chiudendo il programma # of joysticks found: %1 â„– di joystick trovati: %1 List Joysticks: Lista joystick: --------------- --------------- Joystick %1: Joystick %1: Index: %1 Indice: %1 GUID: %1 GUID: %1 Name: %1 Nome: %1 Yes Sì No No Game Controller: %1 Controller di gioco: %1 # of Axes: %1 â„– di assi: %1 # of Buttons: %1 â„– di tasti: %1 # of Hats: %1 â„– di hat switch: %1 Attempting to use fallback option %1 for event generation. Tentativo di utilizzo dell'opzione alternativa %1 per la generazione eventi. Failed to open event generator. Exiting. Impossibile aprire il generatore di eventi. Esco. Using %1 as the event generator. Sto usando %1 come generatore eventi. Could not raise process priority. Impossibile aumentare la priorità del processo. QuickSetDialog Quick Set Set rapido <html><head/><body><p>Please press a button or move an axis on %1 (<span style=" font-weight:600;">%2</span>).<br/>A dialog window will then appear which will<br/>allow you to make an assignment.</p></body></html> <html><head/><body><p>Per favore premi un tasto o muovi un'asse su %1 (<span style=" font-weight:600;">%2</span>).<br/>Verrà mostrata una finestra di dialogo che<br/>ti permetterà di creare un'assegnazione.</p></body></html> Quick Set %1 Set rapido %1 SetAxisThrottleDialog Throttle Change Modifica acceleratore The throttle setting for Axis %1 has been changed. Would you like to distribute this throttle change to all sets? L'impostazione dell'acceleratore per l'asse %1 è cambiata. Vuoi distribuire questa modifica su tutti i set? SetJoystick Set %1: %2 Set %1: %2 Set %1 Set %1 SetNamesDialog Set Name Settings Impostazioni nome set Set 1 Set 1 Set 2 Set 2 Set 3 Set 3 Set 4 Set 4 Set 5 Set 5 Set 6 Set 6 Set 7 Set 7 Set 8 Set 8 Name Nome SimpleKeyGrabberButton Mouse Mouse SpringModeRegionPreview Spring Mode Preview Anteprima modalità fonte UInputEventHandler Could not find a valid uinput device file. Please check that you have the uinput module loaded. lsmod | grep uinput Impossibile trovare un valido file di dispositivo uinput. Per favore controlla di aver caricato il modulo uinput. lsmod | grep uinput Could not open uinput device file Please check that you have permission to write to the device Impossibile aprire il file di dispositivo uinput. Per favore controlla di avere i permessi di scrittura sul dispositivo. Using uinput device file %1 File di dispositivo uinput %1 in uso UInputHelper a a b b c c d d e e f f g g h h i i j j k k l l m m n n o o p p q q r r s s t t u u v v w w x x y y z z Esc Esc F1 F1 F2 F2 F3 F3 F4 F4 F5 F5 F6 F6 F7 F7 F8 F8 F9 F9 F10 F10 F11 F11 F12 F12 ` ` 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 0 0 - - = = BackSpace BackSpace Tab Tab [ [ ] ] \ \ CapsLock BlocMaiusc ; ; ' ' Enter Invio Shift_L Maiusc_SX , , . . / / Ctrl_L Ctrl_SX Super_L Super_SX Alt_L Alt_SX Space Spazio Alt_R Alt_DX Menu Menu Ctrl_R Ctrl_DX Shift_R Maiusc_DX Up Su Left Sinistra Down Giù Right Destra PrtSc Stamp Ins Ins Del Canc Home Home End Fine PgUp PgSu PgDn PgGiù NumLock BlocNum * * + + KP_Enter TN_Invio KP_1 TN_1 KP_2 TN_2 KP_3 TN_3 KP_4 TN_4 KP_5 TN_5 KP_6 TN_6 KP_7 TN_7 KP_8 TN_8 KP_9 TN_9 KP_0 TN_0 SCLK BlocScorr Pause Pausa Super_R Super_DX Mute Muto VolDn VolGiù VolUp VolSu Play Play Stop Stop Prev Prec Next Succ [NO KEY] [NO TASTO] UnixWindowInfoDialog Captured Window Properties Finestra proprietà catturate Information About Window Informazioni sulla finestra Class: Classe: TextLabel etichetta di testo Title: Titolo: Path: Percorso: Match By Properties Trova per proprietà Class Classe Title Titolo Path Percorso VDPad VDPad VDPad VirtualKeyPushButton Space Spazio Tab Tab Shift (L) Maiusc (SX) Shift (R) Maiusc (DX) Ctrl (L) Ctrl (SX) Ctrl (R) Ctrl (DX) Alt (L) Alt (SX) Alt (R) Alt (DX) ` ` ~ ~ - - = = [ [ ] ] \ \ Caps Caps ; ; ' ' , , . . / / ESC ESC PRTSC STAMP SCLK BLOCSCORR INS INS PGUP PGSU DEL CANC PGDN PGGIU 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 0 0 NUM LK BLOC NUM * * + + E N T E R I N V I O < < : : Super (L) Super (SX) Menu Menu Up Su Down Giù Left Sinistra Right Destra VirtualKeyboardMouseWidget Keyboard Tastiera Mouse Mouse Mouse Settings Impostazioni mouse Left Mouse Sinistra Up Mouse Su Left Button Mouse Tasto sinistro Middle Button Mouse Tasto centrale Right Button Mouse Tasto destro Wheel Up Mouse Rotella su Wheel Left Mouse Rotella sinistra Wheel Right Mouse Rotella destra Wheel Down Mouse Rotella giù Down Mouse Giù Right Mouse Destra Button 4 Mouse Tasto 4 Mouse 8 Mouse Mouse 8 Button 5 Mouse Tasto 5 Mouse 9 Mouse Mouse 9 NONE NIENTE Applications Applicazioni Browser Back Browser indietro Browser Favorites Browser preferiti Browser Forward Browser avanti Browser Home Browser home Browser Refresh Browser aggiorna Browser Search Browser cerca Browser Stop Browser stop Calc Calc Email Email Media Media Media Next Media successivo Media Play Media play Media Previous Media precedente Media Stop Media stop Search Cerca Volume Down Volume giù Volume Mute Volume muto Volume Up Volume su VirtualMousePushButton INVALID INVALIDO WinAppProfileTimerDialog Capture Application Cattura applicazione After pressing the "Capture Application" button, please select the application window that you want to have a profile associated with. The active application will be captured after the selected number of seconds. Dopo aver premuto il tasto "Cattura applicazione", per favore seleziona la finestra dell'applicazione con cui vuoi associare un profilo. L'applicazione attiva verrà catturata dopo il numero di secondi scelto. Timer: Timer: Seconds Secondi Cancel Annulla WinExtras [NO KEY] [NO TASTO] AntiMicro Profile Profilo AntiMicro X11Extras ESC ESC Tab Tab Space Spazio DEL CANC Return Invio KP_Enter TN_Invio Backspace Backspace xinput extension was not found. No mouse acceleration changes will occur. Estensione xinput non trovata. Non avverrà alcuna modifica all'accelerazione mouse. xinput version must be at least 2.0. No mouse acceleration changes will occur. La versione xinput dev'essere almeno 2.0. Non avverrà alcuna modifica all'accelerazione mouse. Virtual pointer found with id=%1. Trovato puntatore virtuale con id=%1. PtrFeedbackClass was not found for virtual pointer.No change to mouse acceleration will occur for device with id=%1 PtrFeedbackClass non è stato trovato per il puntatore virtuale. Non avverrà alcuna modifica all'accelerazione del mouse con id=%1 Changing mouse acceleration for device with id=%1 Modificando l'accelerazione mouse per il dispositivo con id=%1 XMLConfigReader Could not write updated profile XML to file %1. Impossibile scrivere profilo XML aggiornato sul file %1. XMLConfigWriter Could not write to profile at %1. Impossibile scrivere su profilo a %1. antimicro-2.23/share/antimicro/translations/antimicro_ja.ts000066400000000000000000011217331300750276700242630ustar00rootroot00000000000000 AboutDialog About Version ãƒãƒ¼ã‚¸ãƒ§ãƒ³ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Originally developed by Travis Nickles &lt;nickles.travis@gmail.com&gt;, now maintained by the AntiMicro group at https://github.com/AntiMicro.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Contributors:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;"><br /></span>Zerro Alvein</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">aybe</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jeff Backus &lt;jeff.backus@gmail.com&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Arthur Moore<br />Anton Tornqvist &lt;antont@inbox.lv&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7185</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">DarkStarSword</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">est31</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ProfessorKaos64</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">qwerty12</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA0</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Translators:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VaGNaroK &lt;vagnarokalkimist@gmail.com&gt; - Brazilian Portuguese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx - Chinese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Belleguic Terence &lt;hizo@free.fr&gt; - French</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Leonard Koenig &lt;leonard.r.koenig@googlemail.com&gt; - German</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phob - German</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">tou omiya - Japanese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Dmitriy Koshel &lt;form.eater@gmail.com&gt; - Russian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jay Alexander Fleming &lt;tito.nehru.naser@gmail.com&gt; - Serbian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">burunduk - Ukrainian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Flavio HR &lt;flavio.hrx@gmail.com&gt; - Spanish</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA - wazaaaaa00&lt;@&gt;gmail&lt;.&gt;com - Italian</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> Info 情報 Changelog Since December 30, 2012, I have been working on antimicro in my spare time. What originally started as a fork of QJoyPad and a way to learn proper event-driven programming has turned into something much bigger than I originally intended. Although I have spent a lot of time learning new techniques, finding out more about the domain of KB+M emulation, and spending Friday nights bashing my head against my keyboard, it has been a fun and enriching experience overall. The need for this program came from me using similar programs on Windows to play several games that did not provide native controller support. Although some alternatives existed on Linux, there wasn't really anything that I felt was good enough in terms of functionality or in-game controls in order to really enjoy games that I wanted to play with using KB+M emulation. QJoyPad was the main program that I had used in the past although it had aged a lot and it didn't provide some basic functionality that I thought was essential. The project was dead as it had not been updated in several years so I decided to make my own. Since then, I have tried to find out what the other programs do right and then improve upon it. I have also discovered some neat tricks along the way and I have learned more about how native gamepad controls are implemented in some games than I ever really wanted to know. Although there are definitely areas where this program could improve, I find that this program offers the best in-game control experience for playing older, and some newer, games that do not provide native controller support. Development of this program is not as high of a priority for me anymore. This is mainly due to the fact that the Steam Controller works pretty well for the task of playing PC games compared to using an Xbox 360 controller. However, it does look like there is still a reason for this program to exist for a while. Copyright: 2013 - 2016 Credits antimicro antimicro <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">GNU GENERAL PUBLIC LICENSE</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Version 3, 29 June 2007</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Preamble</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Developers that use the GNU GPL protect your rights with two steps:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">(1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The precise terms and conditions for copying, distribution and modification follow.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">TERMS AND CONDITIONS</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">0. Definitions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;This License&quot; refers to version 3 of the GNU General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Copyright&quot; also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;The Program&quot; refers to any copyrightable work licensed under this License. Each licensee is addressed as &quot;you&quot;. &quot;Licensees&quot; and &quot;recipients&quot; may be individuals or organizations.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;modify&quot; a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a &quot;modified version&quot; of the earlier work or a work &quot;based on&quot; the earlier work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;covered work&quot; means either the unmodified Program or a work based on the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;propagate&quot; a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;convey&quot; a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An interactive user interface displays &quot;Appropriate Legal Notices&quot; to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">1. Source Code.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;source code&quot; for a work means the preferred form of the work for making modifications to it. &quot;Object code&quot; means any non-source form of a work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;Standard Interface&quot; means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;System Libraries&quot; of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A &quot;Major Component&quot;, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;Corresponding Source&quot; for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source for a work in source code form is that same work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">2. Basic Permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">3. Protecting Users' Legal Rights From Anti-Circumvention Law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">4. Conveying Verbatim Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">5. Conveying Modified Source Versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) The work must carry prominent notices stating that you modified it, and giving a relevant date.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to &quot;keep intact all notices&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an &quot;aggregate&quot; if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">6. Conveying Non-Source Forms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;User Product&quot; is either (1) a &quot;consumer product&quot;, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, &quot;normally used&quot; refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Installation Information&quot; for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">7. Additional Terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Additional permissions&quot; are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Limiting the use for publicity purposes of names of licensors or authors of the material; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All other non-permissive additional terms are considered &quot;further restrictions&quot; within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">8. Termination.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">9. Acceptance Not Required for Having Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">10. Automatic Licensing of Downstream Recipients.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An &quot;entity transaction&quot; is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">11. Patents.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;contributor&quot; is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's &quot;contributor version&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A contributor's &quot;essential patent claims&quot; are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, &quot;control&quot; includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">In the following three paragraphs, a &quot;patent license&quot; is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To &quot;grant&quot; such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. &quot;Knowingly relying&quot; means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A patent license is &quot;discriminatory&quot; if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">12. No Surrender of Others' Freedom.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">13. Use with the GNU Affero General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">14. Revised Versions of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License &quot;or any later version&quot; applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">15. Disclaimer of Warranty.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM &quot;AS IS&quot; WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">16. Limitation of Liability.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">17. Interpretation of Sections 15 and 16.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.</span></p></body></html> About Development License ライセンス Program Version %1 Program Compiled on %1 at %2 Built Against SDL %1 Running With SDL %1 Using Qt %1 Using Event Handler: %1 AddEditAutoProfileDialog Auto Profile Dialog Profile: プロファイル: Browse Window: ウィンドウ: Select Window. Click on the appropriate application window and the application file path will be populated in the form. Detect Window Properties Class: Title: タイトル: Application: アプリケーション: Select Devices: デãƒã‚¤ã‚¹: Select this profile to be the default loaded for the specified device. The selection will be used instead of the all default profile option. Set as Default for Controller A different profile is already selected as the default for this device. Current (%1) Open Config Select Program Programs (*.exe) Please use the main default profile selection. Please select a window by using the mouse. Press Escape if you want to cancel. Capture Application Window Could not obtain information for the selected window. Application Capture Failed Profile file path is invalid. No window matching property was specified. Program path is invalid or not executable. File is not an .exe file. No window matching property was selected. AdvanceButtonDialog Advanced 詳細設定 Assignments 割り当㦠Toggle トグル Turbo 連射 Set Selector Blank or KB/M Hold Pause Pause Cycle Distance Insert Delete 削除 Clear All Time: 0.01s 0.01 ç§’ 0s 0 ç§’ Insert a pause that occurs in between key presses. Release Insert a new blank slot. Delete a slot. Clear all currently assigned slots. Specify the duration of an inserted Pause or Hold slot. 0m 0 分 &Mouse Speed Mod: Specify the range past an axis dead zone in which a sequence of actions will execute. Distance: % % Mouse Mod Press Time Delay Execute Load 読ã¿è¾¼ã¿ Set Change Text Entry Placeholder 0 0 Set the percentage that mouse speeds will be modified by. Auto Reset Cycle After seconds Executable: ... Arguments: Enabled 有効 Mode: <html><head/><body><p>Normal: Repeatedly press and release a button by the chosen rate.</p><p>Gradient: Modify the button press and button release delay based on how far an axis has been moved. The rate will remain the same.</p><p>Pulse: Modify how many times a button is pressed and released per second. The button delay will remain the same.</p></body></html> Normal Gradient Pulse Delay: 0.10s 0.10 ç§’ Rate: 10.0/s Disabled Select Set 1 One Way Select Set 1 Two Way Select Set 1 While Held Select Set 2 One Way Select Set 2 Two Way Select Set 2 While Held Select Set 3 One Way Select Set 3 Two Way Select Set 3 While Held Select Set 4 One Way Select Set 4 Two Way Select Set 4 While Held Select Set 5 One Way Select Set 5 Two Way Select Set 5 While Held Select Set 6 One Way Select Set 6 Two Way Select Set 6 While Held Select Set 7 One Way Select Set 7 Two Way Select Set 7 While Held Select Set 8 One Way Select Set 8 Two Way Select Set 8 While Held sec. /sec. Set %1 セット %1 Select Set %1 One Way Two Way While Held Choose Executable Slots past a Cycle action will be executed on the next button press. Multiple cycles can be added in order to create partitions in a sequence. Delays the time that the next slot is activated by the time specified. Slots activated before the delay will remain active after the delay time has passed. Distance action specifies that the slots afterwards will only be executed when an axis is moved a certain range past the designated dead zone. Insert a hold action. Slots after the action will only be executed if the button is held past the interval specified. Chose a profile to load when this slot is activated. Mouse mod action will modify all mouse speed settings by a specified percentage while the action is being processed. This can be useful for slowing down the mouse while sniping. Specify the time that keys past this slot should be held down. Insert a release action. Slots after the action will only be executed after a button release if the button was held past the interval specified. Change to selected set once slot is activated. Full string will be typed when a slot is activated. Execute program when slot is activated. Choose Profile Config Files (*.amgp *.xml) æ§‹æˆãƒ•ァイル (*.amgp *.xml) AdvanceStickAssignmentDialog Stick/Pad Assignment Sticks スティック DPads å字キー %1 (Joystick %2) %1 (ジョイスティック %2) Stick 1 スティック 1 Enabled 有効 Assign 割り当㦠X Axis: X 軸: Y Axis: Y 軸: Stick 2 スティック 2 Number of Physical DPads: %1 ç‰©ç†æ–¹å‘ã‚­ãƒ¼ã®æ•°: %1 Virtual DPad 1 仮想方å‘キー 1 Up: 上: Down: 下: Note: This window is meant for backwards compatibility with profiles made before antimicro 2.0. Since version 2.0, use of the Game Controller Mapping window is preferred. 注: ã“ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã¯ã€ãƒãƒ¼ã‚¸ãƒ§ãƒ³ 2.0 よりå‰ã® antimicro ã§ä½œæˆã—ãŸãƒ—ロファイルã¨ã®å¾Œæ–¹äº’æ›æ€§ã‚’確ä¿ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã—ã¾ã™ã€‚ãƒãƒ¼ã‚¸ãƒ§ãƒ³ 2.0 以é™ã§ã¯ã€Œã‚²ãƒ¼ãƒ ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ©ãƒ¼ãƒžãƒƒãƒ”ングã€ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã®ä½¿ç”¨ã‚’推奨ã—ã¾ã™ã€‚ Left: å·¦: Right: å³: Axis %1 軸 %1 Axis %1 - 軸 %1 - Axis %1 + 軸 %1 + Button %1 ボタン %1 Move stick 1 along the X axis Move stick 1 along the Y axis Move stick 2 along the X axis Move stick 2 along the Y axis Press a button or move an axis AxisEditDialog Axis 軸 Mouse (Horizontal) Mouse (Inverted Horizontal) Mouse (Vertical) Mouse (Inverted Vertical) Arrows: Up | Down Arrows: Left | Right Keys: W | S Keys: A | D NumPad: KP_8 | KP_2 NumPad: KP_4 | KP_6 None Set the value to use as the limit for an axis. Useful for a worn out analog stick. Negative Half Throttle Positive Half Throttle Name: åå‰: Specify the name of an axis. Mouse Settings マウスã®è¨­å®š Set the value of the dead zone for an axis. Presets: プリセット: Dead Zone: Max Zone: [NO KEY] [割り当ã¦ãªã—] Throttle setting that determines the behavior of how to interpret an axis hold or release. Negative Throttle Normal Positive Throttle Current Value: Set セット Set %1 セット %1 Left Mouse Button 左マウスボタン Right Mouse Button å³ãƒžã‚¦ã‚¹ãƒœã‚¿ãƒ³ ButtonEditDialog Dialog To make a new assignment, press any keyboard key or click a button in the Keyboard or Mouse tab 割り当ã¦ã‚’æ–°è¦ä½œæˆã™ã‚‹ã«ã¯ã€ã‚­ãƒ¼ãƒœãƒ¼ãƒ‰ã®ã‚­ãƒ¼ã‚’押ã™ã‹ã€ã€Œã‚­ãƒ¼ãƒœãƒ¼ãƒ‰ã€ã‚ã‚‹ã„ã¯ã€Œãƒžã‚¦ã‚¹ã€ã‚¿ãƒ–ã®ã„ãšã‚Œã‹ã®ãƒœã‚¿ãƒ³ã‚’クリックã—ã¦ãã ã•ã„ Placeholder Toggle トグル Enables a key press or release to only occur when a controller button is pressed. Enables rapid key presses and releases. Turbo controller. Turbo 連射 Current: ç¾åœ¨ã®å‰²ã‚Šå½“ã¦: Slots Na&me: åå‰(&M): Specify the name of a button. Action: アクション: Specify the action that will be performed in game while this button is being used. Advanced 詳細設定 Set セット Set %1 セット %1 CapturedWindowInfoDialog Captured Window Properties Information About Window Class: TextLabel Title: タイトル: Path: Match By Properties Class Title タイトル Path Full Path File Name CommandLineUtility Profile location %1 is not an XML file. Profile location %1 does not exist. An invalid set number '%1' was specified. Controller identifier '%s'' is not a valid value. No display string was specified. Controller identifier is not a valid value. No set number was specified. No controller was specified. An invalid event generator was specified. No event generator string was specified. Qt style flag was detected but no style was specified. No log level specified. antimicro version Usage: antimicro [options...] [profile] Options オプション Print help text. Print version information. Launch program in system tray only. Launch program with the tray menu disabled. Launch program without the main window displayed. Launch program with the configuration file selected as the default for selected controllers. Defaults to all controllers. Apply configuration file to a specific controller. Value can be a controller index, name, or GUID. Unload currently enabled profile(s). Value can be a controller index, name, or GUID. Start joysticks on a specific set. Value can be a controller index, name, or GUID. Advance profile loading set options. Launch program as a daemon. Enable logging. Use specified display for X11 calls. Useful for ssh. Choose between using XTest support and uinput support for event generation. Default: xtest. Choose between using SendInput and vmulti support for event generation. Default: sendinput. Print information about joysticks detected by SDL. Open game controller mapping window of selected controller. Value can be a controller index or GUID. DPadContextMenu Mouse (Normal) Mouse (Inverted Horizontal) Mouse (Inverted Vertical) Mouse (Inverted Horizontal + Vertical) Arrows Keys: W | A | S | D NumPad None Standard Eight Way 4 Way Cardinal 4 Way Diagonal Mouse Settings マウスã®è¨­å®š DPadEditDialog Dialog Presets: プリセット: Mouse (Normal) Mouse (Inverted Horizontal) Mouse (Inverted Vertical) Mouse (Inverted Horizontal + Vertical) Arrows Keys: W | A | S | D NumPad None Dpad Mode: &Name: 4 Way Cardinal 4 Way Diagonal DPad Delay: Time lapsed before a direction change is taken into effect. s Specify the name of a dpad. Mouse Settings マウスã®è¨­å®š Standard Standard: 8 region dpad with two direction buttons active when the dpad is in a diagonal region. Eight Way: 8 region dpad with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region dpad with regions corresponding to the cardinal directions of the dpad. Useful for menus. 4 Way Diagonal: 4 region dpad with each region corresponding to a diagonal zone. Eight Way Set セット Set %1 セット %1 EditAllDefaultAutoProfileDialog Default Profile Profile: プロファイル: Browse Open Config Profile file path is invalid. ExtraProfileSettingsDialog Extra Profile Settings Key Press Time: 0.00 ms Profile Name: プロファイルå: s s GameController Game Controller ゲームコントローラー GameControllerDPad DPad å字キー GameControllerMappingDialog Game Controller Mapping <html><head/><body><p>antimicro makes use of the <a href="https://wiki.libsdl.org/CategoryGameController"><span style=" text-decoration: underline; color:#0057ae;">Game Controller API</span></a> provided by SDL 2 in order to abstract various gamepads to fit a unified standard. In order to make a button assignment, please highlight the mapping cell for the appropriate button row below. You can then press a button or move an axis on your gamepad and the cell will update with the physical button or axis that will be used.</p><p>antimicro will use the mapping that you specify to save a mapping string that will be loaded into SDL.</p></body></html> A A B B X X Y Y Back Start Guide Left Shoulder Right Shoulder Left Stick Click Right Stick Click Left Stick X 左スティック X Left Stick Y 左スティック Y Right Stick X å³ã‚¹ãƒ†ã‚£ãƒƒã‚¯ X Right Stick Y å³ã‚¹ãƒ†ã‚£ãƒƒã‚¯ Y Left Trigger 左トリガー Right Trigger å³ãƒˆãƒªã‚¬ãƒ¼ DPad Up å字キー↑ DPad Left å字キー↠DPad Down å字キー↓ DPad Right å字キー→ Mapping SDL 2 Game Controller Mapping String Last Axis Event: Current Axis Detection Dead Zone: 5000 5000 10000 10000 15000 15000 20000 20000 25000 25000 30000 30000 32000 32000 Game Controller Mapping (%1) (#%2) Discard Controller Mapping? Discard mapping for this controller? If discarded, the controller will be reverted to a joystick once you refresh all joysticks. GameControllerSet Back Guide Start LS Click RS Click L Shoulder R Shoulder L Trigger 左トリガー R Trigger å³ãƒˆãƒªã‚¬ãƒ¼ GameControllerTrigger Trigger トリガー JoyAxis Axis 軸 JoyAxisButton Negative Positive Unknown 䏿˜Ž Button ボタン JoyAxisContextMenu Mouse (Horizontal) Mouse (Inverted Horizontal) Mouse (Vertical) Mouse (Inverted Vertical) Arrows: Up | Down Arrows: Left | Right Keys: W | S Keys: A | D NumPad: KP_8 | KP_2 NumPad: KP_4 | KP_6 None Mouse Settings マウスã®è¨­å®š Left Mouse Button 左マウスボタン Right Mouse Button å³ãƒžã‚¦ã‚¹ãƒœã‚¿ãƒ³ JoyButton Processing turbo for #%1 - %2 Finishing turbo for button #%1 - %2 Processing press for button #%1 - %2 Processing release for button #%1 - %2 Distance change for button #%1 - %2 Button ボタン [NO KEY] [割り当ã¦ãªã—] [Set %1 1W] [Set %1 2W] [Set %1 WH] JoyButtonContextMenu Toggle トグル Turbo 連射 Clear Set Select Disabled Set %1 セット %1 Set %1 1W セット %1 1W Set %1 2W セット %1 2W Set %1 WH JoyButtonSlot Mouse マウス Up ↑ Down ↓ Left ↠Right → LB MB RB B4 B5 Pause Pause Hold Cycle Distance Release Mouse Mod Press Time Delay Load %1 Set Change %1 [Text] %1 [Exec] %1 [NO KEY] [割り当ã¦ãªã—] JoyControlStick Stick スティック JoyControlStickButton Up ↑ Down ↓ Left ↠Right → Button ボタン JoyControlStickContextMenu Mouse (Normal) Mouse (Inverted Horizontal) Mouse (Inverted Vertical) Mouse (Inverted Horizontal + Vertical) Arrows Keys: W | A | S | D NumPad None Standard Eight Way 4 Way Cardinal 4 Way Diagonal Mouse Settings マウスã®è¨­å®š JoyControlStickEditDialog Dialog X: X: 0 0 Y: Y: Distance: Presets: プリセット: Mouse (Normal) Mouse (Inverted Horizontal) Mouse (Inverted Vertical) Mouse (Inverted Horizontal + Vertical) Arrows Keys: W | A | S | D NumPad None Stick Mode: Standard: 8 region stick with two direction buttons active when the stick is in a diagonal region. Eight Way: 8 region stick with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region stick with regions corresponding to the cardinal directions of the stick. Useful for menus. 4 Way Diagonal: 4 region stick with each region corresponding to a diagonal zone of the stick. 4 Way Cardinal 4 Way Diagonal Dead zone value to use for an analog stick. Value when an analog stick is considered moved 100%. The area (in degrees) that each diagonal region occupies. Square Stick: Percentage to modify a square stick coordinates to confine values to a circle % % Stick Delay: Time lapsed before a direction change is taken into effect. s Modifier: Edit button that is active while the stick is active. This button is useful for assigning zones with modifier keys that can be used to assign walk/run functionality to an analog stick. PushButton Name: åå‰: Specify the name of an analog stick. Mouse Settings マウスã®è¨­å®š Standard Bearing: % Safe Zone: Eight Way Dead Zone: Max Zone: Diagonal Range: Set セット Set %1 セット %1 JoyControlStickModifierButton Modifier JoyDPad DPad å字キー JoyDPadButton Up ↑ Down ↓ Left ↠Right → Button ボタン JoyTabWidget <New> <æ–°è¦> Remove 削除 Remove configuration from recent list. Load 読ã¿è¾¼ã¿ Load configuration file. Save ä¿å­˜ Save changes to configuration file. Save As 別åä¿å­˜ Save changes to a new configuration file. Sets セット Copy from Set セットã‹ã‚‰ã‚³ãƒ”ー Settings 設定 Set 1 セット 1 Set 2 セット 2 Set 3 セット 3 Set 4 セット 4 Set 5 セット 5 Set 6 セット 6 Set 7 セット 7 Set 8 セット 8 Stick/Pad Assign Controller Mapping Quick Set クイックセット Names Toggle button name displaying. Pref Change global profile settings. Reset リセット Revert changes to the configuration. Reload configuration file. Open Config Config Files (*.amgp *.xml) æ§‹æˆãƒ•ァイル (*.amgp *.xml) Config File (*.%1.amgp) æ§‹æˆãƒ•ァイル (*.%1.amgp) Save Profile Changes? Changes to the new profile have not been saved. Would you like to save or discard the current profile? Changes to the profile "%1" have not been saved. Would you like to save or discard changes to the current profile? Sticks スティック DPads å字キー No buttons have been assigned. Please use Quick Set to assign keys to buttons or disable hiding empty buttons. Set %1: %2 セット %1: %2 Set %1 セット %1 Copy Set Assignments Are you sure you want to copy the assignments and device properties from %1? Save Config Set セット Joystick Joystick ジョイスティック JoystickStatusWindow Properties プロパティ Details Name: åå‰: %1 %1 Number: Axes: 軸: Buttons: ボタン: Hats: GUID: GUID: Game Controller: ゲームコントローラー: Axes 軸 Buttons ボタン Hats %1 (#%2) Properties Axis %1 軸 %1 Hat %1 No ã„ã„㈠Yes ã¯ã„ MainSettingsDialog Edit Settings General 全般 Controller Mappings Language 言語 Auto Profile Mouse マウス <html><head/><body><p>Specify the default directory that the program should use in file dialogs when loading a profile or saving a new profile.</p></body></html> Recent Profile Count: <html><head/><body><p>Number of profiles that can be placed in recent profile list. 0 will result in the program not enforcing a limit on the number of profiles displayed.</p></body></html> Gamepad Poll Rate: Change the poll rate that the program uses to discover new events from gamepads. Defaults to 10 ms. Reducing the poll rate value could cause the application to use more CPU power so please test the setting that you use before using antimicro unattended. Hide main window when the main window close button is clicked instead of quitting the program. Close To Tray Have Windows start antimicro at system startup. Launch At Windows Startup Windows ã®èµ·å‹•ã¨åŒæ™‚ã«é–‹å§‹ Display recent profiles for all controllers as a single list in the tray menu. Defaults to using sub-menus. Single Profile List in Tray Have the program minimize to the taskbar. By default, the program minimizes to the system tray if available. Minimize to Taskbar タスクãƒãƒ¼ã«å…¥ã‚Œã‚‹ This option will cause the program to hide all buttons that have no slots assigned to them. The Quick Set dialog window will have to be used to bring up the edit dialog for gamepad buttons. Hide Empty Buttons When the program is launched, open the last known profile that was opened during the previous session. Auto Load Last Opened Profile Only show the system tray icon when the program first launches. Launch in Tray Associate .amgp files with antimicro in Windows Explorer. Associate Profiles プロファイルを関連付㑠Key Repeat Active keys will be repeatedly pressed when this option is enabled. Enable 有効 Specifies how much time should elapse before key repeating begins. Specifies how many times key presses will be performed per seconds. <html><head/><body><p>antimicro has been translated into many different languages by contributors. By default, the program will choose an appropriate translation based on your system's locale setting. However, you can make antimicro load a different translation depending on the language that you choose from the list below.</p></body></html> French フランス語 Italian Japanese Russian ロシア語 Serbian セルビア語 Simplified Chinese 中国語 (簡体字) Ukrainian ウクライナ語 Class Title タイトル Program Disable the "Enhanced Pointer Precision" Windows setting while antimicro is running. Disabling "Enhanced Pointer Precision" will allow mouse movement within antimicro to be more precise. Disable Enhance Pointer Precision Smoothing Histor&y Size: Weight &Modifier: Refresh Rate: The refresh rate is the amount of time that will elapse in between mouse events. Please be cautious when editing this setting as it will cause the program to use more CPU power. Setting this value too low can cause system instability. Please test the setting before using it unattended. Spring Screen: スクリーン: Utilize the specified screen for spring mode. On Linux, the default is to use the primary screen. On Windows, the default is to use all available screens. Accel Numerator: 0 0 Accel Denominator: Accel Threshold: If the acceleration values for the virtual mouse have been changed by a different process, particularly when quitting an older game, then you might want to reset the acceleration values used by the virtual mouse. Reset Acceleration Delay: Profi&le Directory: ms Rate: times/s Below is a list of the custom mappings that have been saved. You can use the following table to delete mappings or have mappings temporarily disabled. You can also disable mappings that are included with SDL; just insert a new row with the appropriate joystick GUID and check disable. Settings will not take affect until you either refresh all joysticks or unplug that particular joystick. GUID GUID Mapping String Disable? Delete 削除 Insert Default デフォルト Brazilian Portuguese ãƒãƒ«ãƒˆã‚¬ãƒ«èªž (ブラジル) English 英語 German ドイツ語 Active Devices: デãƒã‚¤ã‚¹: All Device デãƒã‚¤ã‚¹ Profile プロファイル Default? Add 追加 Edit 編集 Also, Windows users who want to use a low value should also check the "Disable Enhance Pointer Precision" checkbox if you haven't disabled the option in Windows. Select Default Profile Directory Are you sure you want to delete the profile? MainWindow antimicro antimicro No Joysticks have been found. Please plug in a joystick and then choose the "Update Joysticks" option in the main menu ジョイスティックãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。 ジョイスティックを接続ã—ã€ãƒ¡ã‚¤ãƒ³ãƒ¡ãƒ‹ãƒ¥ãƒ¼ã®ã€Œã‚¸ãƒ§ã‚¤ã‚¹ãƒ†ã‚£ãƒƒã‚¯ã‚’æ›´æ–°ã€ã‚’é¸æŠžã—ã¦ãã ã•ã„ If events are not seen by a game, please click here to run this application as the Adminstrator. &App &Options オプション(&O) &Help ヘルプ(&H) &Quit 終了(&Q) Ctrl+Q Ctrl+Q &Update Joysticks ジョイスティックを更新(&U) Ctrl+U Ctrl+U &Hide éš ã™(&H) Ctrl+H Ctrl+H &About AntiMicro ã«ã¤ã„ã¦(&A) Ctrl+A Ctrl+A About Qt Qt ã«ã¤ã„㦠Properties プロパティ Key Checker キーãƒã‚§ãƒƒã‚«ãƒ¼ Home Page ホームページ GitHub Page GitHub ページ Game Controller Mapping Settings 設定 Stick/Pad Assign Wiki Could not find a proper controller identifier. Exiting. (%1) (%1) Open File &Restore Run as Administrator? Are you sure that you want to run this program as Adminstrator? Some games run as Administrator which will cause events generated by antimicro to not be used by those games unless antimicro is also run as the Adminstrator. This is due to permission problems caused by User Account Control (UAC) options in Windows Vista and later. Failed to elevate program Failed to restart this program as the Administrator Could not find controller. Exiting. MouseAxisSettingsDialog Mouse Settings - Set %1 セット %1 MouseButtonSettingsDialog Mouse Settings - Set %1 セット %1 MouseControlStickSettingsDialog Mouse Settings マウスã®è¨­å®š Set %1 セット %1 MouseDPadSettingsDialog Mouse Settings マウスã®è¨­å®š Set %1 セット %1 MouseSettingsDialog Mouse Settings マウスã®è¨­å®š Mouse Mode: マウスモード: Cursor mode is used to move the mouse cursor around the screen relative to its current position depending on how much you move an axis or if a button is pressed. Spring mode is used to move the mouse cursor from the center of the screen depending on how much you move an axis. The mouse cursor will be returned to the center of the screen when the axis is moved back to the dead zone. Cursor カーソル Spring Acceleration: 加速: Enhanced Precision Linear Quadratic Cubic Quadratic Extreme Power Function Easing Quadratic Easing Cubic Mouse Speed Settings Enable to change the horizontal and vertical speed boxes at the same time. Change Together Options for adding more acceleration to the mouse movement beyond what the acceleration curve would produce. Acceleration is added based on how quickly an axis is moved in one gamepad poll. This is meant to help work around some of the issues of the very limited input range available using typical gamepad analog sticks. Delta Acceleration &Multiplier: Mi&n Threshold: Horizontal Speed: 水平速度: 1 = 20 pps Vertical Speed: 垂直速度: Wheel Hori. Speed: Set the speed used for horizontal mouse wheel movement according to number of simulated notches per second. Set the speed used for vertical mouse wheel movement according to number of simulated notches per second. Sensitivit&y: For Power Function acceleration curve. Specifies the factor to use for curve sensitivity. When the value is above 1.0, the mouse movement will be accelerated faster at the low end of an axis. Easing Duration: s Highest value to accelerate mouse movement by x x Start %: Acceleration begins at this percentage of the base multiplier Minimum amount of axis travel required for acceleration to begin Max Threshold: Maximum axis travel before acceleration has reached the multiplier value E&xtra Duration: Curve: Ease Out Sine Ease Out Quad Ease Out Cubic Release Radius: Specifies that the spring area will be relative to the mouse position set by a non-relative spring. Relative Mouse Status X: X: 0 (0 pps) Y: Y: 1 = 1 notch(es)/s 1 = 1 ノッãƒ/ç§’ Enhanced: Three tier curve that makes the mouse move slow on the low end of an axis and fast on the high end. Linear: Mouse moves proportionally to axis. Quadratic: Mouse accelerates slowly on low end. Cubic: Mouse accelerates slower than Quadratic. Quadratic Extreme: Raises mouse speed 1.5 times once 95% axis travel has been reached. Power Function: Allows for a more custom curve option. Easing Quadratic: Axis high end is gradually accelerated over a period of time using a Quadratic curve. Easing Cubic: Axis high end is gradually accelerated over a period of time using a Cubic curve. Hori&zontal Speed: &Vertical Speed: Wheel Vert. Speed: Sensitivity: 感度: Specifies the amount of time (in seconds) that will be required before the mouse is fully accelerated after reaching the high end of an axis. % % Extend the time that extra acceleration is applied. Axis travel will be taken into account. A slower flick will decrease the actual time that extra acceleration will be applied. Spring Settings Spring Width: Changes the width of the region that the cursor can move in spring mode. 0 will use the entire width of your screen. Spring Height: Changes the height of the region that the cursor can move in spring mode. 0 will use the entire height of your screen. %n notch(es)/s %n ノッãƒ/ç§’ QKeyDisplayDialog Key Checker キーãƒã‚§ãƒƒã‚«ãƒ¼ <html><head/><body><p>Press a key on your keyboard to see how the key is detected by this application. The window will show the system native key value, the original value given by Qt (if applicable), and the custom value used by antimicro.</p><p>The antimicro key value and the Qt key value will usually be the same. antimicro tries to use the key values defined in Qt when possible. Check the page <a href="https://doc.qt.io/qt-4.8/qt.html#Key-enum"><span style=" text-decoration: underline; color:#0057ae;">https://doc.qt.io/qt-4.8/qt.html#Key-enum</span></a> for a list of values defined by Qt. If you discover that a key is not natively supported by this program, please report the problem to antimicro's <a href="https://github.com/AntiMicro/antimicro"><span style=" text-decoration: underline; color:#0057ae;">GitHub page</span></a> so that the program can be edited to support it directly. As it is, a custom prefix is added to unknown values so they can still be used; the main problem is that the profile will no longer be portable.</p></body></html> Event Handler: イベントãƒãƒ³ãƒ‰ãƒ©: Native Key Value: ãƒã‚¤ãƒ†ã‚£ãƒ–キー値: 0x00000000 0x00000000 Qt Key Value: Qt キー値: antimicro Key Value: antimicro キー値: QObject Super Menu Mute Vol+ Vol- Play/Pause Play Pause Pause Prev Next Mail Home Home Media メディア Search 検索 Daemon launched Failed to launch daemon Launching daemon Display string "%1" is not valid. Failed to set a signature id for the daemon Failed to change working directory to / Quitting Program # of joysticks found: %1 List Joysticks: --------------- Joystick %1: ジョイスティック %1: Index: %1 GUID: %1 GUID: %1 Name: %1 åå‰: %1 Yes ã¯ã„ No ã„ã„㈠Game Controller: %1 ゲームコントローラー: %1 # of Axes: %1 # of Buttons: %1 # of Hats: %1 Attempting to use fallback option %1 for event generation. Failed to open event generator. Exiting. Using %1 as the event generator. Could not raise process priority. QuickSetDialog Quick Set クイックセット <html><head/><body><p>Please press a button or move an axis on %1 (<span style=" font-weight:600;">%2</span>).<br/>A dialog window will then appear which will<br/>allow you to make an assignment.</p></body></html> Quick Set %1 クイックセット %1 SetAxisThrottleDialog Throttle Change The throttle setting for Axis %1 has been changed. Would you like to distribute this throttle change to all sets? SetJoystick Set %1: %2 セット %1: %2 Set %1 セット %1 SetNamesDialog Set Name Settings Set 1 セット 1 Set 2 セット 2 Set 3 セット 3 Set 4 セット 4 Set 5 セット 5 Set 6 セット 6 Set 7 セット 7 Set 8 セット 8 Name SimpleKeyGrabberButton Mouse マウス SpringModeRegionPreview Spring Mode Preview UInputEventHandler Could not find a valid uinput device file. Please check that you have the uinput module loaded. lsmod | grep uinput Could not open uinput device file Please check that you have permission to write to the device Using uinput device file %1 UInputHelper a a b b c c d d e e f f g g h h i i j j k k l l m m n n o o p p q q r r s s t t u u v v w w x x y y z z Esc Esc F1 F1 F2 F2 F3 F3 F4 F4 F5 F5 F6 F6 F7 F7 F8 F8 F9 F9 F10 F10 F11 F11 F12 F12 ` ` 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 0 0 - - = = BackSpace BackSpace Tab Tab [ [ ] ] \ \ CapsLock CapsLock ; ; ' ' Enter Enter Shift_L , , . . / / Ctrl_L Super_L Alt_L Space スペース Alt_R Menu Ctrl_R Shift_R Up ↑ Left ↠Down ↓ Right → PrtSc PrtSc Ins Del Del Home Home End End PgUp PgUp PgDn PgDn NumLock NumLock * * + + KP_Enter KP_1 KP_2 KP_3 KP_4 KP_5 KP_6 KP_7 KP_8 KP_9 KP_0 SCLK Pause Pause Super_R Mute VolDn VolUp Play Stop Prev Next [NO KEY] [割り当ã¦ãªã—] UnixWindowInfoDialog Captured Window Properties Information About Window Class: TextLabel Title: タイトル: Path: Match By Properties Class Title タイトル Path VDPad VDPad VirtualKeyPushButton Space スペース Tab Tab Shift (L) Shift (å·¦) Shift (R) Shift (å³) Ctrl (L) Ctrl (å·¦) Ctrl (R) Ctrl (å³) Alt (L) Alt (å·¦) Alt (R) Alt (å³) ` ` ~ ~ - - = = [ [ ] ] \ \ Caps Caps ; ; ' ' , , . . / / ESC PRTSC SCLK INS PGUP DEL PGDN 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 0 0 NUM LK * * + + E N T E R < < : : Super (L) Menu Up ↑ Down ↓ Left ↠Right → VirtualKeyboardMouseWidget Keyboard キーボード Mouse マウス Mouse Settings マウスã®è¨­å®š Left Mouse ↠Up Mouse ↑ Left Button Mouse 左ボタン Middle Button Mouse 中ボタン Right Button Mouse å³ãƒœã‚¿ãƒ³ Wheel Up Mouse Wheel Left Mouse Wheel Right Mouse Wheel Down Mouse Down Mouse ↓ Right Mouse → Button 4 Mouse ボタン 4 Mouse 8 Mouse マウス 8 Button 5 Mouse ボタン 5 Mouse 9 Mouse マウス 9 NONE 割り当ã¦ãªã— Applications アプリケーション Browser Back ブラウザ: 戻る Browser Favorites ブラウザ: ãŠæ°—ã«å…¥ã‚Š Browser Forward ブラウザ: 進む Browser Home ブラウザ: ホーム Browser Refresh ブラウザ: æ›´æ–° Browser Search ブラウザ: 検索 Browser Stop Calc Email Eメール Media メディア Media Next メディア: 次㸠Media Play メディア: å†ç”Ÿ Media Previous メディア: å‰ã¸ Media Stop メディア: åœæ­¢ Search 検索 Volume Down 音é‡: 下ã’ã‚‹ Volume Mute 音é‡: ミュート Volume Up 音é‡: 上ã’ã‚‹ VirtualMousePushButton INVALID WinAppProfileTimerDialog Capture Application After pressing the "Capture Application" button, please select the application window that you want to have a profile associated with. The active application will be captured after the selected number of seconds. Timer: タイマー: Seconds ç§’ Cancel キャンセル WinExtras [NO KEY] [割り当ã¦ãªã—] AntiMicro Profile AntiMicro プロファイル X11Extras ESC Tab Tab Space スペース DEL Return KP_Enter Backspace Backspace xinput extension was not found. No mouse acceleration changes will occur. xinput version must be at least 2.0. No mouse acceleration changes will occur. Virtual pointer found with id=%1. PtrFeedbackClass was not found for virtual pointer.No change to mouse acceleration will occur for device with id=%1 Changing mouse acceleration for device with id=%1 XMLConfigReader Could not write updated profile XML to file %1. XMLConfigWriter Could not write to profile at %1. antimicro-2.23/share/antimicro/translations/antimicro_ru.ts000066400000000000000000011625011300750276700243150ustar00rootroot00000000000000 AboutDialog About О программе Version ВерÑÐ¸Ñ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Originally developed by Travis Nickles &lt;nickles.travis@gmail.com&gt;, now maintained by the AntiMicro group at https://github.com/AntiMicro.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Contributors:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;"><br /></span>Zerro Alvein</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">aybe</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jeff Backus &lt;jeff.backus@gmail.com&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Arthur Moore<br />Anton Tornqvist &lt;antont@inbox.lv&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7185</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">DarkStarSword</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">est31</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ProfessorKaos64</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">qwerty12</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA0</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Translators:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VaGNaroK &lt;vagnarokalkimist@gmail.com&gt; - Brazilian Portuguese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx - Chinese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Belleguic Terence &lt;hizo@free.fr&gt; - French</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Leonard Koenig &lt;leonard.r.koenig@googlemail.com&gt; - German</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phob - German</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">tou omiya - Japanese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Dmitriy Koshel &lt;form.eater@gmail.com&gt; - Russian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jay Alexander Fleming &lt;tito.nehru.naser@gmail.com&gt; - Serbian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">burunduk - Ukrainian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Flavio HR &lt;flavio.hrx@gmail.com&gt; - Spanish</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA - wazaaaaa00&lt;@&gt;gmail&lt;.&gt;com - Italian</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> Info Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Changelog Since December 30, 2012, I have been working on antimicro in my spare time. What originally started as a fork of QJoyPad and a way to learn proper event-driven programming has turned into something much bigger than I originally intended. Although I have spent a lot of time learning new techniques, finding out more about the domain of KB+M emulation, and spending Friday nights bashing my head against my keyboard, it has been a fun and enriching experience overall. The need for this program came from me using similar programs on Windows to play several games that did not provide native controller support. Although some alternatives existed on Linux, there wasn't really anything that I felt was good enough in terms of functionality or in-game controls in order to really enjoy games that I wanted to play with using KB+M emulation. QJoyPad was the main program that I had used in the past although it had aged a lot and it didn't provide some basic functionality that I thought was essential. The project was dead as it had not been updated in several years so I decided to make my own. Since then, I have tried to find out what the other programs do right and then improve upon it. I have also discovered some neat tricks along the way and I have learned more about how native gamepad controls are implemented in some games than I ever really wanted to know. Although there are definitely areas where this program could improve, I find that this program offers the best in-game control experience for playing older, and some newer, games that do not provide native controller support. Development of this program is not as high of a priority for me anymore. This is mainly due to the fact that the Steam Controller works pretty well for the task of playing PC games compared to using an Xbox 360 controller. However, it does look like there is still a reason for this program to exist for a while. Copyright: 2013 - 2016 Credits Ðвторы antimicro <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">GNU GENERAL PUBLIC LICENSE</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Version 3, 29 June 2007</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Preamble</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Developers that use the GNU GPL protect your rights with two steps:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">(1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The precise terms and conditions for copying, distribution and modification follow.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">TERMS AND CONDITIONS</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">0. Definitions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;This License&quot; refers to version 3 of the GNU General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Copyright&quot; also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;The Program&quot; refers to any copyrightable work licensed under this License. Each licensee is addressed as &quot;you&quot;. &quot;Licensees&quot; and &quot;recipients&quot; may be individuals or organizations.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;modify&quot; a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a &quot;modified version&quot; of the earlier work or a work &quot;based on&quot; the earlier work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;covered work&quot; means either the unmodified Program or a work based on the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;propagate&quot; a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;convey&quot; a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An interactive user interface displays &quot;Appropriate Legal Notices&quot; to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">1. Source Code.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;source code&quot; for a work means the preferred form of the work for making modifications to it. &quot;Object code&quot; means any non-source form of a work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;Standard Interface&quot; means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;System Libraries&quot; of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A &quot;Major Component&quot;, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;Corresponding Source&quot; for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source for a work in source code form is that same work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">2. Basic Permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">3. Protecting Users' Legal Rights From Anti-Circumvention Law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">4. Conveying Verbatim Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">5. Conveying Modified Source Versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) The work must carry prominent notices stating that you modified it, and giving a relevant date.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to &quot;keep intact all notices&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an &quot;aggregate&quot; if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">6. Conveying Non-Source Forms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;User Product&quot; is either (1) a &quot;consumer product&quot;, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, &quot;normally used&quot; refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Installation Information&quot; for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">7. Additional Terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Additional permissions&quot; are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Limiting the use for publicity purposes of names of licensors or authors of the material; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All other non-permissive additional terms are considered &quot;further restrictions&quot; within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">8. Termination.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">9. Acceptance Not Required for Having Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">10. Automatic Licensing of Downstream Recipients.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An &quot;entity transaction&quot; is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">11. Patents.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;contributor&quot; is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's &quot;contributor version&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A contributor's &quot;essential patent claims&quot; are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, &quot;control&quot; includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">In the following three paragraphs, a &quot;patent license&quot; is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To &quot;grant&quot; such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. &quot;Knowingly relying&quot; means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A patent license is &quot;discriminatory&quot; if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">12. No Surrender of Others' Freedom.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">13. Use with the GNU Affero General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">14. Revised Versions of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License &quot;or any later version&quot; applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">15. Disclaimer of Warranty.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM &quot;AS IS&quot; WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">16. Limitation of Liability.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">17. Interpretation of Sections 15 and 16.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.</span></p></body></html> About Development License Ð›Ð¸Ñ†ÐµÐ½Ð·Ð¸Ñ Program Version %1 ВерÑÐ¸Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ñ‹ %1 Program Compiled on %1 at %2 Программа Ñкомпилирована %1 в %2 Built Against SDL %1 Собрана на SDL %1 Running With SDL %1 ЗапуÑкаетÑÑ Ð½Ð° SDL %1 Using Qt %1 ВерÑÐ¸Ñ Qt %1 Using Event Handler: %1 AddEditAutoProfileDialog Auto Profile Dialog Окно Ðвто ÐŸÑ€Ð¾Ñ„Ð¸Ð»Ñ Profile: Профиль: Browse Обзор Window: Select Window. Click on the appropriate application window and the application file path will be populated in the form. Кликните по нужному окну Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ñ‡Ñ‚Ð¾Ð±Ñ‹ автоматичеÑки добавить путь до него в форму. Detect Window Properties Class: Title: Application: Select Выбор Devices: УÑтройÑтва: Select this profile to be the default loaded for the specified device. The selection will be used instead of the all default profile option. Выберите профиль, который будет автоматичеÑки загружатьÑÑ Ð´Ð»Ñ Ð²Ñ‹Ð±Ñ€Ð°Ð½Ð½Ð¾Ð³Ð¾ уÑтройÑтва. Выбранный профиль загрузитÑÑ Ð´Ð°Ð¶Ðµ еÑли выбран профиль по-умолчанию. Set as Default for Controller УÑтановить по-умолчанию Ð´Ð»Ñ Ñтого контроллера A different profile is already selected as the default for this device. Ð”Ð»Ñ Ñтого контроллера уже назначен профиль по-умолчанию. Current (%1) Текущий (%1) Open Config Открыть Конфигурацию Select Program Выбрать Программу Programs (*.exe) Please use the main default profile selection. ПожалуйÑта, иÑпользуйте оÑновной профиль по-умолчанию. Please select a window by using the mouse. Press Escape if you want to cancel. Capture Application Window Could not obtain information for the selected window. Application Capture Failed Profile file path is invalid. Ðеверный путь до профилÑ. No window matching property was specified. Program path is invalid or not executable. Путь до программы Ñодержит ошибку или не может быть выполнен. File is not an .exe file. No window matching property was selected. AdvanceButtonDialog Advanced Продвинутые наÑтройки Assignments ÐÐ°Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Toggle Переключатель Turbo Турбо Set Selector УÑтановить Селектор Blank or KB/M Hold Удерживать Pause Пауза Cycle Цикл Distance ДиÑÑ‚Ð°Ð½Ñ†Ð¸Ñ Insert Ð’Ñтавить Delete Удалить Clear All ОчиÑтить Ð’Ñе Time: ВремÑ: 0.01s 0,01 Ñек 0s 0 Ñек Insert a pause that occurs in between key presses. Ð’Ñтавить паузу между нажатиÑми на кнопку. Release ОтпуÑкание Insert a new blank slot. Ð’Ñтавить новый пуÑтой Ñлот. Delete a slot. Удалить Ñлот. Clear all currently assigned slots. ОчиÑтить вÑе заполненные Ñлоты. Specify the duration of an inserted Pause or Hold slot. ОпределÑет продолжительноÑть Ð´Ð»Ñ Ñлотов Пауза и Удерживание. 0m 0 мин &Mouse Speed Mod: Specify the range past an axis dead zone in which a sequence of actions will execute. ОпределÑет диапазон оÑи Ð´Ð»Ñ Ð¼ÐµÑ€Ñ‚Ð²Ð¾Ð¹ зоны в котором Ñледует выполнÑть дейÑтвиÑ. Distance: ДиÑтанциÑ: % % Mouse Mod СкороÑть Мыши Press Time Ð’Ñ€ÐµÐ¼Ñ ÐÐ°Ð¶Ð°Ñ‚Ð¸Ñ Delay Задержка Execute Load Загрузить Set Change Text Entry Placeholder Заполнитель 0 0 Mouse Speed Mod: Модификатор СкороÑти Мыши: Set the percentage that mouse speeds will be modified by. ОпределÑет в процентах на Ñколько должна быть изменена ÑкороÑть мыши. Auto Reset Cycle After ÐвтоматичеÑки ÑброÑить цикл поÑле seconds Ñекунд Executable: ... Arguments: Enabled Включено Mode: <html><head/><body><p>Normal: Repeatedly press and release a button by the chosen rate.</p><p>Gradient: Modify the button press and button release delay based on how far an axis has been moved. The rate will remain the same.</p><p>Pulse: Modify how many times a button is pressed and released per second. The button delay will remain the same.</p></body></html> Normal Ðормально Gradient Pulse Delay: Задержка: 0.10s 0,10 Ñек Rate: ЧаÑтота: 10.0/s 10,0/Ñек Disabled Отключено Select Set 1 One Way УÑтановить Ðабор 1 ОдноÑторонним Select Set 1 Two Way УÑтановить Ðабор 1 ДвуÑторонним Select Set 1 While Held УÑтановить Ðабор 1 Пока Ðажато Select Set 2 One Way УÑтановить Ðабор 2 ОдноÑторонним Select Set 2 Two Way УÑтановить Ðабор 2 ДвуÑторонним Select Set 2 While Held УÑтановить Ðабор 2 Пока Ðажато Select Set 3 One Way УÑтановить Ðабор 3 ОдноÑторонним Select Set 3 Two Way УÑтановить Ðабор 3 ДвуÑторонним Select Set 3 While Held УÑтановить Ðабор 3 Пока Ðажато Select Set 4 One Way УÑтановить Ðабор 4 ОдноÑторонним Select Set 4 Two Way УÑтановить Ðабор 4 ДвуÑторонним Select Set 4 While Held УÑтановить Ðабор 4 Пока Ðажато Select Set 5 One Way УÑтановить Ðабор 5 ОдноÑторонним Select Set 5 Two Way УÑтановить Ðабор 5 ДвуÑторонним Select Set 5 While Held УÑтановить Ðабор 5 Пока Ðажато Select Set 6 One Way УÑтановить Ðабор 6 ОдноÑторонним Select Set 6 Two Way УÑтановить Ðабор 6 ДвуÑторонним Select Set 6 While Held УÑтановить Ðабор 6 Пока Ðажато Select Set 7 One Way УÑтановить Ðабор 7 ОдноÑторонним Select Set 7 Two Way УÑтановить Ðабор 7 ДвуÑторонним Select Set 7 While Held УÑтановить Ðабор 7 Пока Ðажато Select Set 8 One Way УÑтановить Ðабор 8 ОдноÑторонним Select Set 8 Two Way УÑтановить Ðабор 8 ДвуÑторонним Select Set 8 While Held УÑтановить Ðабор 8 Пока Ðажато sec. Ñек. /sec. /Ñек. Set %1 Ðабор %1 Select Set %1 УÑтановить Ðабор %1 One Way ОдноÑторонним Two Way ДвуÑторонним While Held Пока Ðажато Choose Executable Slots past a Cycle action will be executed on the next button press. Multiple cycles can be added in order to create partitions in a sequence. Delays the time that the next slot is activated by the time specified. Slots activated before the delay will remain active after the delay time has passed. Distance action specifies that the slots afterwards will only be executed when an axis is moved a certain range past the designated dead zone. Insert a hold action. Slots after the action will only be executed if the button is held past the interval specified. Chose a profile to load when this slot is activated. Mouse mod action will modify all mouse speed settings by a specified percentage while the action is being processed. This can be useful for slowing down the mouse while sniping. Specify the time that keys past this slot should be held down. Insert a release action. Slots after the action will only be executed after a button release if the button was held past the interval specified. Change to selected set once slot is activated. Full string will be typed when a slot is activated. Execute program when slot is activated. Choose Profile Config Files (*.amgp *.xml) AdvanceStickAssignmentDialog Stick/Pad Assignment ÐаÑтройки Стиков / КреÑтовин Sticks Стики DPads КреÑтовины %1 (Joystick %2) %1 (Геймпад %2) Stick 1 Стик 1 Enabled Включено Assign Ðазначить X Axis: ОÑÑŒ X: Y Axis: ОÑÑŒ Y: Stick 2 Стик 2 Number of Physical DPads: %1 КоличеÑтво физичеÑких креÑтовин: %1 Virtual DPad 1 Ð’Ð¸Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð°Ñ ÐšÑ€ÐµÑтовина 1 Up: Вверх: Down: Вниз: Note: This window is meant for backwards compatibility with profiles made before antimicro 2.0. Since version 2.0, use of the Game Controller Mapping window is preferred. Left: Влево: Right: Вправо: Axis %1 ОÑÑŒ %1 Axis %1 - ОÑÑŒ %1 - Axis %1 + ОÑÑŒ %1 + Button %1 Кнопка %1 Move stick 1 along the X axis ПеремеÑтите Cтик 1 по оÑи X Move stick 1 along the Y axis ПеремеÑтите Cтик 1 по оÑи Y Move stick 2 along the X axis ПеремеÑтите Cтик 2 по оÑи X Move stick 2 along the Y axis ПеремеÑтите Cтик 2 по оÑи Y Press a button or move an axis Ðажмите кнопку или подвигайте Ñтик AxisEditDialog Axis ОÑÑŒ Mouse (Horizontal) Мышь (горизонталь) Mouse (Inverted Horizontal) Мышь (Ð¸Ð½Ð²ÐµÑ€Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ð³Ð¾Ñ€Ð¸Ð·Ð¾Ð½Ñ‚Ð°Ð»ÑŒ) Mouse (Vertical) Мышь (вертикаль) Mouse (Inverted Vertical) Мышь (Ð¸Ð½Ð²ÐµÑ€Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ð²ÐµÑ€Ñ‚Ð¸ÐºÐ°Ð»ÑŒ) Arrows: Up | Down Стрелки: Вверх | Вниз Arrows: Left | Right Стрелки: Влево | Вправо Keys: W | S Клавиши: W | S Keys: A | D Клавиши: A | D NumPad: KP_8 | KP_2 NumPad: 8 | 2 NumPad: KP_4 | KP_6 NumPad: 4 | 6 None ОтÑутÑтвует Set the value to use as the limit for an axis. Useful for a worn out analog stick. Negative Half Throttle ÐžÑ‚Ñ€Ð¸Ñ†Ð°Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ ÐŸÐ¾Ð»ÑƒÑ‚Ñга Positive Half Throttle ÐŸÐ¾Ð»Ð¾Ð¶Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ ÐŸÐ¾Ð»ÑƒÑ‚Ñга Name: ИмÑ: Specify the name of an axis. Укажите Ð¸Ð¼Ñ Ð´Ð»Ñ Ð¾Ñи. Mouse Settings ÐаÑтройки Мыши Set the value of the dead zone for an axis. УÑтанавливает значение мертвой зоны Ð´Ð»Ñ Ð¾Ñи. Presets: ПреÑет: Dead Zone: ÐœÐµÑ€Ñ‚Ð²Ð°Ñ Ð—Ð¾Ð½Ð°: Max Zone: Лимит: [NO KEY] [ПУСТО] Throttle setting that determines the behavior of how to interpret an axis hold or release. ÐаÑтройки Ñ‚Ñги определÑÑŽÑ‚ как программа будет раÑценивать удерживание или отпуÑкание оÑи. Negative Throttle ÐžÑ‚Ñ€Ð¸Ñ†Ð°Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ð¢Ñга Normal Ðормально Positive Throttle ÐŸÐ¾Ð»Ð¾Ð¶Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ð¢Ñга Current Value: Текущее значение: Set УÑтановки Ð´Ð»Ñ Set %1 Ðабор %1 Left Mouse Button Right Mouse Button ButtonEditDialog Dialog Окно To make a new assignment, press any keyboard key or click a button in the Keyboard or Mouse tab <center>Чтобы назначить новое дейÑтвие нажмите на ÑоответÑтвующую кнопку во вкладках "Клавиатура" или "Мышь"</center> Placeholder Заполнитель Toggle Переключатель Enables a key press or release to only occur when a controller button is pressed. ДобавлÑет возможноÑть производить дейÑтвие только в Ñлучае Ð½Ð°Ð¶Ð°Ñ‚Ð¸Ñ Ð¸Ð»Ð¸ отпуÑÐºÐ°Ð½Ð¸Ñ ÐºÐ½Ð¾Ð¿ÐºÐ¸. Enables rapid key presses and releases. Turbo controller. ДобавлÑет возможноÑть быÑтрого Ð½Ð°Ð¶Ð°Ñ‚Ð¸Ñ ÐºÐ½Ð¾Ð¿Ð¾Ðº (как в турбо контроллере). Turbo Турбо Current: ТекущаÑ: Slots Слоты Na&me: Specify the name of a button. Укажите название кнопки. Action: ДейÑтвие: Specify the action that will be performed in game while this button is being used. Укажите какое дейÑтвие будет производитÑÑ Ð¿Ñ€Ð¸ нажатии данной кнопки. Advanced Дополнительно Set УÑтановки Ð´Ð»Ñ Set %1 Ðабор %1 CapturedWindowInfoDialog Captured Window Properties Information About Window Class: TextLabel Title: Path: Match By Properties Class Title Path Full Path File Name CommandLineUtility Profile location %1 is not an XML file. Профиль, находÑщийÑÑ Ð² %1 не ÑвлÑетÑÑ XML файлом. Profile location %1 does not exist. Профиль, находÑщийÑÑ Ð² %1 не ÑущеÑтвует. An invalid set number '%1' was specified. Controller identifier '%s'' is not a valid value. No display string was specified. Ðе указана Ñтрока Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ. Controller identifier is not a valid value. Идентификатор контроллера имеет недопуÑтимое значение. No set number was specified. Ðе указан набор значений. No controller was specified. An invalid event generator was specified. No event generator string was specified. Qt style flag was detected but no style was specified. No log level specified. antimicro version Usage: antimicro [options...] [profile] Options Опции Print help text. Показать текÑÑ‚ помощи. Print version information. Показать информацию о верÑии. Launch program in system tray only. ЗапуÑкать программу только в ÑиÑтемном трее. Launch program with the tray menu disabled. ЗапуÑтить программу Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ‹Ð¼ меню треÑ. Launch program without the main window displayed. ЗапуÑкать программу без Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð³Ð»Ð°Ð²Ð½Ð¾Ð³Ð¾ окна. Launch program with the configuration file selected as the default for selected controllers. Defaults to all controllers. ЗапуÑкать программу Ñ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ñ‹Ð¼ файлом, назначенным по-умолчанию Ð´Ð»Ñ Ð²Ñ‹Ð±Ñ€Ð°Ð½Ð½Ñ‹Ñ… контроллеров. ÐаÑтройки контроллеров будут выÑтавлены по-умолчанию. Apply configuration file to a specific controller. Value can be a controller index, name, or GUID. Применить файл конфигурации Ð´Ð»Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð½Ñ‹Ñ… контроллеров. ЗначениÑми могут быть Ð¸Ð½Ð´ÐµÐºÑ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»Ð»ÐµÑ€Ð°, Ð¸Ð¼Ñ Ð¸Ð»Ð¸ GUID. Unload currently enabled profile(s). Value can be a controller index, name, or GUID. Загрузить текущие активные профили. ЗначениÑми могут быть Ð¸Ð½Ð´ÐµÐºÑ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»Ð»ÐµÑ€Ð°, Ð¸Ð¼Ñ Ð¸Ð»Ð¸ GUID. Start joysticks on a specific set. Value can be a controller index, name, or GUID. ЗапуÑкать геймпады на определнном наборе. ЗначениÑми могут быть Ð¸Ð½Ð´ÐµÐºÑ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»Ð»ÐµÑ€Ð°, Ð¸Ð¼Ñ Ð¸Ð»Ð¸ GUID. Advance profile loading set options. Launch program as a daemon. ЗапуÑкать программу в качеÑтве демона. Enable logging. Use specified display for X11 calls. Useful for ssh. Choose between using XTest support and uinput support for event generation. Default: xtest. Choose between using SendInput and vmulti support for event generation. Default: sendinput. Print information about joysticks detected by SDL. Open game controller mapping window of selected controller. Value can be a controller index or GUID. DPadContextMenu Mouse (Normal) Мышь (Ðормально) Mouse (Inverted Horizontal) Mouse (Inverted Vertical) Mouse (Inverted Horizontal + Vertical) Arrows Стрелки Keys: W | A | S | D Клавиши: W | A | S | D NumPad NumPad None ОтÑутÑтвует Standard Стандартный Eight Way 8-ми Ñторонний 4 Way Cardinal 4-Ñ… Ñторонний оÑновной 4 Way Diagonal 4-Ñ… Ñторонний диагональный Mouse Settings DPadEditDialog Dialog Окно Presets: ПреÑет: Mouse (Normal) Мышь (Ðормально) Mouse (Inverted Horizontal) Мышь (Ð˜Ð½Ð²ÐµÑ€Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ð“Ð¾Ñ€Ð¸Ð·Ð¾Ð½Ñ‚Ð°Ð»ÑŒ) Mouse (Inverted Vertical) Мышь (Ð˜Ð½Ð²ÐµÑ€Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ð’ÐµÑ€Ñ‚Ð¸ÐºÐ°Ð»ÑŒ) Mouse (Inverted Horizontal + Vertical) Мышь (Ð˜Ð½Ð²ÐµÑ€Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ð“Ð¾Ñ€Ð¸Ð·Ð¾Ð½Ñ‚Ð°Ð»ÑŒ + Вертикаль) Arrows Стрелки Keys: W | A | S | D Клавиши: W | A | S | D NumPad NumPad None ОтÑутÑтвует Dpad Mode: Режим КреÑтовины: &Name: 4 Way Cardinal 4-Ñ… Ñторонний оÑновной 4 Way Diagonal 4-Ñ… Ñторонний диагональный DPad Delay: Time lapsed before a direction change is taken into effect. s Specify the name of a dpad. Укажите Ð¸Ð¼Ñ Ð´Ð»Ñ ÐºÑ€ÐµÑтовины. Mouse Settings ÐаÑтройки Мыши Standard Стандартный Standard: 8 region dpad with two direction buttons active when the dpad is in a diagonal region. Eight Way: 8 region dpad with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region dpad with regions corresponding to the cardinal directions of the dpad. Useful for menus. 4 Way Diagonal: 4 region dpad with each region corresponding to a diagonal zone. Eight Way 8-ми Ñторонний Set УÑтановки Ð´Ð»Ñ Set %1 Ðабор %1 EditAllDefaultAutoProfileDialog Default Profile Профиль По-Умолчанию Profile: Профиль: Browse Обзор Open Config Открыть Конфигурацию Profile file path is invalid. Путь до Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ñ Ð½ÐµÐ²ÐµÑ€ÐµÐ½. ExtraProfileSettingsDialog Extra Profile Settings Дополнительные наÑтройки Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ñ Key Press Time: Отклик Клавиш: 0.00 ms 0,00 Ð¼Ñ Profile Name: Ð˜Ð¼Ñ ÐŸÑ€Ð¾Ñ„Ð¸Ð»Ñ: s Ñек GameController Game Controller Геймпад GameControllerDPad DPad КреÑтовина GameControllerMappingDialog Game Controller Mapping ÐаÑтройка Игрового Контроллера <html><head/><body><p>antimicro makes use of the <a href="https://wiki.libsdl.org/CategoryGameController"><span style=" text-decoration: underline; color:#0057ae;">Game Controller API</span></a> provided by SDL 2 in order to abstract various gamepads to fit a unified standard. In order to make a button assignment, please highlight the mapping cell for the appropriate button row below. You can then press a button or move an axis on your gamepad and the cell will update with the physical button or axis that will be used.</p><p>antimicro will use the mapping that you specify to save a mapping string that will be loaded into SDL.</p></body></html> A A B B X X Y Y Back Back Start Start Guide Guide Left Shoulder Левый Бампер Right Shoulder Правый Бампер Left Stick Click Кнопка Левого Стика Right Stick Click Кнопка Правого Стика Left Stick X ОÑÑŒ X Левого Стика Left Stick Y ОÑÑŒ Y Левого Стика Right Stick X ОÑÑŒ X Правого Стика Right Stick Y ОÑÑŒ Y Правого Стика Left Trigger Левый Триггер Right Trigger Правый Триггер DPad Up КреÑтовина Вверх DPad Left КреÑтовина Влево DPad Down КреÑтовина Вниз DPad Right КреÑтовина Вправо Mapping ÐаÑтройка SDL 2 Game Controller Mapping String Вывод наÑтройщика контроллеров SDL 2 Last Axis Event: Current Axis Detection Dead Zone: 5000 5000 10000 10000 15000 15000 20000 20000 25000 25000 30000 30000 32000 32000 Game Controller Mapping (%1) (#%2) Discard Controller Mapping? СброÑить наÑтройки контроллера? Discard mapping for this controller? If discarded, the controller will be reverted to a joystick once you refresh all joysticks. СброÑить наÑтройки Ð´Ð»Ñ Ñтого контроллера? ЕÑли ÑброÑить наÑтройки, контроллер вернетÑÑ Ðº Ñвоему изначальному ÑоÑтоÑнию поÑле Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð²Ñех геймпадов. GameControllerSet Back Back Guide Guide Start Start LS Click RS Click L Shoulder R Shoulder L Trigger R Trigger GameControllerTrigger Trigger Триггер JoyAxis Axis ОÑÑŒ JoyAxisButton Negative Отрицательно Positive Положительно Unknown ÐеизвеÑтно Button Кнопка JoyAxisContextMenu Mouse (Horizontal) Мышь (горизонталь) Mouse (Inverted Horizontal) Mouse (Vertical) Мышь (вертикаль) Mouse (Inverted Vertical) Arrows: Up | Down Стрелки: Вверх | Вниз Arrows: Left | Right Стрелки: Влево | Вправо Keys: W | S Клавиши: W | S Keys: A | D Клавиши: A | D NumPad: KP_8 | KP_2 NumPad: 8 | 2 NumPad: KP_4 | KP_6 NumPad: 4 | 6 None ОтÑутÑтвует Mouse Settings Left Mouse Button Right Mouse Button JoyButton Processing turbo for #%1 - %2 Finishing turbo for button #%1 - %2 Processing press for button #%1 - %2 Processing release for button #%1 - %2 Distance change for button #%1 - %2 Button Кнопка [NO KEY] [ПУСТО] [Set %1 1W] [Set %1 2W] [Set %1 WH] JoyButtonContextMenu Toggle Переключатель Turbo Турбо Clear Set Select Disabled Отключено Set %1 Set %1 1W Ðабор %1 1W Set %1 2W Ðабор %1 2W Set %1 WH JoyButtonSlot Mouse Мышь Up Вверх Down Вниз Left Влево Right Вправо LB LB MB MB RB RB B4 B4 B5 B5 Pause Пауза Hold Удерживание Cycle Цикл Distance ДиÑÑ‚Ð°Ð½Ñ†Ð¸Ñ Release ОтпуÑкание Mouse Mod СкороÑть Мыши Press Time Ð’Ñ€ÐµÐ¼Ñ ÐÐ°Ð¶Ð°Ñ‚Ð¸Ñ Delay Задержка Load %1 Set Change %1 [Text] %1 [Exec] %1 [NO KEY] [ПУСТО] JoyControlStick Stick Стик JoyControlStickButton Up Вверх Down Вниз Left Влево Right Вправо Button Кнопка JoyControlStickContextMenu Mouse (Normal) Мышь (Ðормально) Mouse (Inverted Horizontal) Mouse (Inverted Vertical) Mouse (Inverted Horizontal + Vertical) Arrows Стрелки Keys: W | A | S | D Клавиши: W | A | S | D NumPad NumPad None ОтÑутÑтвует Standard Стандартный Eight Way 8-ми Ñторонний 4 Way Cardinal 4-Ñ… Ñторонний оÑновной 4 Way Diagonal 4-Ñ… Ñторонний диагональный Mouse Settings JoyControlStickEditDialog Dialog Окно X: Ð¥: 0 0 Y: Y: Distance: ДиÑтанциÑ: Presets: ПреÑет: Mouse (Normal) Мышь (Ðормально) Mouse (Inverted Horizontal) Мышь (Ð¸Ð½Ð²ÐµÑ€Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ð³Ð¾Ñ€Ð¸Ð·Ð¾Ð½Ñ‚Ð°Ð»ÑŒ) Mouse (Inverted Vertical) Мышь (Ð¸Ð½Ð²ÐµÑ€Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ð²ÐµÑ€Ñ‚Ð¸ÐºÐ°Ð»ÑŒ) Mouse (Inverted Horizontal + Vertical) Мышь (Ð¸Ð½Ð²ÐµÑ€Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ð³Ð¾Ñ€Ð¸Ð·Ð¾Ð½Ñ‚Ð°Ð»ÑŒ + вертикаль) Arrows Стрелки Keys: W | A | S | D Клавиши: W | A | S | D NumPad NumPad None ОтÑутÑтвует Stick Mode: Режим Стика: Standard: 8 region stick with two direction buttons active when the stick is in a diagonal region. Eight Way: 8 region stick with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region stick with regions corresponding to the cardinal directions of the stick. Useful for menus. 4 Way Diagonal: 4 region stick with each region corresponding to a diagonal zone of the stick. 4 Way Cardinal 4-Ñ… Ñторонний оÑновной 4 Way Diagonal 4-Ñ… Ñторонний диагональный Dead zone value to use for an analog stick. Value when an analog stick is considered moved 100%. The area (in degrees) that each diagonal region occupies. Square Stick: Percentage to modify a square stick coordinates to confine values to a circle % % Stick Delay: Time lapsed before a direction change is taken into effect. s Modifier: Edit button that is active while the stick is active. This button is useful for assigning zones with modifier keys that can be used to assign walk/run functionality to an analog stick. PushButton Name: ИмÑ: Specify the name of an analog stick. Укажите Ð¸Ð¼Ñ Ð´Ð»Ñ Ð°Ð½Ð°Ð»Ð¾Ð³Ð¾Ð²Ð¾Ð³Ð¾ Ñтика. Mouse Settings ÐаÑтройки Мыши Standard Стандартный Bearing: Точка Опоры: % Safe Zone: % ограничениÑ: Eight Way 8-ми Ñторонний Dead Zone: ÐœÐµÑ€Ñ‚Ð²Ð°Ñ Ð—Ð¾Ð½Ð°: Max Zone: Лимит: Diagonal Range: Диагональный диапазон: Set УÑтановки Ð´Ð»Ñ Set %1 УÑтановки Ð´Ð»Ñ %1 JoyControlStickModifierButton Modifier JoyDPad DPad КреÑтовина JoyDPadButton Up Вверх Down Вниз Left Влево Right Вправо Button Кнопка JoyTabWidget <New> <Ðовый> Remove Удалить Remove configuration from recent list. Удалить конфигурацию из ÑпиÑка недавно иÑпользованных файлов. Load Загрузить Load configuration file. Загрузить файл конфигурации. Save Сохранить Save changes to configuration file. Сохранить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² файл конфигурации. Save As Сохранить Как Save changes to a new configuration file. Сохранить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² новый файл конфигурации. Sets Ðаборы Copy from Set Settings ÐаÑтройки Set 1 Ðабор 1 Set 2 Ðабор 2 Set 3 Ðабор 3 Set 4 Ðабор 4 Set 5 Ðабор 5 Set 6 Ðабор 6 Set 7 Ðабор 7 Set 8 Ðабор 8 Stick/Pad Assign ÐаÑтройка Стиков/КреÑтровин Controller Mapping ÐаÑтройка Контроллера Quick Set БыÑÑ‚Ñ€Ð°Ñ ÐаÑтройка Names Бирки Toggle button name displaying. Вкл. / Выкл. отображение названий команд на кнопках. Pref ÐаÑтройки ÐŸÑ€Ð¾Ñ„Ð¸Ð»Ñ Change global profile settings. Изменить общие наÑтройки профилÑ. Reset Ð¡Ð±Ñ€Ð¾Ñ Revert changes to the configuration. Reload configuration file. ОтменÑет Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ ÐºÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ð¸. Перезагружает конфигурационный файл. Open Config Открыть Конфигурацию Config Files (*.amgp *.xml) Config File (*.%1.amgp) Save Profile Changes? Сохранить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² профиле? Changes to the new profile have not been saved. Would you like to save or discard the current profile? Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² новом профиле не были Ñохранены. Сохранить или отменить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² текущем профиле? Changes to the profile "%1" have not been saved. Would you like to save or discard changes to the current profile? Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² профиле "%1" не были Ñохранены. Сохранить или отменить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² текущем профиле? Sticks Стики DPads КреÑтовины No buttons have been assigned. Please use Quick Set to assign keys to buttons or disable hiding empty buttons. <center>Ðе было назначено ни одной кнопки. ВоÑпользуйтеÑÑŒ "БыÑтрой ÐаÑтройкой" <br>Ð´Ð»Ñ Ð½Ð°Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ ÐºÐ½Ð¾Ð¿Ð¾Ðº или отключите Ñокрытие пуÑтых кнопок.</center> Set %1: %2 Ðабор %1: %2 Set %1 Ðабор %1 Copy Set Assignments Скопировать Ðабор ÐаÑтроек Are you sure you want to copy the assignments and device properties from %1? Ð’Ñ‹ уверены что хотите Ñкопировать наÑтройки и параметры уÑтройÑтва из %1? Save Config Сохранить Конфигурацию Set Ðабор Joystick Joystick Геймпад JoystickStatusWindow Properties СвойÑтва Details Детали Name: ИмÑ: %1 %1 Number: Ðомер: Axes: ОÑей: Buttons: Кнопок: Hats: Мини-джойÑтиков: GUID: GUID: Game Controller: Axes ОÑи Buttons Кнопки Hats Мини-джойÑтики %1 (#%2) Properties %1 (#%2) СвойÑтва Axis %1 ОÑÑŒ %1 Hat %1 Мини-джойÑтик %1 No Yes MainSettingsDialog Edit Settings Редактировать наÑтройки General Общие Controller Mappings ÐаÑтройки Контроллера Language Язык Auto Profile ÐвтоПрофиль Mouse Мышь <html><head/><body><p>Specify the default directory that the program should use in file dialogs when loading a profile or saving a new profile.</p></body></html> <html><head/><body><p>Укажите путь до директории, которую программа будет иÑпользовать Ð´Ð»Ñ Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ñ„Ð¸Ð»ÐµÐ¹.</p></body></html> Recent Profile Count: КоличеÑтво недавних профилей: <html><head/><body><p>Number of profiles that can be placed in recent profile list. 0 will result in the program not enforcing a limit on the number of profiles displayed.</p></body></html> <html><head/><body><p>КоличеÑтво профилей, которые будут хранитÑÑ Ð² ÑпиÑке недавних. ЕÑли выÑтавить "0" то программа не будет ограничивать количеÑтво отображаемых профилей.</p></body></html> Gamepad Poll Rate: Change the poll rate that the program uses to discover new events from gamepads. Defaults to 10 ms. Reducing the poll rate value could cause the application to use more CPU power so please test the setting that you use before using antimicro unattended. Hide main window when the main window close button is clicked instead of quitting the program. ПрÑтать главное окно программы по нажатию на кнопку выхода вмеÑто того чтобы закрывать программу. Close To Tray Сворачивать в трей Have Windows start antimicro at system startup. Launch At Windows Startup Загружать вмеÑте Ñ Windows Display recent profiles for all controllers as a single list in the tray menu. Defaults to using sub-menus. Отображает недавно открытые профили Ð´Ð»Ñ Ð²Ñех контроллеров в виде единого ÑпиÑка под иконкой в трее. По-умолчанию иÑпользует подменю. Single Profile List in Tray Единый лиÑÑ‚ профилей в трее Have the program minimize to the taskbar. By default, the program minimizes to the system tray if available. ЗаÑтавлÑет программу ÑворачиватÑÑ Ð² панель задач. По-умолчанию программа ÑворачиваетÑÑ Ð² ÑиÑтемный трей. Minimize to Taskbar Сворачивать в панель задач This option will cause the program to hide all buttons that have no slots assigned to them. The Quick Set dialog window will have to be used to bring up the edit dialog for gamepad buttons. Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð·Ð°Ñтавит программу Ñкрывать вÑе кнопки, к которым не привÑзаны Ñлоты Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°Ð¼Ð¸. ВоÑпользуйтеÑÑŒ окном "БыÑтрой ÐаÑтройки" Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ñкрытых кнопок. Hide Empty Buttons Скрыть пуÑтые кнопки When the program is launched, open the last known profile that was opened during the previous session. Когда программа запуÑтитÑÑ, будет открыт поÑледний профиль, иÑпользованный в предыдущей ÑеÑÑии. Auto Load Last Opened Profile ÐвтоматичеÑки загружать поÑледний открытый профиль Only show the system tray icon when the program first launches. При запуÑке программы поÑвитÑÑ Ð»Ð¸ÑˆÑŒ значок в ÑиÑтемном трее. Launch in Tray ЗапуÑкатьÑÑ Ð² Ñвернутом виде Associate .amgp files with antimicro in Windows Explorer. Associate Profiles Key Repeat Повтор клавиш Active keys will be repeatedly pressed when this option is enabled. ЕÑли активировать данную опцию то активные клавиши будут нажиматьÑÑ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑки. Enable Specifies how much time should elapse before key repeating begins. Specifies how many times key presses will be performed per seconds. <html><head/><body><p>antimicro has been translated into many different languages by contributors. By default, the program will choose an appropriate translation based on your system's locale setting. However, you can make antimicro load a different translation depending on the language that you choose from the list below.</p></body></html> French Italian Japanese Russian Serbian Simplified Chinese Ukrainian Class Title Program Disable the "Enhanced Pointer Precision" Windows setting while antimicro is running. Disabling "Enhanced Pointer Precision" will allow mouse movement within antimicro to be more precise. Disable Enhance Pointer Precision Smoothing Histor&y Size: Weight &Modifier: Refresh Rate: The refresh rate is the amount of time that will elapse in between mouse events. Please be cautious when editing this setting as it will cause the program to use more CPU power. Setting this value too low can cause system instability. Please test the setting before using it unattended. Spring Пружина Screen: Utilize the specified screen for spring mode. On Linux, the default is to use the primary screen. On Windows, the default is to use all available screens. Accel Numerator: 0 0 Accel Denominator: Accel Threshold: If the acceleration values for the virtual mouse have been changed by a different process, particularly when quitting an older game, then you might want to reset the acceleration values used by the virtual mouse. Reset Acceleration Delay: Задержка: Profi&le Directory: ms Ð¼Ñ Rate: ЧаÑтота: times/s раз/Ñек Below is a list of the custom mappings that have been saved. You can use the following table to delete mappings or have mappings temporarily disabled. You can also disable mappings that are included with SDL; just insert a new row with the appropriate joystick GUID and check disable. Settings will not take affect until you either refresh all joysticks or unplug that particular joystick. Ðиже приведен Ñохраненный ÑпиÑок из пользовательÑких наÑтроек. Ð’Ñ‹ можете иÑпользовать Ñту таблицу, чтобы удалÑть наÑтройки или же временно их отключать. Также Ð’Ñ‹ можете отключить наÑтройки, входÑщие в SDL - проÑто добавьте новую Ñтроку Ñ ÑоответÑтвующим GUID геймпада и активируйте Ñ‡ÐµÐºÐ±Ð¾ÐºÑ "Отключить" Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð½Ðµ вÑтупÑÑ‚ в Ñилу пока вы не обновите или переподключите вÑе геймпады. GUID GUID Mapping String Строка ÐаÑтроек Disable? Отключить? Delete Удалить Insert Ð’Ñтавить Default По-умолчанию Brazilian Portuguese БразильÑкий / ПортугальÑкий English ÐнглийÑкий German Ðемецкий Active Ðктивировать Devices: УÑтройÑтва: All Ð’Ñе Device УÑтройÑтво Profile Профиль Default? По-умолчанию? Add Добавить Edit Редактировать Also, Windows users who want to use a low value should also check the "Disable Enhance Pointer Precision" checkbox if you haven't disabled the option in Windows. Select Default Profile Directory Выбрать как профиль по-умолчанию Are you sure you want to delete the profile? Ð’Ñ‹ уверены что хотите удалить Ñтот профиль? MainWindow antimicro No Joysticks have been found. Please plug in a joystick and then choose the "Update Joysticks" option in the main menu Геймпады не обнаружены. ПожалуйÑта, подключите геймпад к компьютеру и выберете опцию "Обновить Геймпады" из главного меню. If events are not seen by a game, please click here to run this application as the Adminstrator. &App &Приложение &Options &Опции &Help &Помощь &Quit &Выход Ctrl+Q Ctrl+Q &Update Joysticks &Обновить Геймпады Ctrl+U Ctrl+U &Hide &Скрыть Ctrl+H Ctrl+H &About &О программе Ctrl+A Ctrl+A About Qt О Qt Properties СвойÑтва Key Checker Проверка Клавиш Home Page ДомашнÑÑ Ñтраница GitHub Page Страница на GitHub Game Controller Mapping ÐаÑтройки Игрового Контроллера Settings ÐаÑтройки Stick/Pad Assign ÐаÑтройки Стиков / КреÑтовин Wiki Could not find a proper controller identifier. Exiting. (%1) (%1) Open File Открыть файл &Restore &ВоÑÑтановить Run as Administrator? Are you sure that you want to run this program as Adminstrator? Some games run as Administrator which will cause events generated by antimicro to not be used by those games unless antimicro is also run as the Adminstrator. This is due to permission problems caused by User Account Control (UAC) options in Windows Vista and later. Failed to elevate program Failed to restart this program as the Administrator Could not find controller. Exiting. MouseAxisSettingsDialog Mouse Settings - ÐаÑтройки Мыши - Set %1 УÑтановки Ð´Ð»Ñ %1 MouseButtonSettingsDialog Mouse Settings - ÐаÑтройки Мыши - Set %1 УÑтановки Ð´Ð»Ñ %1 MouseControlStickSettingsDialog Mouse Settings ÐаÑтройки Мыши Set %1 УÑтановки Ð´Ð»Ñ %1 MouseDPadSettingsDialog Mouse Settings ÐаÑтройки Мыши Set %1 УÑтановки Ð´Ð»Ñ %1 MouseSettingsDialog Mouse Settings ÐаÑтройки Мыши Mouse Mode: Режим Мыши: Cursor mode is used to move the mouse cursor around the screen relative to its current position depending on how much you move an axis or if a button is pressed. Spring mode is used to move the mouse cursor from the center of the screen depending on how much you move an axis. The mouse cursor will be returned to the center of the screen when the axis is moved back to the dead zone. Режим КурÑора иÑпользуетÑÑ Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ ÐºÑƒÑ€Ñора мыши по Ñкрану по отношению к текущей позиции в завиÑимоÑти от того, наÑколько вы перемеÑтили оÑÑŒ, или при нажатии кнопки. Режим Пружины иÑпользуетÑÑ Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ ÐºÑƒÑ€Ñора мыши от центра Ñкрана в завиÑимоÑти от того, наÑколько вы перемеÑтили оÑÑŒ. КурÑор мыши будет возвращен в центр Ñкрана, когда оÑÑŒ перемеÑтитÑÑ Ð¾Ð±Ñ€Ð°Ñ‚Ð½Ð¾ к мертвой зоне. Cursor КурÑор Spring Пружина Acceleration: УÑиление: Enhanced Precision Ð£Ð»ÑƒÑ‡ÑˆÐµÐ½Ð½Ð°Ñ Ð¢Ð¾Ñ‡Ð½Ð¾Ñть Linear Линейное Quadratic Квадратное Cubic КубичеÑкое Quadratic Extreme ЭкÑтримально КубичеÑкое Power Function Ð¡Ñ‚ÐµÐ¿ÐµÐ½Ð½Ð°Ñ Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Easing Quadratic Easing Cubic Mouse Speed Settings ÐаÑтройки ÑкороÑти мыши Enable to change the horizontal and vertical speed boxes at the same time. ПозволÑет увеличивать ÑкороÑть мыши по горизонтали и вертикали одновременно. Change Together ИзменÑть ÑовмеÑтно Options for adding more acceleration to the mouse movement beyond what the acceleration curve would produce. Acceleration is added based on how quickly an axis is moved in one gamepad poll. This is meant to help work around some of the issues of the very limited input range available using typical gamepad analog sticks. Delta Acceleration &Multiplier: Mi&n Threshold: Horizontal Speed: СкороÑть по горизонтали: 1 = 20 pps 1 = 20 pps Vertical Speed: СкороÑть по вертикали: Wheel Hori. Speed: СкороÑть колеÑика по горизонтали: Set the speed used for horizontal mouse wheel movement according to number of simulated notches per second. УÑтанавливает ÑкороÑть Ð´Ð²Ð¸Ð¶ÐµÐ½Ð¸Ñ ÐºÐ¾Ð»ÐµÑика мыши по горизонтали. Set the speed used for vertical mouse wheel movement according to number of simulated notches per second. УÑтанавливает ÑкороÑть Ð´Ð²Ð¸Ð¶ÐµÐ½Ð¸Ñ ÐºÐ¾Ð»ÐµÑика мыши по вертикали. Sensitivit&y: For Power Function acceleration curve. Specifies the factor to use for curve sensitivity. When the value is above 1.0, the mouse movement will be accelerated faster at the low end of an axis. Easing Duration: s Highest value to accelerate mouse movement by x x Start %: Acceleration begins at this percentage of the base multiplier Minimum amount of axis travel required for acceleration to begin Max Threshold: Maximum axis travel before acceleration has reached the multiplier value E&xtra Duration: Curve: Ease Out Sine Ease Out Quad Ease Out Cubic Release Radius: Specifies that the spring area will be relative to the mouse position set by a non-relative spring. ПривÑзывает пружину к позиции мыши. Relative ПривÑзка Mouse Status X: Ð¥: 0 (0 pps) Y: Y: 1 = 1 notch(es)/s 1 = 1 шаг(ов)/Ñек Enhanced: Three tier curve that makes the mouse move slow on the low end of an axis and fast on the high end. Linear: Mouse moves proportionally to axis. Quadratic: Mouse accelerates slowly on low end. Cubic: Mouse accelerates slower than Quadratic. Quadratic Extreme: Raises mouse speed 1.5 times once 95% axis travel has been reached. Power Function: Allows for a more custom curve option. Easing Quadratic: Axis high end is gradually accelerated over a period of time using a Quadratic curve. Easing Cubic: Axis high end is gradually accelerated over a period of time using a Cubic curve. Hori&zontal Speed: &Vertical Speed: Wheel Vert. Speed: СкороÑть колеÑика по вертикали: Sensitivity: ЧувÑтвительноÑть: Specifies the amount of time (in seconds) that will be required before the mouse is fully accelerated after reaching the high end of an axis. % % Extend the time that extra acceleration is applied. Axis travel will be taken into account. A slower flick will decrease the actual time that extra acceleration will be applied. Spring Settings ÐаÑтройки Пружины Spring Width: Ширина Пружины: Changes the width of the region that the cursor can move in spring mode. 0 will use the entire width of your screen. ИзменÑет ширину облаÑти, по которой будет двигатьÑÑ ÐºÑƒÑ€Ñор в режиме Пружины. ЕÑли выÑтавить "0" будет иÑпользоватьÑÑ Ð²ÑÑ ÑˆÐ¸Ñ€Ð¸Ð½Ð° Ñкрана. Spring Height: Ð’Ñ‹Ñота Пружины: Changes the height of the region that the cursor can move in spring mode. 0 will use the entire height of your screen. ИзменÑет выÑоту облаÑти, по которой будет двигатьÑÑ ÐºÑƒÑ€Ñор в режиме Пружины. ЕÑли выÑтавить "0" будет иÑпользоватьÑÑ Ð²ÑÑ Ð²Ñ‹Ñота Ñкрана. %n notch(es)/s %n шаг/Ñек %n шагов/Ñек %n шаг(ов)/Ñек QKeyDisplayDialog Key Checker Проверка Клавиш <html><head/><body><p>Press a key on your keyboard to see how the key is detected by this application. The window will show the system native key value, the original value given by Qt (if applicable), and the custom value used by antimicro.</p><p>The antimicro key value and the Qt key value will usually be the same. antimicro tries to use the key values defined in Qt when possible. Check the page <a href="https://doc.qt.io/qt-4.8/qt.html#Key-enum"><span style=" text-decoration: underline; color:#0057ae;">https://doc.qt.io/qt-4.8/qt.html#Key-enum</span></a> for a list of values defined by Qt. If you discover that a key is not natively supported by this program, please report the problem to antimicro's <a href="https://github.com/AntiMicro/antimicro"><span style=" text-decoration: underline; color:#0057ae;">GitHub page</span></a> so that the program can be edited to support it directly. As it is, a custom prefix is added to unknown values so they can still be used; the main problem is that the profile will no longer be portable.</p></body></html> Event Handler: Native Key Value: Родное Значение Клавиши: 0x00000000 0x00000000 Qt Key Value: Значение Клавиши в Qt: antimicro Key Value: QObject Super Super Menu Меню Mute Vol+ Vol- Play/Pause Play Pause Пауза Prev Next Next Mail Home Home Media Search Daemon launched Демон запущен Failed to launch daemon Ðе удалоÑÑŒ запуÑтить демон Launching daemon Демон запуÑкаетÑÑ Display string "%1" is not valid. Failed to set a signature id for the daemon Ðе удалоÑÑŒ подпиÑать демон Failed to change working directory to / Ðе удалоÑÑŒ менить рабочую директорию на "/" Quitting Program # of joysticks found: %1 List Joysticks: --------------- Joystick %1: Index: %1 GUID: %1 Name: %1 Yes No Game Controller: %1 # of Axes: %1 # of Buttons: %1 # of Hats: %1 Attempting to use fallback option %1 for event generation. Failed to open event generator. Exiting. Using %1 as the event generator. Could not raise process priority. QuickSetDialog Quick Set БыÑÑ‚Ñ€Ð°Ñ Ð½Ð°Ñтройка <html><head/><body><p>Please press a button or move an axis on %1 (<span style=" font-weight:600;">%2</span>).<br/>A dialog window will then appear which will<br/>allow you to make an assignment.</p></body></html> <html><head/><body><p>ПожалуйÑта, нажмите кнопку или подвигайте Ñтик на %1 (<span style=" font-weight:600;">%2</span>).<br/>ПоÑвитÑÑ Ð¾ÐºÐ½Ð¾, которое позволит вам назначить кнопку.</p></body></html> Quick Set %1 БыÑÑ‚Ñ€Ð°Ñ ÐаÑтройка %1 SetAxisThrottleDialog Throttle Change Смена ТÑги The throttle setting for Axis %1 has been changed. Would you like to distribute this throttle change to all sets? ÐаÑтройки Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ñ Ð´Ð»Ñ ÐžÑи %1 были изменены. Желаете применить Ñти наÑтройки ко вÑем наборам? SetJoystick Set %1: %2 Ðабор %1: %2 Set %1 Ðабор %1 SetNamesDialog Set Name Settings УÑтановить имена Ð´Ð»Ñ Ð½Ð°Ð±Ð¾Ñ€Ð¾Ð² Set 1 Ðабор 1 Set 2 Ðабор 2 Set 3 Ðабор 3 Set 4 Ðабор 4 Set 5 Ðабор 5 Set 6 Ðабор 6 Set 7 Ðабор 7 Set 8 Ðабор 8 Name Ð˜Ð¼Ñ SimpleKeyGrabberButton Mouse Мышь SpringModeRegionPreview Spring Mode Preview ПредпроÑмотр Режима Пружины UInputEventHandler Could not find a valid uinput device file. Please check that you have the uinput module loaded. lsmod | grep uinput Could not open uinput device file Please check that you have permission to write to the device Using uinput device file %1 UInputHelper a a b b c c d d e e f f g g h h i i j j k k l l m m n n o o p p q q r r s Ñек t t u u v v w w x x y y z z Esc F1 F1 F2 F2 F3 F3 F4 F4 F5 F5 F6 F6 F7 F7 F8 F8 F9 F9 F10 F10 F11 F11 F12 F12 ` ` 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 0 0 - - = = BackSpace BackSpace Tab Tab [ [ ] ] \ \ CapsLock ; ; ' ' Enter Shift_L Shift_L , , . . / / Ctrl_L Super_L Super_L Alt_L Alt_L Space Пробел Alt_R Alt_R Menu Меню Ctrl_R Shift_R Shift_R Up Left Down Right PrtSc Ins Del Home Home End End PgUp PgDn NumLock * * + + KP_Enter KP_Enter KP_1 KP_1 KP_2 KP_2 KP_3 KP_3 KP_4 KP_4 KP_5 KP_5 KP_6 KP_6 KP_7 KP_7 KP_8 KP_8 KP_9 KP_9 KP_0 KP_0 SCLK SCLK Pause Пауза Super_R Mute VolDn VolUp Play Stop Prev Next Next [NO KEY] [ПУСТО] UnixWindowInfoDialog Captured Window Properties Information About Window Class: TextLabel Title: Path: Match By Properties Class Title Path VDPad VDPad Ð’Ð¸Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð°Ñ ÐšÑ€ÐµÑтовина VirtualKeyPushButton Space Пробел Tab Tab Shift (L) Shift (Л) Shift (R) Shift (П) Ctrl (L) Ctrl (Л) Ctrl (R) Ctrl (П) Alt (L) Alt (Л) Alt (R) Alt (П) ` ` ~ ~ - - = = [ [ ] ] \ \ Caps Caps ; ; ' ' , , . . / / ESC ESC PRTSC PRTSC SCLK SCLK INS INS PGUP PGUP DEL DEL PGDN PGDN 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 0 0 NUM LK NUM * * + + E N T E R E N T E R < < : : Super (L) Super Menu Меню Up Вверх Down Вниз Left Влево Right Вправо VirtualKeyboardMouseWidget Keyboard Клавиатура Mouse Мышь Mouse Settings Ðаcтройка Мыши Left Mouse Left Up Mouse Up Left Button Mouse Left Button Middle Button Mouse Middle Button Right Button Mouse Right Button Wheel Up Mouse Wheel Up Wheel Left Mouse Wheel Left Wheel Right Mouse Wheel Right Wheel Down Mouse Wheel Down Down Mouse Down Right Mouse Right Button 4 Mouse Button 4 Mouse 8 Mouse Mouse 8 Button 5 Mouse Button 5 Mouse 9 Mouse Mouse 9 NONE ПУСТО Applications Browser Back Browser Favorites Browser Forward Browser Home Browser Refresh Browser Search Browser Stop Calc Email Media Media Next Media Play Media Previous Media Stop Search Volume Down Volume Mute Volume Up VirtualMousePushButton INVALID ОШИБКРWinAppProfileTimerDialog Capture Application Звхватить Приложение After pressing the "Capture Application" button, please select the application window that you want to have a profile associated with. The active application will be captured after the selected number of seconds. ПоÑле Ð½Ð°Ð¶Ð°Ñ‚Ð¸Ñ Ð½Ð° кнопку "Захватить Приложение" кликните по приложению Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ð¼ хотите аÑÑоциировать данный профиль. Ðктивное приложение будет захвачено поÑле выбранного количеÑтва Ñекунд. Timer: Таймер: Seconds Секунды Cancel Отмена WinExtras [NO KEY] [ПУСТО] AntiMicro Profile X11Extras ESC ESC Tab Tab Space Пробел DEL DEL Return Return KP_Enter KP_Enter Backspace Backspace xinput extension was not found. No mouse acceleration changes will occur. xinput version must be at least 2.0. No mouse acceleration changes will occur. Virtual pointer found with id=%1. PtrFeedbackClass was not found for virtual pointer.No change to mouse acceleration will occur for device with id=%1 Changing mouse acceleration for device with id=%1 XMLConfigReader Could not write updated profile XML to file %1. XMLConfigWriter Could not write to profile at %1. antimicro-2.23/share/antimicro/translations/antimicro_sr.ts000066400000000000000000012374331300750276700243220ustar00rootroot00000000000000 AboutDialog About О програму Version Издање <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Originally developed by Travis Nickles &lt;nickles.travis@gmail.com&gt;, now maintained by the AntiMicro group at https://github.com/AntiMicro.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Contributors:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;"><br /></span>Zerro Alvein</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">aybe</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jeff Backus &lt;jeff.backus@gmail.com&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Arthur Moore<br />Anton Tornqvist &lt;antont@inbox.lv&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7185</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">DarkStarSword</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">est31</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ProfessorKaos64</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">qwerty12</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA0</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Translators:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VaGNaroK &lt;vagnarokalkimist@gmail.com&gt; - Brazilian Portuguese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx - Chinese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Belleguic Terence &lt;hizo@free.fr&gt; - French</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Leonard Koenig &lt;leonard.r.koenig@googlemail.com&gt; - German</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phob - German</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">tou omiya - Japanese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Dmitriy Koshel &lt;form.eater@gmail.com&gt; - Russian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jay Alexander Fleming &lt;tito.nehru.naser@gmail.com&gt; - Serbian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">burunduk - Ukrainian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Flavio HR &lt;flavio.hrx@gmail.com&gt; - Spanish</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA - wazaaaaa00&lt;@&gt;gmail&lt;.&gt;com - Italian</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> Info Подаци Changelog Дневник измена Since December 30, 2012, I have been working on antimicro in my spare time. What originally started as a fork of QJoyPad and a way to learn proper event-driven programming has turned into something much bigger than I originally intended. Although I have spent a lot of time learning new techniques, finding out more about the domain of KB+M emulation, and spending Friday nights bashing my head against my keyboard, it has been a fun and enriching experience overall. The need for this program came from me using similar programs on Windows to play several games that did not provide native controller support. Although some alternatives existed on Linux, there wasn't really anything that I felt was good enough in terms of functionality or in-game controls in order to really enjoy games that I wanted to play with using KB+M emulation. QJoyPad was the main program that I had used in the past although it had aged a lot and it didn't provide some basic functionality that I thought was essential. The project was dead as it had not been updated in several years so I decided to make my own. Since then, I have tried to find out what the other programs do right and then improve upon it. I have also discovered some neat tricks along the way and I have learned more about how native gamepad controls are implemented in some games than I ever really wanted to know. Although there are definitely areas where this program could improve, I find that this program offers the best in-game control experience for playing older, and some newer, games that do not provide native controller support. Development of this program is not as high of a priority for me anymore. This is mainly due to the fact that the Steam Controller works pretty well for the task of playing PC games compared to using an Xbox 360 controller. However, it does look like there is still a reason for this program to exist for a while. Copyright: 2013 - 2016 ÐуторÑка права: 2013 - 2016. {2013 ?} Since December 30, 2012, I have been working on antimicro in my spare time. What originally started as a fork of QJoyPad and a way to learn proper event-driven programming has turned into something much bigger than I originally intended. Although I have spent a lot of time learning new techniques, finding out more about the domain of KB+M emulation, and spending Friday nights bashing my head against my keyboard, it has been a fun and enriching experience overall. The need for this program came from me using similar programs on Windows to play several games that did not provide native controller support. Although some alternatives existed on Linux, there wasn't really anything that I felt was good enough in terms of functionality or in-game controls in order to really enjoy games that I wanted to play with using KB+M emulation. QJoyPad was the main program that I had used in the past although it had aged a lot and it didn't provide some basic functionality that I thought was essential. The project was dead as it had not been updated in several years so I decided to make my own. Since then, I have tried to find out what the other programs do right and then improve upon it. I have also discovered some neat tricks along the way and I have learned more about how native gamepad controls are implemented in some games than I ever really wanted to know. Although there are definitely areas where this program could improve, I find that this program offers the best in-game control experience for playing older, and some newer, games that do not provide native controller support. Once the Steam controller is finally released to the public, the need for this program might not exist anymore. Just based on the concept of the controller alone, the Steam controller would have so many advantages over using a program like this to provide KB+M emulation. Од 30. децембра 2012. године, Ñтварао Ñам Ðнти-микро у Ñвоје Ñлободно време. Оно што је првобитно започето као верзија програма КЈу-Ðој-Пед (енг. „QJoyPad“) и начин да Ñе научи правилно програмирање управљано догађајима, претворило Ñе у нешто много веће од оне моје првобитна намере. Иако Ñам провео доÑта времена учећи нове технике, Ñазнавајући више о Ñимулацији таÑтатуре и миша, те проводећи петак увече разбијајући главу о моју таÑтатуру, било је забавно ово радити Ñвеукупно обогаћујући ÑопÑтвено иÑкуÑтво. Програм Ñам Ñтворио јер није било природне подршке за контролере код неких игара као код Ñличних програма на Виндоузу. Иако Ñу поÑтојали Ñлични програми на Гну/ЛинукÑу, није било оних који би, по мени, били довољно добри у ÑмиÑлу функционалноÑти или у играма које Ñам желео да играм Ñа употребљавајући Ñимулацију таÑтатуре и миша. КЈу-Ðој-Пед је био оÑновни програм који Ñам кориÑтио раније, али он Ñе предуго није развијао и није пружао неке оÑновне функционалноÑти за које Ñам веровао да Ñу од ÑуштинÑког значаја. Како Ñе КЈу-Ðој-Пед није развијао већ неколико година одлучио Ñам да направим Ñвој. Од тада, покушавао Ñам да откријем оно што други програми раде ваљано и да то онда унапредим и побољшам. УÑпут, открио Ñам неке лепе фазоне и научио више него што Ñам икада желео да знам о унутрашњим контролама гејмпеда и њиховој изведби у неким играма. Иако Ñе у неким облаÑтима овај програм и даље може унапређивати, Ñматрам да нуди најбоље иÑкуÑтво у-контролама игара код играње Ñтаријих, а неки новијих игара које Ñаме не обезбеђују природну подршку за контролер. Овај Ñе програм, највероватније, неће даље развијати, када Ñе званично појави програм Стим-контролер. Управо заÑнован на идеји Ñамог контролера, Стим-контролер ће имати толико предноÑти у одноÑу на друге програме који обезбеђују Ñимулацију таÑтатуре и миша. Copyright: 2013 - 2016 ÐуторÑка права: 2013 - 2016. Credits ЗаÑлуге antimicro Ðнти-микро <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">GNU GENERAL PUBLIC LICENSE</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Version 3, 29 June 2007</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Preamble</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Developers that use the GNU GPL protect your rights with two steps:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">(1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The precise terms and conditions for copying, distribution and modification follow.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">TERMS AND CONDITIONS</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">0. Definitions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;This License&quot; refers to version 3 of the GNU General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Copyright&quot; also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;The Program&quot; refers to any copyrightable work licensed under this License. Each licensee is addressed as &quot;you&quot;. &quot;Licensees&quot; and &quot;recipients&quot; may be individuals or organizations.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;modify&quot; a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a &quot;modified version&quot; of the earlier work or a work &quot;based on&quot; the earlier work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;covered work&quot; means either the unmodified Program or a work based on the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;propagate&quot; a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;convey&quot; a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An interactive user interface displays &quot;Appropriate Legal Notices&quot; to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">1. Source Code.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;source code&quot; for a work means the preferred form of the work for making modifications to it. &quot;Object code&quot; means any non-source form of a work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;Standard Interface&quot; means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;System Libraries&quot; of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A &quot;Major Component&quot;, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;Corresponding Source&quot; for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source for a work in source code form is that same work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">2. Basic Permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">3. Protecting Users' Legal Rights From Anti-Circumvention Law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">4. Conveying Verbatim Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">5. Conveying Modified Source Versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) The work must carry prominent notices stating that you modified it, and giving a relevant date.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to &quot;keep intact all notices&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an &quot;aggregate&quot; if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">6. Conveying Non-Source Forms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;User Product&quot; is either (1) a &quot;consumer product&quot;, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, &quot;normally used&quot; refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Installation Information&quot; for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">7. Additional Terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Additional permissions&quot; are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Limiting the use for publicity purposes of names of licensors or authors of the material; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All other non-permissive additional terms are considered &quot;further restrictions&quot; within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">8. Termination.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">9. Acceptance Not Required for Having Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">10. Automatic Licensing of Downstream Recipients.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An &quot;entity transaction&quot; is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">11. Patents.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;contributor&quot; is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's &quot;contributor version&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A contributor's &quot;essential patent claims&quot; are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, &quot;control&quot; includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">In the following three paragraphs, a &quot;patent license&quot; is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To &quot;grant&quot; such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. &quot;Knowingly relying&quot; means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A patent license is &quot;discriminatory&quot; if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">12. No Surrender of Others' Freedom.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">13. Use with the GNU Affero General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">14. Revised Versions of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License &quot;or any later version&quot; applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">15. Disclaimer of Warranty.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM &quot;AS IS&quot; WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">16. Limitation of Liability.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">17. Interpretation of Sections 15 and 16.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.</span></p></body></html> About Development О развоју програма License Лиценца Program Version %1 Издање програма %1 Program Compiled on %1 at %2 ПрограмÑки код је превођен дана %1 у %2 Built Against SDL %1 Изграђен помоћу СДЛ %1 Running With SDL %1 Употребљава СДЛ %1 Using Qt %1 Уз КјуТ-библиотеке %1 Using Event Handler: %1 Употребљава руковаоца догађајима („Event Handler“) : %1 AddEditAutoProfileDialog Auto Profile Dialog СамоÑтално профилиÑање Profile: Профил: Browse Разгледај Window: Прозор: Select Window. Click on the appropriate application window and the application file path will be populated in the form. Одабир прозора — ПритиÑком на одговарајући прозор програма у обраÑцу Ñе попуњава путања до датотеке програма. Detect Window Properties Сам откриј оÑобине прозора Class: КлаÑа: Title: ÐаÑлов: Application: Програм: Select Одабери Devices: Уређаји: Select this profile to be the default loaded for the specified device. The selection will be used instead of the all default profile option. Подразумевано поÑтавља овај профил за дати уређај. Овај избор ће Ñе кориÑтити умеÑто Ñвеопштих опција профила. Set as Default for Controller ПоÑтави као подразумевано за контролер A different profile is already selected as the default for this device. За овај уређај је већ одабран други подразумевани профил. Current (%1) Текући (%1) Open Config Отвори подешавања Select Program Одабери програм Programs (*.exe) Програми (*.exe) Please use the main default profile selection. КориÑтите главни избор подразумеваног профила. Please select a window by using the mouse. Press Escape if you want to cancel. Одабирајте прозор употребом миша, а поништите одабир таÑтером <Esc>. Capture Application Window Разоткривање графичког Ñучеља програма Could not obtain information for the selected window. Ðе могу да добавим податке о одабраном прозору. Application Capture Failed Ðије уÑпело разоткривање програма Profile file path is invalid. Путања до датотеке профила није ваљана. No window matching property was specified. Ðије била одређена одговарајућа оÑобина прозора. Program path is invalid or not executable. Путања до програма није ваљана или није извршна. File is not an .exe file. Ово није извршна датотека. No window matching property was selected. Ðије била одабрана одговарајућа оÑобина прозора. AdvanceButtonDialog Advanced Ðапредно Assignments Придруживања Toggle Преклопник Turbo Ðабуџи Set Selector Изборник Ñкупа Blank or KB/M Празно или „ТаÑÑ‚./Миш“ Hold Држи Pause Пауза Cycle Врти Distance Раздаљина Insert Уметни Delete Уклони Clear All Уклони Ñве Time: Време: 0.01s 0,01 Ñек 0s 0 Ñек Insert a pause that occurs in between key presses. Време између притиÑка два притиÑка дугмета. Release ПуÑти Insert a new blank slot. УнеÑи нов, празан Ñлот. Delete a slot. Уклони Ñлот. Clear all currently assigned slots. Уклони Ñве већ придружене Ñлотове. Specify the duration of an inserted Pause or Hold slot. Одређивање трајања за већ унет Пауза/Држи Ñлот. 0m 0 мин &Mouse Speed Mod: Specify the range past an axis dead zone in which a sequence of actions will execute. ПоÑтавите облаÑÑ‚ изван мртве облаÑти правца, у којој ће Ñе извршити низ радњи. Distance: Раздаљина: % % Mouse Mod Мишар Press Time Трајање притиÑка Delay Кашњење Execute Изврши Load Учитај Set Change Измени Ñкуп Text Entry Ð£Ð½Ð¾Ñ Ñ‚ÐµÐºÑта Placeholder Препознавач положаја 0 0 Mouse Speed Mod: Брзина Мишара: Set the percentage that mouse speeds will be modified by. ПоÑтавите промену брзине померања миша у процентима. Auto Reset Cycle After Самопоништавање „вртње“ након seconds Ñекунди Executable: ... ... Arguments: Enabled Омогућено Mode: Режим: <html><head/><body><p>Normal: Repeatedly press and release a button by the chosen rate.</p><p>Gradient: Modify the button press and button release delay based on how far an axis has been moved. The rate will remain the same.</p><p>Pulse: Modify how many times a button is pressed and released per second. The button delay will remain the same.</p></body></html> <html><head/><body><p>Обично: УзаÑтопно притиÑкање-пуштање дугмета одабраном брзином.</p><p>ПоÑтепено: Измена кашњења код притиÑка-пуштања дугмета заÑновано на померају оÑног раÑтојањ. Брзина оÑтаје неизмењена.</p><p>ИмпулÑно: Измена броја притиÑака-пуштања дугмета по Ñекунди. Кашњење оÑтаје неизмењено.</p></body></html> Normal Обично Gradient ПоÑтепено Pulse ИмпулÑно Delay: Кашњење: 0.10s 0,10 Ñек Rate: Брзина: 10.0/s 10,0/Ñек Disabled Онемогућено Select Set 1 One Way Изабери 1. Ñкуп, једноÑмерно Select Set 1 Two Way Изабери 1. Ñкуп, двоÑмерно Select Set 1 While Held Изабери 1. Ñкуп, док држим Select Set 2 One Way Изабери 2. Ñкуп, једноÑмерно Select Set 2 Two Way Изабери 2. Ñкуп, двоÑмерно Select Set 2 While Held Изабери 2. Ñкуп, док држим Select Set 3 One Way Изабери 3. Ñкуп, једноÑмерно Select Set 3 Two Way Изабери 3. Ñкуп, двоÑмерно Select Set 3 While Held Изабери 3. Ñкуп, док држим Select Set 4 One Way Изабери 4. Ñкуп, једноÑмерно Select Set 4 Two Way Изабери 4. Ñкуп, двоÑмерно Select Set 4 While Held Изабери 4. Ñкуп, док држим Select Set 5 One Way Изабери 5. Ñкуп, једноÑмерно Select Set 5 Two Way Изабери 5. Ñкуп, двоÑмерно Select Set 5 While Held Изабери 5. Ñкуп, док држим Select Set 6 One Way Изабери 6. Ñкуп, једноÑмерно Select Set 6 Two Way Изабери 6. Ñкуп, двоÑмерно Select Set 6 While Held Изабери 6. Ñкуп, док држим Select Set 7 One Way Изабери 7. Ñкуп, једноÑмерно Select Set 7 Two Way Изабери 7. Ñкуп, двоÑмерно Select Set 7 While Held Изабери 7. Ñкуп, док држим Select Set 8 One Way Изабери 8. Ñкуп, једноÑмерно Select Set 8 Two Way Изабери 8. Ñкуп, двоÑмерно Select Set 8 While Held Изабери 8. Ñкуп, док држим sec. Ñек. /sec. /Ñек. Set %1 Скуп %1 Select Set %1 Одабери %1. Ñкуп One Way ЈедноÑмерно Two Way ДвоÑмерно While Held Док држим Choose Executable Избор извршне датотеке Slots past a Cycle action will be executed on the next button press. Multiple cycles can be added in order to create partitions in a sequence. Слотови изван „вртње“ ће Ñе извршити по наредном притиÑку таÑтера. ВишеÑтруке „вртње“ Ñе могу додавати код Ñтварање делова једног низа. Delays the time that the next slot is activated by the time specified. Slots activated before the delay will remain active after the delay time has passed. Покретање наредног Ñлота биће одложено за наведено време.Слотови покренути пре овог одлагања ће оÑтати покренути и по његовом иÑтеку. Distance action specifies that the slots afterwards will only be executed when an axis is moved a certain range past the designated dead zone. Овом Ñе радњом одређује да накнадни Ñлотови могу да Ñе изврше Ñамо када Ñе нека оÑа помери за одређени опÑег изван дате мртве облаÑти. Insert a hold action. Slots after the action will only be executed if the button is held past the interval specified. Уметање задржавања. Слотови након дате радње ће да Ñе изврше Ñамо ако Ñе таÑтер задржи ван наведеног периода. Chose a profile to load when this slot is activated. Одабир профила који ће Ñе учитати по укључењу овог Ñлота. Mouse mod action will modify all mouse speed settings by a specified percentage while the action is being processed. This can be useful for slowing down the mouse while sniping. Радња за управљањем начином рада миша ће изменити Ñве поÑтавке брзине миша за одређен проценат,а док је радња у току. Ово може бити кориÑно за уÑпоравање миша при нишањењу. Specify the time that keys past this slot should be held down. Одређује колико ће дуго бити задржани у доњем положају (притиÑнути) таÑтери ван овог Ñлота. Insert a release action. Slots after the action will only be executed after a button release if the button was held past the interval specified. Уметање отпуштања. Слотови након дате радње ће да Ñе изврше Ñамо по отпуштању таÑтера ако је он задржан ван наведеног периода. Change to selected set once slot is activated. Промени на одабрани Ñкуп по отпочињању Ñлота. Full string will be typed when a slot is activated. УпиÑује пуну ниÑку знакова по отпочињању Ñлота. Execute program when slot is activated. Извршава програм по отпочињању Ñлота. Choose Profile Одабир профила Config Files (*.amgp *.xml) Датотеке подешавања (*.amgp *.xml) AdvanceStickAssignmentDialog Stick/Pad Assignment Придружвање Управљача/ТаÑтера Sticks Управљачи DPads ТаÑтери правца или Ñмера (дирекционални) Д-таÑтери %1 (Joystick %2) %1 (ÐојÑтик %2) Stick 1 Управљач 1 Enabled Омогућен Assign Придружи X Axis: »X« правац: Y Axis: »Y« правац: Stick 2 Управљач 2 Number of Physical DPads: %1 Број Ñтварних Д-таÑтера: %1 Virtual DPad 1 Патворено = Виртуелно Патворен Д-таÑтатер 1 Up: Горе: Down: Доле: Note: This window is meant for backwards compatibility with profiles made before antimicro 2.0. Since version 2.0, use of the Game Controller Mapping window is preferred. Обавештење: Ово прозорче још увек поÑтоји Ñамо због уÑаглашеноÑти Ñа ранијим издањима програма (пре издања 2.0). Придруживач таÑтера контролера Ñе препоручује од издања 2.0. Left: Лево: Right: ДеÑно: Axis %1 Правац %1 Axis %1 - Правац %1 - Axis %1 + Правац %1 + Button %1 Дугме %1 Move stick 1 along the X axis Померајте по »Х-оÑи« 1. управљач Move stick 1 along the Y axis Померајте по »У-оÑи« 1. управљач Move stick 2 along the X axis Померајте по »Х-оÑи« 2. управљач Move stick 2 along the Y axis Померајте по »У-оÑи« 2. управљач Press a button or move an axis ПритиÑните таÑтер или померите управљач AxisEditDialog Axis Правац Mouse (Horizontal) Миш (водоравно) Mouse (Inverted Horizontal) Миш (обрнуто водоравно) Mouse (Vertical) Миш (уÑправно) Mouse (Inverted Vertical) Миш (обрнуто уÑправно) Arrows: Up | Down Стрелице: Горе | Доле Arrows: Left | Right Стрелице: Лево | ДеÑно Keys: W | S ТаÑтери: Њ | С Keys: A | D ТаÑтери: Ð | Д NumPad: KP_8 | KP_2 Број.ТаÑтатура: КП_8 | КП_2 NumPad: KP_4 | KP_6 Број.ТаÑтатура: КП_4 | КП_6 None Ðишта Set the value to use as the limit for an axis. Useful for a worn out analog stick. ПоÑтави ову вредноÑÑ‚ као граничну за правац. Употребљиво у раду Ñа иÑтрошеним аналогним управљачем. Negative Half Throttle Полу-регулатор умањења Positive Half Throttle Полу-регулатор увећавања Name: Ðазив: Specify the name of an axis. Одредите Ðазив оÑе(правца). Mouse Settings ПоÑтавке миша Set the value of the dead zone for an axis. ПодеÑи вредноÑÑ‚ мртве облаÑти за правaц. Presets: ПоÑтавке: Dead Zone: Мртва облаÑÑ‚: Max Zone: Ðајвиша облаÑÑ‚: [NO KEY] [Без таÑтера] Throttle setting that determines the behavior of how to interpret an axis hold or release. ПоÑтавке регулатора које одређују понашање при тумачењу држи („hold“) или пуÑти („release“) за правац. Negative Throttle Регулатор умањења Normal Ðормално Positive Throttle Регулатор увећавања Current Value: Текућа вредноÑÑ‚: Set ПоÑтави Set %1 Скуп %1 Left Mouse Button Леви таÑтер миша Right Mouse Button ДеÑни таÑтер миша ButtonEditDialog Dialog Прозорче To make a new assignment, press any keyboard key or click a button in the Keyboard or Mouse tab Да би Ñте Ñтворили ново придруживање, притиÑните неко од дугмади таÑтатуре или кликните мишем на неко дугме у неком од језичака „ТаÑтатура“ или „Миш“ Placeholder Препознавач положаја Toggle Преклопник Enables a key press or release to only occur when a controller button is pressed. Омогућава да Ñе догоди дугме „притиÑни“ или „пуÑти“, и то, Ñамо ако је дугме контролера притиÑнуто. Enables rapid key presses and releases. Turbo controller. Омогућава хитрије дугме „притиÑни“ или дугме „пуÑти“. Контролер набуџивања. Turbo Ðабуџи Current: Тренутно Ñтање: Slots Слотови Na&me: Specify the name of a button. УнеÑите назив за дугме. Action: Радња: Specify the action that will be performed in game while this button is being used. Одредите радњу која ће Ñе извршавати при употреби овог дугмета. Advanced Ðапредно Set ПодеÑи Set %1 Скуп %1 CapturedWindowInfoDialog Captured Window Properties ОÑобине откривеног прозора Information About Window Подаци о прозору Class: КлаÑа: TextLabel ТекÑÑ‚-Ð½Ð°Ñ‚Ð¿Ð¸Ñ Title: ÐаÑлов: Path: Путања: Match By Properties Прилагоди по Class клаÑи Title наÑлову Path путањи Full Path Пуна путања File Name Ðазив датотеке CommandLineUtility Profile location %1 is not an XML file. Путања до профила „%1“ није ИкÑМЛ датотека. Profile location %1 does not exist. Путања до профила „%1“ не поÑтоји. An invalid set number '%1' was specified. Controller identifier '%s'' is not a valid value. No display string was specified. Ðије поÑтављено »Display string«. Controller identifier is not a valid value. Означивач контролера нема ваљану вредноÑÑ‚. No set number was specified. Ðије одређен број Ñкупа. No controller was specified. Ðије одређен контролер. An invalid event generator was specified. Одређен је неважећи Ñтваралац догађаја. No event generator string was specified. Ðије одређен назив Ñтвараоца догађаја. Qt style flag was detected but no style was specified. Откривен је белег Кјут-Ñтила али Ñам Ñтил није одређен. No log level specified. Ðије одређен ниво извештавања. antimicro version Издање програма Usage: antimicro [options...] [profile] Options Опције Print help text. ИÑпиÑује овај текÑÑ‚ помоћи. Print version information. ИÑпиÑује податке о издању. Launch program in system tray only. Покреће програм Ñамо у обавештајној зони. Launch program with the tray menu disabled. Покреће програм не кориÑтећи обавештајну зону. Launch program without the main window displayed. Покреће програм без приказивања главног произора. Launch program with the configuration file selected as the default for selected controllers. Defaults to all controllers. Покреће програм учитавајући датотеку Ñа подешавањима обележену као подразумевана за одабрани контролер. Подразумевано је, примена на Ñве контролере. Apply configuration file to a specific controller. Value can be a controller index, name, or GUID. Примени датотеку Ñа подешавањима на одређени контролер, чија вредноÑÑ‚ Ñе може предÑтавити као Ð¸Ð½Ð´ÐµÐºÑ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»ÐµÑ€Ð°, назив, или ЈИБГ. Unload currently enabled profile(s). Value can be a controller index, name, or GUID. Одбаци текући, укључени профил(е). ВредноÑÑ‚ Ñе може предÑтавити као Ð¸Ð½Ð´ÐµÐºÑ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»ÐµÑ€Ð°, назив, или ЈИБГ. Start joysticks on a specific set. Value can be a controller index, name, or GUID. Покрени џојÑтик употребом одређеног Ñкупа. ВредноÑÑ‚ Ñе може предÑтавити као Ð¸Ð½Ð´ÐµÐºÑ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»ÐµÑ€Ð°, назив, или ЈИБГ. Advance profile loading set options. Launch program as a daemon. Покрени програм као позадинÑки процеÑ. Enable logging. Укључује извештавање. Use specified display for X11 calls. Useful for ssh. Употребљава дати екран за ИкÑ-11 позиве. Употребљиво за „ssh“. Choose between using XTest support and uinput support for event generation. Default: xtest. Одабир између ИкÑ-теÑÑ‚ и „uinput“ подршке за Ñтварање догађаја. Подразумевано: „xtest“. Choose between using SendInput and vmulti support for event generation. Default: sendinput. Одабир између „SendInput“ и „vmulti“ подршке за Ñтварање догађаја. Подразумевано: „sendinput“. Print information about joysticks detected by SDL. Приказује податке о џојÑицима које је открио СДЛ. Open game controller mapping window of selected controller. Value can be a controller index or GUID. Отвори прозор придруживача таÑтера контролера за одабран контролер. ВредноÑÑ‚ може бити Ð¸Ð½Ð´ÐµÐºÑ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»ÐµÑ€Ð° или ЈИБГ (енг. „GUID“). DPadContextMenu Mouse (Normal) Миш (обично) Mouse (Inverted Horizontal) Миш (обрнуто водоравно) Mouse (Inverted Vertical) Миш (обрнуто уÑправно) Mouse (Inverted Horizontal + Vertical) Миш (обрнуто водоравно и уÑправно) Arrows Стрелице Keys: W | A | S | D ТаÑтери: Њ | Ð | С | Д NumPad Број.таÑтатура None Ðишта Standard Уобичајено Eight Way ОÑмоÑмерно 4 Way Cardinal Уобичајено четвороÑмерно 4 Way Diagonal ЧетвороÑмерно-дијагонално Mouse Settings ПоÑтавке миша DPadEditDialog Dialog Прозорче Presets: ПоÑтавке: Mouse (Normal) Миш (нормално) Mouse (Inverted Horizontal) Миш (обрнуто водоравно) Mouse (Inverted Vertical) Миш (обрнуто уÑправно) Mouse (Inverted Horizontal + Vertical) Миш (обрнуто водоравно и уÑправно) Arrows Стрелице Keys: W | A | S | D ТаÑтери: Њ | Ð | С | Д NumPad Бројчана таÑтатура None Ðишта Dpad Mode: Употреба Д-таÑтера: &Name: 4 Way Cardinal Уобичајено четвороÑмерно 4 Way Diagonal ЧетвороÑмерно-дијагонално DPad Delay: Д-таÑтери — кашњење: Time lapsed before a direction change is taken into effect. Кашњење пре но промена Ñмера приметно наÑтупи. s Ñ Specify the name of a dpad. УнеÑите назив за Д-таÑтер. Mouse Settings ПоÑтавке миша Standard Уобичајено Standard: 8 region dpad with two direction buttons active when the dpad is in a diagonal region. Eight Way: 8 region dpad with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region dpad with regions corresponding to the cardinal directions of the dpad. Useful for menus. 4 Way Diagonal: 4 region dpad with each region corresponding to a diagonal zone. Eight Way ОÑмоÑмерно Set ПодеÑи Set %1 Скуп %1 EditAllDefaultAutoProfileDialog Default Profile Подразумеван профил Profile: Профил: Browse Разгледај Open Config Отвори подешавања Profile file path is invalid. Путања до датотеке профила није ваљана. ExtraProfileSettingsDialog Extra Profile Settings Додатна подешавања профила Key Press Time: Време притиÑка таÑтера: 0.00 ms 0.00 Ð¼Ñ Profile Name: Ðазив профила: s Ñек. GameController Game Controller Контролер програма GameControllerDPad DPad Д-таÑтер GameControllerMappingDialog Game Controller Mapping Придруживач таÑтера контролера <html><head/><body><p>antimicro makes use of the <a href="https://wiki.libsdl.org/CategoryGameController"><span style=" text-decoration: underline; color:#0057ae;">Game Controller API</span></a> provided by SDL 2 in order to abstract various gamepads to fit a unified standard. In order to make a button assignment, please highlight the mapping cell for the appropriate button row below. You can then press a button or move an axis on your gamepad and the cell will update with the physical button or axis that will be used.</p><p>antimicro will use the mapping that you specify to save a mapping string that will be loaded into SDL.</p></body></html> <html><head/><body><p>Да би Ñе у већини програма различити контролери (гејмпедови) употребљавали на јединÑтвен начин програм Ðнти-микро употребљава програмÑко Ñучеље дефиниÑано у пројекту СДЛ издања2, а названо „Гејм-контролер ÐПИ“ (енг. <a href="https://wiki.libsdl.org/CategoryGameController"><span style=" text-decoration: underline; color:#0057ae;">„Game Controller API“</span></a>). За придруживање таÑтера одаберите поље за придруживање у реду одговарајућег таÑтера, а након тога притиÑните неки таÑтер на гејмпеду или померите ручицу управљача правца на њему. У пољу за придруживање ће Ñе појавити подаци Ñтварног (физичког) таÑтера или ручице управљача који ће Ñе употребљавати.</p><p>Ðнти-микро ће да употреби ова придруживања за чување знаковних ниÑки придруживања које Ñе могу учитавати помоћу СДЛ програма.</p></body></html> A 3 B 2 X 4 Y 1 Back Ðазад Start Почни Guide Водич Left Shoulder Леви окидач 1 Right Shoulder ДеÑни окидач 1 Left Stick Click ПритиÑак на леви управљач Right Stick Click ПритиÑак на деÑни управљач Left Stick X Леви управљач — водоравно Left Stick Y Леви управљач — уÑправно Right Stick X ДеÑни управљач — водоравно Right Stick Y ДеÑни управљач — уÑправно Left Trigger Леви окидач 2 Right Trigger ДеÑни окидач 2 DPad Up Д-таÑтер — Горе DPad Left Д-таÑтер — Лево DPad Down Д-таÑтер — Доле DPad Right Д-таÑтер — ДеÑно Mapping Придруживања SDL 2 Game Controller Mapping String СДЛ-2 ниÑка придруживања таÑтера контролера Last Axis Event: Задњи догађај на правцу: Current Axis Detection Dead Zone: Откривање мртве облаÑти текућег правца: 5000 5000 10000 10000 15000 15000 20000 20000 25000 25000 30000 30000 32000 32000 Game Controller Mapping (%1) (#%2) Придруживач таÑтера контролера (%1) (#%2) Discard Controller Mapping? Поништавање придруживања контролера? Discard mapping for this controller? If discarded, the controller will be reverted to a joystick once you refresh all joysticks. Да ли да поништим придруживања за овај контролер? If discarded, the controller will be reverted to a joystick once you refresh all joysticks. GameControllerSet Back Ðазад Guide Водич Start Почни LS Click ПритиÑак 1. левог окидача RS Click ПритиÑак 1. деÑног окидача L Shoulder 1. леви окидач R Shoulder 1. деÑни окидач L Trigger 2. леви окидач R Trigger 2. деÑни окидач GameControllerTrigger Trigger Окидач JoyAxis Axis Правац JoyAxisButton Negative Умањи Positive Увећај Unknown Ðепознато Button Дугме JoyAxisContextMenu Mouse (Horizontal) Миш (водоравно) Mouse (Inverted Horizontal) Миш (обрнуто водоравно) Mouse (Vertical) Миш (уÑправно) Mouse (Inverted Vertical) Миш (обрнуто уÑправно) Arrows: Up | Down Стрелице: Горе | Доле Arrows: Left | Right Стрелице: Лево | ДеÑно Keys: W | S ТаÑтери: Њ | С Keys: A | D ТаÑтери: Ð | Д NumPad: KP_8 | KP_2 Број.ТаÑтатура: КП_8 | КП_2 NumPad: KP_4 | KP_6 Број.ТаÑтатура: КП_4 | КП_6 None Ðишта Mouse Settings ПоÑтавке миша Left Mouse Button Леви таÑтер миша Right Mouse Button ДеÑни таÑтер миша JoyButton Processing turbo for #%1 - %2 Буџим за #%1 - %2 Finishing turbo for button #%1 - %2 Завршено набуџивање таÑтера #%1 - %2 Processing press for button #%1 - %2 ПритиÑкам за таÑтер #%1 - %2 Processing release for button #%1 - %2 Отпуштам за таÑтер #%1 - %2 Distance change for button #%1 - %2 Промена раздаљине за таÑтер #%1 - %2 Button ТаÑтер [NO KEY] [Без таÑтера] [Set %1 1W] [Скуп %1 1-Ñмерно] [Set %1 2W] [Скуп %1 2-Ñмерно] [Set %1 WH] [Скуп %1 WH] JoyButtonContextMenu Toggle Преклопи Turbo Ðабуџи Clear ОчиÑти Set Select Одабир Ñкупа Disabled Онемогућено Set %1 Скуп %1 Set %1 1W Скуп %1 1-Ñмерно Set %1 2W Скуп %1 2-Ñмерно Set %1 WH Скуп %1 WH JoyButtonSlot Mouse Миш Up Ðапред Down Ðазад Left Лево Right ДеÑно LB Л.дугме MB С.дугме RB Д.дугме B4 Дугме 4 B5 Дугме 5 Pause Пауза Hold Држи Cycle Врти Distance Раздаљина Release ПуÑти Mouse Mod Мишар Press Time Трајање притиÑка Delay Кашњење Load %1 Учитај %1 Set Change %1 Измена Ñкупа %1 [Text] %1 [ТекÑÑ‚] %1 [Exec] %1 [Извршавам] %1 [NO KEY] [Без таÑтера] JoyControlStick Stick Управљач JoyControlStickButton Up Ðапред Down Ðазад Left Лево Right ДеÑно Button Дугме JoyControlStickContextMenu Mouse (Normal) Миш (обично) Mouse (Inverted Horizontal) Миш (обрнуто водоравно) Mouse (Inverted Vertical) Миш (обрнуто уÑправно) Mouse (Inverted Horizontal + Vertical) Миш (обрнуто водоравно и уÑправно) Arrows Стрелице Keys: W | A | S | D ТаÑтери: Њ | Ð | С | Д NumPad Број.таÑтатура None Ðишта Standard Уобичајено Eight Way ОÑмоÑмерно 4 Way Cardinal Уобичајено четвороÑмерно 4 Way Diagonal ЧетвороÑмерно-дијагонално Mouse Settings ПоÑтавке миша JoyControlStickEditDialog Dialog Прозорче X: X: 0 0 Y: Y: Distance: Раздаљина: Presets: ПоÑтавке: Mouse (Normal) Миш (обично) Mouse (Inverted Horizontal) Миш (обрнуто водоравно) Mouse (Inverted Vertical) Миш (обрнуто уÑправно) Mouse (Inverted Horizontal + Vertical) Миш (обрнуто водоравно и уÑправно) Arrows Стрелице Keys: W | A | S | D ТаÑтери: Њ | Ð | С | Д NumPad Бројчана таÑтатура None Ðишта Stick Mode: Ðачин рада управљача: Standard: 8 region stick with two direction buttons active when the stick is in a diagonal region. Eight Way: 8 region stick with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region stick with regions corresponding to the cardinal directions of the stick. Useful for menus. 4 Way Diagonal: 4 region stick with each region corresponding to a diagonal zone of the stick. Уобичајено: 8-Ñмерни управљач Ñа два притиÑнута таÑтера за померање по дијагонали. ОÑмоÑмерно: 8-Ñмерни управљач Ñа ÑопÑтвеним таÑтерима за Ñваки Ñмер. У једном тренутку, радни је Ñамо један таÑтер. Употребљиво за роголике (енг. „rougelike“) игре. Уобичајено 4-Ñмерно: 4-Ñмерни управљач за померање у 4 Ñмера (померена за 90°). Употребљиво за изборнике. 4-Ñмерно дијагонално: 4-Ñмерни управљач где Ñвака облаÑÑ‚ одговара дијагоналној облаÑти датог управљача. 4 Way Cardinal Уобичајено четвороÑмерно 4 Way Diagonal ЧетвороÑмерно-дијагонално Dead zone value to use for an analog stick. ВредноÑÑ‚ мртве облаÑти код аналогних управљача. Value when an analog stick is considered moved 100%. ВредноÑÑ‚ у којој је аналогни управљач у крајњем положају. The area (in degrees) that each diagonal region occupies. ОблаÑÑ‚ (у Ñтепенима) коју Ñвака облаÑÑ‚ на дијагонали заузима. Square Stick: ЧетвртаÑÑ‚ управљач: Percentage to modify a square stick coordinates to confine values to a circle ПоÑтотак промене квадратних координата управљача за ограничавање вредноÑти у кружници % % Stick Delay: Кашњење управљача: Time lapsed before a direction change is taken into effect. Кашњење пре но промена Ñмера приметно наÑтупи. s Ñ Modifier: Измењивач: Edit button that is active while the stick is active. This button is useful for assigning zones with modifier keys that can be used to assign walk/run functionality to an analog stick. Дугме за уређивање који је радно док управљач ради. Употребљиво за доделе облаÑти таÑтерима-измењивачима који могу да Ñе употребе за додавање могућноÑти ходај-трчи аналогним управљачима. PushButton Дугме Name: Ðазив: Specify the name of an analog stick. УнеÑите назив за аналогни управљач. Mouse Settings ПоÑтавке миша Standard Уобичајено Bearing: Ðзимут: % Safe Zone: % Безбедна облаÑÑ‚: Eight Way ОÑмоÑмерно Dead Zone: Мртва облаÑÑ‚: Max Zone: Ðајвиша облаÑÑ‚: Diagonal Range: Дијагонални опÑег: Set ПоÑтави Set %1 Скуп %1 JoyControlStickModifierButton Modifier Измењивач JoyDPad DPad Д-таÑтер JoyDPadButton Up Горе Down Доле Left Лево Right ДеÑно Button Дугме JoyTabWidget <New> <Ðово> Remove Уклони Remove configuration from recent list. Уклони подешавање Ñа текуће лиÑте. Load Учитај Load configuration file. Учитај датотеку Ñа подешавањима. Save Сачувај Save changes to configuration file. Сачувај измене у датотеку подешавања. Save As Сачувај као Save changes to a new configuration file. Сачувај измене у новој датотеци подешавања. Sets Скупови Copy from Set Умножи из ... Settings ПоÑтави називе Set 1 1. Ñкупа Set 2 2. Ñкупа Set 3 3. Ñкупа Set 4 4. Ñкупа Set 5 5. Ñкупа Set 6 6. Ñкупа Set 7 7. Ñкупа Set 8 8. Ñкупа Stick/Pad Assign Придружи Управљач/ТаÑтатуру Controller Mapping Придруживач таÑтера контролера Quick Set Брзе поÑтавке Names Ðазиви Toggle button name displaying. Приказивање назива преклопника. Pref Опште поÑтавке Change global profile settings. Измените опште поÑтавке профила. Reset Поништи Revert changes to the configuration. Reload configuration file. Поништи измене и учитај опет датотеку Ñа подешавањем. Open Config Отвори подешавања Config Files (*.amgp *.xml) Датотеке подешавања (*.amgp *.xml) Config File (*.%1.amgp) Датотека подешавања (*.%1.amgp) Save Profile Changes? Да ли да Ñачувам измене профила? Changes to the new profile have not been saved. Would you like to save or discard the current profile? Имате неÑачуваних промена новог профила. Да ли желите да их Ñачувам или да их поништим? Changes to the profile "%1" have not been saved. Would you like to save or discard changes to the current profile? Имате неÑачуваних промена у профилу "%1" . Да ли желите да их Ñачувам или да их поништим? Sticks Управљачи DPads Д-таÑтери No buttons have been assigned. Please use Quick Set to assign keys to buttons or disable hiding empty buttons. Ðема придруживања за дугмад. Можете да употребите „Брзе поÑтавке“ за придруживања дугмадима или да иÑкључите Ñкривање „празних“ дугмади. Set %1: %2 Скуп %1: %2 Set %1 Скуп %1 Copy Set Assignments Умножи придруживања из Ñкупа Are you sure you want to copy the assignments and device properties from %1? Да ли заиÑта желите да умножите придруживања и оÑобине уређаја из %1? Save Config Сачувај подешавања Set ПоÑтави Joystick Joystick ÐојÑтик JoystickStatusWindow Properties ОÑобине Details Детаљи Name: Ðазив: %1 %1 Number: Број: Axes: Праваца: Buttons: Дугмад: Hats: Капице: GUID: ЈИБГ: Game Controller: Контролер за игре: Axes Правци Buttons Дугмад Hats Капице %1 (#%2) Properties %1 (#%2) ОÑобине Axis %1 Правац %1 Hat %1 Хат %1 No Ðе Yes Да MainSettingsDialog Edit Settings Уређивање поÑтавки General Опште поÑтавке Controller Mappings Придруживања контролера Language Језик Auto Profile Ðуто-профил Mouse Миш <html><head/><body><p>Specify the default directory that the program should use in file dialogs when loading a profile or saving a new profile.</p></body></html> <html><head/><body><p>ПоÑтављање уобичајеног директоријума за учитавање поÑтојећих или чување нових профила.</p></body></html> Recent Profile Count: Број Ñкорашњих профила: <html><head/><body><p>Number of profiles that can be placed in recent profile list. 0 will result in the program not enforcing a limit on the number of profiles displayed.</p></body></html> <html><head/><body><p>Број профила који Ñе може ÑмеÑтити у лиÑту недавно употребљаваних профила. Број 0 означава приказ Ñвих употребљаваних профила.</p></body></html> Gamepad Poll Rate: Провера порука џојÑтика након: Change the poll rate that the program uses to discover new events from gamepads. Defaults to 10 ms. Reducing the poll rate value could cause the application to use more CPU power so please test the setting that you use before using antimicro unattended. Измените време након кога ће програм да провери да ли је гејмпед производио догађаје (поруке). Уобичајена вредноÑÑ‚ је 10 мÑ. Ðиже вредноÑти ове опције могу да доведу до веће употребе ЦПЈ (процеÑора), Проверите ову поÑтавку пре озбиљније употребе. Hide main window when the main window close button is clicked instead of quitting the program. ПритиÑком на дугме затварања главног прозора, он Ñе затвара али програм оÑтаје покренут у обавештајној зони. Close To Tray СмеÑти у обавештајну зону Have Windows start antimicro at system startup. Покрени програм Ñа покретањем ÑиÑтема. Launch At Windows Startup Покрени по покретању ÑиÑтема Display recent profiles for all controllers as a single list in the tray menu. Defaults to using sub-menus. Приказаће Ñе Ñкорашњи профили за Ñве контролере као јединÑтвен ÑпиÑак профила у обавештајној зони. Уобичајено је употреба под-изборника. Single Profile List in Tray ЈединÑтвен ÑпиÑак профила у обавештајној зони Have the program minimize to the taskbar. By default, the program minimizes to the system tray if available. Програм ће Ñе ÑмеÑтити у траку покренутих задатака. Подразумевано Ñмештање програма је у обавештајној зони ако је она доÑтупна. Minimize to Taskbar СмеÑти у траку покренутих задатака This option will cause the program to hide all buttons that have no slots assigned to them. The Quick Set dialog window will have to be used to bring up the edit dialog for gamepad buttons. Ðко је укључена ова опција, програм ће Ñкрити дугмад која немају придружених Ñлотова. У прозору „Брзе поÑтавке“ моћи ћете да подеÑите придруживања таÑтера гејмпеда. Hide Empty Buttons Сакриј „празну“ дугмад When the program is launched, open the last known profile that was opened during the previous session. Ово омогућава да Ñе по покретању програма учита познат, поÑледње учитаван профил у претходној ÑеÑији. Auto Load Last Opened Profile Отвори Ñам поÑледњи употребљени профил Only show the system tray icon when the program first launches. Приказује Ñамо икону у обавештајној зони по првом покретању програма. Launch in Tray Покрени у обавештајној зони Associate .amgp files with antimicro in Windows Explorer. Придружуј „.amgp“-датотеке програму Ðнти-микро (виндоуз екÑплорер). Associate Profiles Придружени профили Key Repeat ВишеÑтруки притиÑци таÑтера Active keys will be repeatedly pressed when this option is enabled. Ðко је укључено омогућени Ñу вишеÑтруки, узаÑтопни притиÑци таÑтера. Enable Омогућено Specifies how much time should elapse before key repeating begins. Кашњење пре започињања вишеÑтруког, узаÑтопног притиÑкања таÑтера. Specifies how many times key presses will be performed per seconds. Одређује број притиÑака таÑтера у Ñекунди код вишеÑтруког, узаÑтопног притиÑкања таÑтера. <html><head/><body><p>antimicro has been translated into many different languages by contributors. By default, the program will choose an appropriate translation based on your system's locale setting. However, you can make antimicro load a different translation depending on the language that you choose from the list below.</p></body></html> <html><head/><body><p>Сарадници аутора Ñу локализовали програм за разне језике. Уобичајено, програм ће употребљавати језичке поÑтавке Ñамог ÑиÑтема за приказ, али, уколико то желите, можете употребљавати програм и на језику који одаберете на лиÑти иÑпод.</p></body></html> French француÑки Italian Japanese Russian руÑки Serbian ÑрпÑки Simplified Chinese Ukrainian украјинÑки Class клаÑи Title наÑлову Program Програм Disable the "Enhanced Pointer Precision" Windows setting while antimicro is running. Disabling "Enhanced Pointer Precision" will allow mouse movement within antimicro to be more precise. ИÑкључи виндоуз-поÑтавку за „побољшање прецизноÑти показивача“ док програм ради. Онемогућавањем ове виндоуз-поÑтавке повећава Ñе прециÑноÑÑ‚ померања показивача (миша) у Ñамом програму. Disable Enhance Pointer Precision ИÑкључи побољшања прецизноÑти показивача Smoothing УглађеноÑÑ‚ Histor&y Size: Weight &Modifier: Refresh Rate: Брзина оÑвежавања: The refresh rate is the amount of time that will elapse in between mouse events. Please be cautious when editing this setting as it will cause the program to use more CPU power. Setting this value too low can cause system instability. Please test the setting before using it unattended. Брзина оÑвежавања предÑтавља протекло време између догађаја миша. Будите врло опрезни при уређивању ове поÑтавке јер Ñе може повећати употреба ЦПЈ (процеÑора), а при премалим вредноÑтима ове поÑтавке ÑиÑтем може да пређе у неÑтабилно Ñтање. Проверите ову поÑтавку пре озбиљније употребе. Spring Скоковито Screen: Екран: Utilize the specified screen for spring mode. On Linux, the default is to use the primary screen. On Windows, the default is to use all available screens. Употребљава наведени екран за „Ñкоковит“ режим. Уобичајено, Ðа ГÐУ-ЛинукÑу је употреба оÑновног екрана, а на Виндоузу Ñвих раÑположивих екрана. Accel Numerator: Бројилац убрзања: 0 0 Accel Denominator: Именилац убрзања: Accel Threshold: Праг убрзања: If the acceleration values for the virtual mouse have been changed by a different process, particularly when quitting an older game, then you might want to reset the acceleration values used by the virtual mouse. Када Ñу вредноÑти убрзања патвореног миша измењене од Ñтране различитих процеÑа, поÑебно при излаÑку из Ñтаријих игара, можете пожелети да вратите ове вредноÑти убрзања патвореног миша на оне претходне. Reset Acceleration Поврати убрзање Delay: Кашњење: Profi&le Directory: ms Ð¼Ñ Rate: Брзина: times/s пута/Ñек. Below is a list of the custom mappings that have been saved. You can use the following table to delete mappings or have mappings temporarily disabled. You can also disable mappings that are included with SDL; just insert a new row with the appropriate joystick GUID and check disable. Settings will not take affect until you either refresh all joysticks or unplug that particular joystick. ИÑпод је лиÑта Ñачуваних, прилагођених мапирања. Можете да употребите Ñледећу табелу да биÑте избриÑали мапирања или да их привремено онемогућите. Можете да онемогућите мапирања која Ñу укључена у СДЛ; Ñамо уметните нови ред Ñа одговарајућим ЈИБГ-џојÑтика и означите онемогући. Подешавања Ñе неће узети у обзир док Ñе не оÑвежи лиÑта доÑтупних џојÑтика или док не иÑкључите дати, конкретан џојÑтик. GUID ЈИБГ Mapping String ÐиÑка придруживања Disable? ИÑкључи? Delete Уклони Insert Уметни Default подразумевано Brazilian Portuguese португалÑки (Бразил) English енглеÑки German немачки Active Омогућен Devices: Уређаји: All Сви Device Уређај Profile Профил Default? Подразумевано? Add Додај Edit Уреди Also, Windows users who want to use a low value should also check the "Disable Enhance Pointer Precision" checkbox if you haven't disabled the option in Windows. Такође, Виндоуз кориÑници који желе да употребе нижу вредноÑÑ‚, нека провере и „ИÑкључи побољшања прецизноÑти показивача“, ако ниÑу онемогућили ову опцију у Ñамом ÑиÑтему. Select Default Profile Directory Одабир уобичајеног директоријум профила Are you sure you want to delete the profile? Да ли заиÑта желите да уклоните овај профил? MainWindow No Joysticks have been found. Please plug in a joystick and then choose the "Update Joysticks" option in the main menu ÐиÑам пронашао џојÑтик. Када га прикључите покрените „ПоÑтавке > Пронађи џојÑтике“ из главног менија &App &Датотека Stick/Pad Assign Придружи Управљач/ТаÑтатуру &Options П&оÑтавке antimicro Ðнти-микро If events are not seen by a game, please click here to run this application as the Adminstrator. Ðко догађаје игра не „види“, притиÑните ово дугме за покретање овог програма као админиÑтратор. &Help &Помоћ &Quit &Затвори Ctrl+Q Ctrl+Q &Update Joysticks Про&нађи џојÑтике Ctrl+U Ctrl+U &Hide &Сакриј Ctrl+H Ctrl+H &About О прогр&аму Ctrl+A Ctrl+A About Qt О КјуТ Properties ОÑобине Key Checker Провера таÑтера таÑтатуре Home Page Матична Ñтрана GitHub Page Гит-хаб Ñтрана Game Controller Mapping Придруживач таÑтера контролера Settings ПоÑтави називе Wiki Вики-Ñтране Could not find a proper controller identifier. Exiting. (%1) (%1) Open File Отвори датотеку &Restore Ð’&рати Run as Administrator? Покрени као админиÑтратор? Are you sure that you want to run this program as Adminstrator? Some games run as Administrator which will cause events generated by antimicro to not be used by those games unless antimicro is also run as the Adminstrator. This is due to permission problems caused by User Account Control (UAC) options in Windows Vista and later. Да ли заиÑта желите да покренете програм уз админиÑтраторÑке дозволе? Ðеки програми покренути уз админиÑтраторÑке дозволе могу да доведу до тога да радње које захтева Ðнти-микро не буду ваљано препознате Ñве док Ñе и Ñам Ðнти-микро не покрене уз иÑте дозволе. Код Видоуз-ВиÑта или новијих виндоуза ово је изазвано проблемима Ñа дозволама које Ñтвара опција за управљање кориÑничким налозима (енг. Ñкр. „UAC“). Failed to elevate program Ðе могу да покренем програм Failed to restart this program as the Administrator ÐеуÑпело покретање програма Ñа админ. дозволама Could not find controller. Exiting. MouseAxisSettingsDialog Mouse Settings - ПоÑтавке миша - Set %1 Скуп %1 MouseButtonSettingsDialog Mouse Settings - ПоÑтавке миша - Set %1 Скуп %1 MouseControlStickSettingsDialog Mouse Settings ПоÑтавке миша Set %1 Скуп %1 MouseDPadSettingsDialog Mouse Settings ПоÑтавке миша Set %1 Скуп %1 MouseSettingsDialog Mouse Settings ПоÑтавке миша Mouse Mode: Мишар: Cursor mode is used to move the mouse cursor around the screen relative to its current position depending on how much you move an axis or if a button is pressed. Spring mode is used to move the mouse cursor from the center of the screen depending on how much you move an axis. The mouse cursor will be returned to the center of the screen when the axis is moved back to the dead zone. У начину „показивач“, омогућава Ñе релативно померање показивача миша у одноÑу на његову текућу позицију. У „Ñкоковитом“ начину померање показивача миша је од Ñредишта екрана у Ñвим Ñмеровима, а када Ñе показивач миша нађе у мртвој облаÑти програм га враћа на Ñредину екрана. Cursor Показивач Spring Скоковито Acceleration: Убрзавање: Enhanced Precision Побољшана прецизноÑÑ‚ Linear Линеарно Quadratic Квадратно Cubic Кубно Quadratic Extreme Ðабуџено квадратно Power Function Ðај-функција Easing Quadratic Квадратно попуштање Easing Cubic Кубно попуштање Mouse Speed Settings Брзина померања Enable to change the horizontal and vertical speed boxes at the same time. Омогућује иÑтовремену промену брзине у оба правца. Change Together Измењуј повезано Options for adding more acceleration to the mouse movement beyond what the acceleration curve would produce. Acceleration is added based on how quickly an axis is moved in one gamepad poll. This is meant to help work around some of the issues of the very limited input range available using typical gamepad analog sticks. Delta Acceleration &Multiplier: Mi&n Threshold: Horizontal Speed: Лево→ДеÑно: 1 = 20 pps 1 = 20 тачака/Ñек. Vertical Speed: Горе→Доле: Wheel Hori. Speed: Tочкић водоравно: Set the speed used for horizontal mouse wheel movement according to number of simulated notches per second. ПоÑтављање брзине водоравног померања миша према одговарајућем, Ñимулираном броју зареза по Ñекунди. Set the speed used for vertical mouse wheel movement according to number of simulated notches per second. ПоÑтављање брзине уÑправног померања миша према одговарајућем, Ñимулираном броју зареза по Ñекунди. Sensitivit&y: For Power Function acceleration curve. Specifies the factor to use for curve sensitivity. When the value is above 1.0, the mouse movement will be accelerated faster at the low end of an axis. За кривуљу убрзавања Ðај-функције. Одређује чинилац код поÑтављања оÑетљивоÑти кривуље. За вредноÑÑ‚ изнад 1.0, покрети миша ће Ñе више убрзавати у крајњем доњем положају оÑе. Easing Duration: Трајање попуштањa: s Ñ Extra Acceleration Додатно убрзање Multiplier: Чинилац: Highest value to accelerate mouse movement by Ðајвиша вредноÑÑ‚ за убрзање померања миша x x Start %: Почетак %: Acceleration begins at this percentage of the base multiplier Убрзање почиње након оволико процената од оÑновног чиниоца Min Threshold: Ðајмањи праг: Minimum amount of axis travel required for acceleration to begin Ðајмања количина оÑног померања неопходна за отпочињање убрзања Max Threshold: Ðајвећи праг: Maximum axis travel before acceleration has reached the multiplier value Ðајвиша количина оÑног померања пре но Ñе доÑтигне вредноÑÑ‚ датог чиниоца E&xtra Duration: Curve: Ease Out Sine Ease Out Quad Ease Out Cubic Release Radius: Пречник пуштања: Specifies that the spring area will be relative to the mouse position set by a non-relative spring. Одређује да ће „Ñкоковито“ подручје бити релативно у одноÑу на положај миша поÑтављен не-релативним Ñкоком. Relative Релативно Mouse Status Стање миша X: X: 0 (0 pps) 0 (0 тачака/Ñек) Y: Y: 1 = 1 notch(es)/s 1 = 1 зарез(а)/Ñек. Enhanced: Three tier curve that makes the mouse move slow on the low end of an axis and fast on the high end. Linear: Mouse moves proportionally to axis. Quadratic: Mouse accelerates slowly on low end. Cubic: Mouse accelerates slower than Quadratic. Quadratic Extreme: Raises mouse speed 1.5 times once 95% axis travel has been reached. Power Function: Allows for a more custom curve option. Easing Quadratic: Axis high end is gradually accelerated over a period of time using a Quadratic curve. Easing Cubic: Axis high end is gradually accelerated over a period of time using a Cubic curve. Подиже брзину померања миша 1,5 пута по доÑтизању 95% оÑног пута Побољшана прецизноÑÑ‚: ТроÑлојна кривуља која чини да померање миша буде Ñпоро на доњем крају оÑе и брзо на њеном горњем крају. Линеарно: Померања миша је Ñразмерно по оÑи. Квадратно: Померања миша Ñе лагано убрзавају на доњем крају. Кубно: Спорије убрзавање миша од „Квадратног“. Ðабуџено квадратно: Подиже брзину померања миша 1,5 пута по доÑтизању 95% од могућег оÑног померања. Ðај-функција: Дозвољава потпуније прилагођавање кривуље убрзавања. Квадратно попуштање: У горњем крају оÑе, поÑтепено убрзање током времена употребљавајући квадратну кривуљу. Кубно попуштање: У горњем крају оÑе, поÑтепено убрзање током времена употребљавајући кубну кривуљу. Hori&zontal Speed: &Vertical Speed: Wheel Vert. Speed: Tочкић уÑправно: Sensitivity: ОÑетљивоÑÑ‚: Specifies the amount of time (in seconds) that will be required before the mouse is fully accelerated after reaching the high end of an axis. Одређује количину времена (у Ñекундама) неопходну за потпуно убрзање миша, а након доÑтизања горњег краја оÑе. % % Extra Duration: Додатно трајање: Extend the time that extra acceleration is applied. Axis travel will be taken into account. A slower flick will decrease the actual time that extra acceleration will be applied. Продужује време за које ће Ñе применити додатно убрзање. У обзир ће Ñе узети оÑно померање. Спорији „флик“ Ñмањује Ñтварно време након кога ће Ñе примењивати додатно убрзање. Spring Settings Скоковито померање Spring Width: По ширини: Changes the width of the region that the cursor can move in spring mode. 0 will use the entire width of your screen. Мењање ширине облаÑти за померање показивача у Ñкоковитом начину. „0“ означава иÑкоришћавање укупне ширине Вашег екрана. Spring Height: По виÑини: Changes the height of the region that the cursor can move in spring mode. 0 will use the entire height of your screen. Мењање виÑине облаÑти за померање показивача у Ñкоковитом начину. „0“ означава иÑкоришћавање укупне виÑине Вашег екрана. %n notch(es)/s %n зарез/Ñек. %n зареза/Ñек. %n зареза/Ñек. QKeyDisplayDialog Key Checker Провера таÑтера таÑтатуре <html><head/><body><p>Press a key on your keyboard to see how the key is detected by this application. The window will show the system native key value, the original value given by Qt (if applicable), and the custom value used by antimicro.</p><p>The antimicro key value and the Qt key value will usually be the same. antimicro tries to use the key values defined in Qt when possible. Check the page <a href="https://doc.qt.io/qt-4.8/qt.html#Key-enum"><span style=" text-decoration: underline; color:#0057ae;">https://doc.qt.io/qt-4.8/qt.html#Key-enum</span></a> for a list of values defined by Qt. If you discover that a key is not natively supported by this program, please report the problem to antimicro's <a href="https://github.com/AntiMicro/antimicro"><span style=" text-decoration: underline; color:#0057ae;">GitHub page</span></a> so that the program can be edited to support it directly. As it is, a custom prefix is added to unknown values so they can still be used; the main problem is that the profile will no longer be portable.</p></body></html> <html><head/><body><p>ПритиÑните таÑтер на таÑтатури да биÑте видели како је овај програм открио одговарајућу вредноÑÑ‚. У прозору ће Ñе приказати вредноÑÑ‚ руковаоца догађаја, вредноÑÑ‚ у КјуТ-библиотекама (по потреби), као и прилагођена вредноÑÑ‚ у Ðнти-микро програму.</p><p>ВредноÑти које Ñу откривене програмима Ðнти-микро и КјуТ ће обично бити идентичне. јер Ðнти-микро употребљава вредноÑти КјуТ-библиотека када је то могуће. Погледајте Ñтраницу на мрежи <a href="https://doc.qt.io/qt-4.8/qt.html#Key-enum"><span style=" text-decoration: underline; color:#0057ae;">https://doc.qt.io/qt-4.8/qt.html#Key-enum (енг.)</span></a> за вредноÑти одређене за употребу КјуТ-програмима. Ðко откријете неке неподржане вредноÑти за таÑтере у овом програму, извеÑтите о том проблему на <a href="https://github.com/AntiMicro/antimicro"><span style=" text-decoration: underline; color:#0057ae;">Ðнти-микро гит-Ñтранама</span></a>, а у циљу иÑправљања уочених недоÑтатака. Како год, додат је предложак за непознате вредноÑти да би Ñе програм могао употребљавати, али оÑтаје главни проблем који Ñе одноÑи на преноÑивоÑÑ‚ профила.</p></body></html> Event Handler: Руковалац догађајем: Native Key Value: Очитана вредноÑÑ‚: 0x00000000 0x00000000 Qt Key Value: КјуТ вредноÑÑ‚: antimicro Key Value: Ðнти-микро вредноÑÑ‚: QObject Super Супер Menu Изборник Mute Мук Vol+ ГлаÑније Vol- Тише Play/Pause ПуÑти/Пауза Play ПуÑти Pause Пауза Prev Претходно Next Ðаредно Mail Е-пошта Home Почетно Media Медији Search Ðађи Daemon launched Покренут је позадинÑки Ð¿Ñ€Ð¾Ñ†ÐµÑ Failed to launch daemon Ðије уÑпело покретање позадинÑког процеÑа Launching daemon Покрећем позадинÑки Ð¿Ñ€Ð¾Ñ†ÐµÑ Display string "%1" is not valid. Ðије ваљана »Display string „%1“«. Failed to set a signature id for the daemon Ðије уÑпело поÑтављање ИБ-потпиÑа за позадинÑки Ð¿Ñ€Ð¾Ñ†ÐµÑ Failed to change working directory to / Ðе могу да поÑтавим „/“ као радни директоријум Quitting Program Излазак из програма # of joysticks found: %1 # џојÑтика пронађено: %1 List Joysticks: СпиÑак џојÑтика: --------------- --------------- Joystick %1: ÐојÑтик %1: Index: %1 ИндекÑ: %1 GUID: %1 ЈИБГ: %1 Name: %1 Ðазив: %1 Yes Да No Ðе Game Controller: %1 Контролер програма: %1 # of Axes: %1 # праваца: %1 # of Buttons: %1 # таÑтера: %1 # of Hats: %1 # капица: %1 Attempting to use fallback option %1 for event generation. Покушавам да кориÑтим резервну опцију %1 у Ñтварању догађаја. Failed to open event generator. Exiting. Ðе могу да отворим Ñтвараоца догађаја. Излазим. Using %1 as the event generator. Употребљавам %1 као Ñтвараоца догађаја. Could not raise process priority. Ðе могу да повиÑим приоритет процеÑа. QuickSetDialog Quick Set Брзе поÑтавке <html><head/><body><p>Please press a button or move an axis on %1 (<span style=" font-weight:600;">%2</span>).<br/>A dialog window will then appear which will<br/>allow you to make an assignment.</p></body></html> <html><head/><body><p>ПритиÑните неки таÑтер или померите управљач на уређају <br/>„%1“ (<span style=" font-weight:600;">%2</span>). Ðакон тога, појавиће Ñе прозорче <br/>у којем ћете моћи да придружите том таÑтеру-управљачу <br/>одговарајући таÑтер таÑтатуре, догађај и Ñл.</p></body></html> Quick Set %1 Брзе поÑтавке — %1 SetAxisThrottleDialog Throttle Change Промена регулатора The throttle setting for Axis %1 has been changed. Would you like to distribute this throttle change to all sets? ПоÑтавке регулатора за правац %1 Ñу Ñе промениле. Желите ли да ове промене регулатора буду доÑтупне у Ñвим групама? SetJoystick Set %1: %2 Скуп %1: %2 Set %1 Скуп %1 SetNamesDialog Set Name Settings ПоÑтавке назива Ñкупова Set 1 1. Ñкуп Set 2 2. Ñкуп Set 3 3. Ñкуп Set 4 4. Ñкуп Set 5 5. Ñкуп Set 6 6. Ñкуп Set 7 7. Ñкуп Set 8 8. Ñкуп Name Ðазив SimpleKeyGrabberButton Mouse Миш SpringModeRegionPreview Spring Mode Preview Преглед за начин „Скоковито“ UInputEventHandler Could not find a valid uinput device file. Please check that you have the uinput module loaded. lsmod | grep uinput Ðе могу да нађем ваљану „uinput“-датотеку уређаја. Проверите да ли је „uinput“-модул учитан. lsmod | grep uinput Could not open uinput device file Please check that you have permission to write to the device Ðе могу да отворим „uinput“-датотеку уређаја Проверите да ли имате дозволу за упиÑивање на уређај Using uinput device file %1 Употребљавам „uinput“-датотеку уређаја %1 UInputHelper a а b б c ц d д e е f Ñ„ g г h Ñ… i и j ј k к l л m м n н o о p п q Ñ™ r Ñ€ s Ñ t Ñ‚ u у v в w Ñš x ÑŸ y ж z з Esc Врати („Esc“) F1 Ф1 F2 Ф2 F3 Ф3 F4 Ф4 F5 Ф5 F6 Ф6 F7 Ф7 F8 Ф8 F9 Ф9 F10 Ф10 F11 Ф11 F12 Ф12 ` ` 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 0 0 - - = = BackSpace Уназад Tab Таб [ [ ] ] \ \ CapsLock Ð’.Ñлова ; ; ' ' Enter УнеÑи Shift_L л.Мењач , , . . / / Ctrl_L л.Ктрл Super_L л.Супер Alt_L л.Ðлт Space Размакница Alt_R д.Ðлт Menu Изборник Ctrl_R д.Ктрл Shift_R д.Мењач Up Горе Left Лево Down Доле Right ДеÑно PrtSc Сликај Ins Уметни Del Бриши Home Почетак End Крај PgUp Страна изнад PgDn Страна иÑпод NumLock УКЉ/ ИСКЉ * * + + KP_Enter КП_УнеÑи KP_1 КП_1 KP_2 КП_2 KP_3 КП_3 KP_4 КП_4 KP_5 КП_5 KP_6 КП_6 KP_7 КП_7 KP_8 КП_8 KP_9 КП_9 KP_0 КП_0 SCLK SCLK Pause Пауза Super_R д.Супер Mute Мук VolDn Тише VolUp ГлаÑније Play ПуÑти Stop ЗауÑтави Prev Претходно Next Ðаредно [NO KEY] [Без таÑтера] UnixWindowInfoDialog Captured Window Properties ОÑобине откривеног прозора Information About Window Подаци о прозору Class: КлаÑа: TextLabel ТекÑÑ‚-Ð½Ð°Ñ‚Ð¿Ð¸Ñ Title: ÐаÑлов: Path: Путања: Match By Properties Прилагоди по Class клаÑи Title наÑлову Path путањи VDPad VDPad Патворен Д-таÑтер VirtualKeyPushButton Space Размакница Tab Таб Shift (L) л. Мењач Shift (R) д. Мењач Ctrl (L) л. Ктрл Ctrl (R) д. Ктрл Alt (L) л. Ðлт Alt (R) д. Ðлт ` ` ~ ~ - - = = [ [ ] ] \ \ Caps Ð’.Ñлова ; ; ' ' , , . . / / ESC Врати PRTSC Сликај SCLK SCLK INS Уметни PGUP Страна изнад DEL Бриши PGDN Страна иÑпод 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 0 0 NUM LK УКЉ/ ИСКЉ * * + + E N T E R У РЕ С И < < : : Super (L) л.Супер Menu Избор Up Горе Down Доле Left Лево Right ДеÑно VirtualKeyboardMouseWidget Keyboard ТаÑтатура Mouse Миш Mouse Settings ПоÑтавке миша Left Mouse Лево Up Mouse Горе Left Button Mouse Леви таÑтер Middle Button Mouse Средњи таÑтер Right Button Mouse ДеÑни таÑтер Wheel Up Mouse Точкић унапред Wheel Left Mouse Точкић улево Wheel Right Mouse Точкић удеÑно Wheel Down Mouse Точкић уназад Down Mouse Доле Right Mouse ДеÑно Button 4 Mouse ТаÑтер 4 Mouse 8 Mouse Миш 8 Button 5 Mouse ТаÑтер 5 Mouse 9 Mouse Миш 9 NONE ÐИШТРApplications Програми Browser Back Претходно (веб прегледник) Browser Favorites Обележивачи (веб прегледник) Browser Forward Ðаредно (веб прегледник) Browser Home Почетна Ñтрана (веб прегледник) Browser Refresh ОÑвежи (веб прегледник) Browser Search Претрага (веб прегледник) Browser Stop ЗауÑтави учитавање (веб прегледник) Calc Калкулатор Email Е-пошта Media Медији Media Next Медији — Ðаредно Media Play Медији — ПуÑти Media Previous Медији — Претходно Media Stop Медији — ЗауÑтави Search Ðађи Volume Down Тише Volume Mute Мук Volume Up ГлаÑније VirtualMousePushButton INVALID ОШТЕЋЕÐО WinAppProfileTimerDialog Capture Application Разоткриј прозор After pressing the "Capture Application" button, please select the application window that you want to have a profile associated with. The active application will be captured after the selected number of seconds. По притиÑку дугмета „Разоткриј прозор“, одаберите прозор програма који желите да повежете Ñа профилом. Разоткривање тог прозора отпочеће након иÑтека доле задатог времена. Timer: Ðакон: Seconds Ñекунди(е,а) Cancel Поништи WinExtras [NO KEY] [Без таÑтера] AntiMicro Profile Профил за Ðнти-микро X11Extras ESC Врати Tab Таб Space Размакница DEL Бриши Return УнеÑи („Return“) („Enter“) KP_Enter КП_УнеÑи Backspace Уназад xinput extension was not found. No mouse acceleration changes will occur. Ðије нађено проширење „xinput“. ÐиÑу могуће измене брзина при руковању мишем. xinput version must be at least 2.0. No mouse acceleration changes will occur. Издање проширење „xinput“ је Ñтарије од издања 2.0. ÐиÑу могуће измене брзина при руковању мишем. Virtual pointer found with id=%1. Ðађен је патворени показивач Ñа ИБ=%1. PtrFeedbackClass was not found for virtual pointer.No change to mouse acceleration will occur for device with id=%1 Ðије нађено „ÐPtrFeedbackClass“ за патворени показивач. ÐиÑу могуће измене брзина при руковању мишем за уређај чији је ИБ=%1 Changing mouse acceleration for device with id=%1 Измена убрзања при употреби миша за уређај чији је ИБ=%1 XMLConfigReader Could not write updated profile XML to file %1. Ðе могу да упишем зановљен ИкÑМЛ-профил у датотеку %1. XMLConfigWriter Could not write to profile at %1. Ðе могу да упиÑујем у профил у %1. antimicro-2.23/share/antimicro/translations/antimicro_uk.ts000066400000000000000000011515251300750276700243120ustar00rootroot00000000000000 AboutDialog About Про програму Version ВерÑÑ–Ñ Credits Розробники <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Originally developed by Travis Nickles &lt;nickles.travis@gmail.com&gt;, now maintained by the AntiMicro group at https://github.com/AntiMicro.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Contributors:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;"><br /></span>Zerro Alvein</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">aybe</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jeff Backus &lt;jeff.backus@gmail.com&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Arthur Moore<br />Anton Tornqvist &lt;antont@inbox.lv&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7185</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">DarkStarSword</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">est31</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ProfessorKaos64</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">qwerty12</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA0</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Translators:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VaGNaroK &lt;vagnarokalkimist@gmail.com&gt; - Brazilian Portuguese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx - Chinese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Belleguic Terence &lt;hizo@free.fr&gt; - French</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Leonard Koenig &lt;leonard.r.koenig@googlemail.com&gt; - German</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phob - German</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">tou omiya - Japanese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Dmitriy Koshel &lt;form.eater@gmail.com&gt; - Russian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jay Alexander Fleming &lt;tito.nehru.naser@gmail.com&gt; - Serbian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">burunduk - Ukrainian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Flavio HR &lt;flavio.hrx@gmail.com&gt; - Spanish</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA - wazaaaaa00&lt;@&gt;gmail&lt;.&gt;com - Italian</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> Changelog Since December 30, 2012, I have been working on antimicro in my spare time. What originally started as a fork of QJoyPad and a way to learn proper event-driven programming has turned into something much bigger than I originally intended. Although I have spent a lot of time learning new techniques, finding out more about the domain of KB+M emulation, and spending Friday nights bashing my head against my keyboard, it has been a fun and enriching experience overall. The need for this program came from me using similar programs on Windows to play several games that did not provide native controller support. Although some alternatives existed on Linux, there wasn't really anything that I felt was good enough in terms of functionality or in-game controls in order to really enjoy games that I wanted to play with using KB+M emulation. QJoyPad was the main program that I had used in the past although it had aged a lot and it didn't provide some basic functionality that I thought was essential. The project was dead as it had not been updated in several years so I decided to make my own. Since then, I have tried to find out what the other programs do right and then improve upon it. I have also discovered some neat tricks along the way and I have learned more about how native gamepad controls are implemented in some games than I ever really wanted to know. Although there are definitely areas where this program could improve, I find that this program offers the best in-game control experience for playing older, and some newer, games that do not provide native controller support. Development of this program is not as high of a priority for me anymore. This is mainly due to the fact that the Steam Controller works pretty well for the task of playing PC games compared to using an Xbox 360 controller. However, it does look like there is still a reason for this program to exist for a while. Copyright: 2013 - 2016 Info Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ antimicro <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">GNU GENERAL PUBLIC LICENSE</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Version 3, 29 June 2007</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Preamble</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Developers that use the GNU GPL protect your rights with two steps:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">(1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The precise terms and conditions for copying, distribution and modification follow.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">TERMS AND CONDITIONS</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">0. Definitions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;This License&quot; refers to version 3 of the GNU General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Copyright&quot; also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;The Program&quot; refers to any copyrightable work licensed under this License. Each licensee is addressed as &quot;you&quot;. &quot;Licensees&quot; and &quot;recipients&quot; may be individuals or organizations.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;modify&quot; a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a &quot;modified version&quot; of the earlier work or a work &quot;based on&quot; the earlier work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;covered work&quot; means either the unmodified Program or a work based on the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;propagate&quot; a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;convey&quot; a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An interactive user interface displays &quot;Appropriate Legal Notices&quot; to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">1. Source Code.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;source code&quot; for a work means the preferred form of the work for making modifications to it. &quot;Object code&quot; means any non-source form of a work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;Standard Interface&quot; means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;System Libraries&quot; of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A &quot;Major Component&quot;, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;Corresponding Source&quot; for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source for a work in source code form is that same work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">2. Basic Permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">3. Protecting Users' Legal Rights From Anti-Circumvention Law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">4. Conveying Verbatim Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">5. Conveying Modified Source Versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) The work must carry prominent notices stating that you modified it, and giving a relevant date.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to &quot;keep intact all notices&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an &quot;aggregate&quot; if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">6. Conveying Non-Source Forms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;User Product&quot; is either (1) a &quot;consumer product&quot;, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, &quot;normally used&quot; refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Installation Information&quot; for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">7. Additional Terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Additional permissions&quot; are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Limiting the use for publicity purposes of names of licensors or authors of the material; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All other non-permissive additional terms are considered &quot;further restrictions&quot; within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">8. Termination.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">9. Acceptance Not Required for Having Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">10. Automatic Licensing of Downstream Recipients.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An &quot;entity transaction&quot; is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">11. Patents.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;contributor&quot; is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's &quot;contributor version&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A contributor's &quot;essential patent claims&quot; are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, &quot;control&quot; includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">In the following three paragraphs, a &quot;patent license&quot; is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To &quot;grant&quot; such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. &quot;Knowingly relying&quot; means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A patent license is &quot;discriminatory&quot; if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">12. No Surrender of Others' Freedom.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">13. Use with the GNU Affero General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">14. Revised Versions of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License &quot;or any later version&quot; applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">15. Disclaimer of Warranty.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM &quot;AS IS&quot; WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">16. Limitation of Liability.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">17. Interpretation of Sections 15 and 16.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.</span></p></body></html> About Development License Ð›Ñ–Ñ†ÐµÐ½Ð·Ñ–Ñ Program Version %1 ВерÑÑ–Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¸ %1 Program Compiled on %1 at %2 Програму Ñкомпільовано %1 о %2 Built Against SDL %1 Зібрано на SDL %1 Running With SDL %1 Запущено з SDL %1 Using Qt %1 ВикориÑтано Qt %1 Using Event Handler: %1 Обробник подій: %1 AddEditAutoProfileDialog Auto Profile Dialog Вікно автоматичного профілю Profile: Профіль: Browse ОглÑнути Window: Select Window. Click on the appropriate application window and the application file path will be populated in the form. Оберіть вікно. ÐатиÑніть на вікно необхідного додатку, Ñ– шлÑÑ… до нього автоматично заповнитьÑÑ Ð² поле вводу. Detect Window Properties Class: Title: Application: Select Обрати Devices: ПриÑтрої: Select this profile to be the default loaded for the specified device. The selection will be used instead of the all default profile option. Оберіть цей профіль Ñк типовий Ð´Ð»Ñ Ð²ÐºÐ°Ð·Ð°Ð½Ð¾Ð³Ð¾ приÑтрою. Обраний профіль перекриватиме загальні Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ‚Ð¸Ð¿Ð¾Ð²Ð¾Ð³Ð¾ профілю. Set as Default for Controller Ð’Ñтановити типовим Ð´Ð»Ñ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»ÐµÑ€Ð° A different profile is already selected as the default for this device. Інший профіль вже вÑтановлено типовим Ð´Ð»Ñ Ð²ÐºÐ°Ð·Ð°Ð½Ð¾Ð³Ð¾ приÑтрою. Current (%1) Поточний (%1) Open Config Відкрити конфігурацію Select Program Обрати програму Programs (*.exe) Please use the main default profile selection. ВикориÑтовуйте оÑновний типовий профіль. Please select a window by using the mouse. Press Escape if you want to cancel. Оберіть мишкою вікно. Ðби ÑкаÑувати вибір натиÑніть Escape. Capture Application Window Ð—Ð°Ñ…Ð¾Ð¿Ð»ÐµÐ½Ð½Ñ Ð²Ñ–ÐºÐ½Ð° програми Could not obtain information for the selected window. Ðе отримано інформації Ð´Ð»Ñ Ð¾Ð±Ñ€Ð°Ð½Ð¾Ð³Ð¾ вікна. Application Capture Failed Ð—Ð°Ñ…Ð¾Ð¿Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¸ зазнало невдачі Profile file path is invalid. ШлÑÑ… до профілю хибний. No window matching property was specified. Program path is invalid or not executable. ШлÑÑ… до програми хибний, або вона не має прав на виконаннÑ. File is not an .exe file. No window matching property was selected. AdvanceButtonDialog Advanced Розширені параметри Assignments ÐŸÑ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Toggle Перемикач Turbo Турбо Set Selector Ð’Ñтановити Ñелектор Press Time Ð§Ð°Ñ Ð½Ð°Ñ‚Ð¸Ñку Insert a pause that occurs in between key presses. Ð’Ñтавте паузу між натиÑканнÑми клавіш. Pause Пауза Hold Ð£Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Mouse Mod Мод. мишки Cycle Цикл Distance ДиÑÑ‚Ð°Ð½Ñ†Ñ–Ñ Release Віджати Blank or KB/M Delay Затримка Execute Load Завантажити Set Change Text Entry Insert a new blank slot. Ð’Ñтавити новий пуÑтий Ñлот. Insert Ð’Ñтавити Delete a slot. Вилучити Ñлот. Delete Вилучити Clear all currently assigned slots. ОчиÑтити вÑÑ– поточні Ñлоти. Clear All ОчиÑтити вÑе Placeholder Заповнювач Specify the duration of an inserted Pause or Hold slot. Ð’Ñтановити триваліÑть Ñлотів Пауза чи УтриманнÑ. Time: ЧаÑ: 0.01s 0.01Ñ 0m 0хв 0 0 0s Mouse Speed Mod: Зміна швидкоÑті мишки: &Mouse Speed Mod: Set the percentage that mouse speeds will be modified by. Ð’Ñтановіть зміну швидкоÑті миші у відÑотковому Ñпіввідношенні. % % Specify the range past an axis dead zone in which a sequence of actions will execute. Distance: ДиÑтанціÑ: Auto Reset Cycle After Ðвтоматично Ñкидати цикл опіÑÐ»Ñ seconds Ñекунд Executable: ... Arguments: Enabled Включити Mode: Режим: <html><head/><body><p>Normal: Repeatedly press and release a button by the chosen rate.</p><p>Gradient: Modify the button press and button release delay based on how far an axis has been moved. The rate will remain the same.</p><p>Pulse: Modify how many times a button is pressed and released per second. The button delay will remain the same.</p></body></html> Normal Звичайний Gradient ÐароÑтаючий Pulse ПульÑуючий Delay: Затримка: 0.10s 0.10Ñ Rate: ЧаÑтота: 10.0/s 10.0/Ñ Disabled Вимкнено Select Set 1 One Way Ð’Ñтановити набір 1 одноÑтороннім Select Set 1 Two Way Ð’Ñтановити набір 1 двоÑтороннім Select Set 1 While Held Ð’Ñтановити набір 1 доки натиÑнуто Select Set 2 One Way Ð’Ñтановити набір 2 одноÑтороннім Select Set 2 Two Way Ð’Ñтановити набір 2 двоÑтороннім Select Set 2 While Held Ð’Ñтановити набір 2 доки натиÑнуто Select Set 3 One Way Ð’Ñтановити набір 3 одноÑтороннім Select Set 3 Two Way Ð’Ñтановити набір 3 двоÑтороннім Select Set 3 While Held Ð’Ñтановити набір 3 доки натиÑнуто Select Set 4 One Way Ð’Ñтановити набір 4 одноÑтороннім Select Set 4 Two Way Ð’Ñтановити набір 4 двоÑтороннім Select Set 4 While Held Ð’Ñтановити набір 4 доки натиÑнуто Select Set 5 One Way Ð’Ñтановити набір 5 одноÑтороннім Select Set 5 Two Way Ð’Ñтановити набір 5 двоÑтороннім Select Set 5 While Held Ð’Ñтановити набір 5 доки натиÑнуто Select Set 6 One Way Ð’Ñтановити набір 6 одноÑтороннім Select Set 6 Two Way Ð’Ñтановити набір 6 двоÑтороннім Select Set 6 While Held Ð’Ñтановити набір 6 доки натиÑнуто Select Set 7 One Way Ð’Ñтановити набір 7 одноÑтороннім Select Set 7 Two Way Ð’Ñтановити набір 7 двоÑтороннім Select Set 7 While Held Ð’Ñтановити набір 7 доки натиÑнуто Select Set 8 One Way Ð’Ñтановити набір 8 одноÑтороннім Select Set 8 Two Way Ð’Ñтановити набір 8 двоÑтороннім Select Set 8 While Held Ð’Ñтановити набір 8 доки натиÑнуто sec. Ñек. /sec. /Ñек. Set %1 Ðабір %1 Select Set %1 Обрати набір %1 One Way ОдноÑторонній Two Way ДвоÑторонній While Held Доки натиÑнуто Choose Executable Slots past a Cycle action will be executed on the next button press. Multiple cycles can be added in order to create partitions in a sequence. Delays the time that the next slot is activated by the time specified. Slots activated before the delay will remain active after the delay time has passed. Distance action specifies that the slots afterwards will only be executed when an axis is moved a certain range past the designated dead zone. Insert a hold action. Slots after the action will only be executed if the button is held past the interval specified. Chose a profile to load when this slot is activated. Mouse mod action will modify all mouse speed settings by a specified percentage while the action is being processed. This can be useful for slowing down the mouse while sniping. Specify the time that keys past this slot should be held down. Insert a release action. Slots after the action will only be executed after a button release if the button was held past the interval specified. Change to selected set once slot is activated. Full string will be typed when a slot is activated. Execute program when slot is activated. Choose Profile Config Files (*.amgp *.xml) AdvanceStickAssignmentDialog Stick/Pad Assignment ÐŸÑ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñтіків/хреÑтовин Sticks Стіки DPads DPad'и Note: This window is meant for backwards compatibility with profiles made before antimicro 2.0. Since version 2.0, use of the Game Controller Mapping window is preferred. %1 (Joystick %2) %1 (джойÑтик %2) Stick 1 Стік 1 Enabled Ðктивний Assign Призначити X Axis: Ð’Ñ–ÑÑŒ X: Y Axis: Ð’Ñ–ÑÑŒ Y: Stick 2 Стік 2 Number of Physical DPads: %1 КількіÑть фізичних DPad'ів: %1 Virtual DPad 1 Віртуальний DPad 1 Down: Вниз: Left: Вліво: Right: Вправо: Up: Вверх: Axis %1 Ð’Ñ–ÑÑŒ %1 Axis %1 - Ð’Ñ–ÑÑŒ %1 - Axis %1 + Ð’Ñ–ÑÑŒ %1 + Button %1 Кнопка %1 Move stick 1 along the X axis Рухайте Ñтік 1 по віÑÑ– X Move stick 1 along the Y axis Рухайте Ñтік 1 по віÑÑ– Y Move stick 2 along the X axis Рухайте Ñтік 2 по віÑÑ– X Move stick 2 along the Y axis Рухайте Ñтік 2 по віÑÑ– Y Press a button or move an axis ÐатиÑніть кнопки чи зміÑтіть віÑÑŒ AxisEditDialog Axis Ð’Ñ–ÑÑŒ Presets: Типовий набір: Mouse (Horizontal) Мишка (Горизонтально) Mouse (Inverted Horizontal) Мишка (Горизонтально інвертовано) Mouse (Vertical) Мишка (Вертикально) Mouse (Inverted Vertical) Мишка (Вертикально інвертовано) Arrows: Up | Down Стрілки: Вверх | Вниз Arrows: Left | Right Стрілки: Вліво | Вправо Keys: W | S Клавіші: W | S Keys: A | D Клавіші: A | D NumPad: KP_8 | KP_2 NumPad: KP_8 | KP_2 NumPad: KP_4 | KP_6 NumPad: KP_4 | KP_6 None ВідÑутній Set the value to use as the limit for an axis. Useful for a worn out analog stick. Dead Zone: Сліпа зона: Set the value of the dead zone for an axis. Ð’Ñтановіть Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñліпої зони Ð´Ð»Ñ Ð²Ñ–ÑÑ–. Max Zone: МакÑимальна зона: [NO KEY] [ÐЕМÐЄ КÐОПКИ] Throttle setting that determines the behavior of how to interpret an axis hold or release. Параметри Ñ‚Ñги визначають, Ñк програма має реагувати на ÑƒÑ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ñ‚Ð° натиÑÐºÐ°Ð½Ð½Ñ Ð²Ñ–ÑÑ–. Negative Half Throttle Ð—Ð²Ð¾Ñ€Ð¾Ñ‚Ð½Ñ Ð½Ð°Ð¿Ñ–Ð²Ñ‚Ñга Negative Throttle Ð—Ð²Ð¾Ñ€Ð¾Ñ‚Ð½Ñ Ñ‚Ñга Normal Звичайний Positive Throttle ПрÑма Ñ‚Ñга Positive Half Throttle ПрÑма напівтÑга Current Value: Поточне значеннÑ: Name: Ім'Ñ: Specify the name of an axis. Ðазначте ім'Ñ Ð´Ð»Ñ Ð²Ñ–ÑÑ–. Mouse Settings Параметри мишки Set Ðабір Set %1 Ðабір %1 Left Mouse Button Right Mouse Button ButtonEditDialog Dialog Діалог To make a new assignment, press any keyboard key or click a button in the Keyboard or Mouse tab Ðби зробити нове призначеннÑ, натиÑніть клавішу на клавіатурі, чи клацніть по кнопці розташованій на вкладках «Клавіатура» чи «Мишка» Placeholder Заповнювач Enables a key press or release to only occur when a controller button is pressed. ДозволÑÑ” виконувати дію тільки при натиÑканні чи відпуÑканні клавіші. Toggle Перемикач Enables rapid key presses and releases. Turbo controller. Дозволити приÑкорене натиÑÐºÐ°Ð½Ð½Ñ ÐºÐ»Ð°Ð²Ñ–Ñˆ. Турбо контролер. Turbo Турбо Current: Поточний: Slots Слоти Na&me: Specify the name of a button. Ðазначте ім'Ñ Ð´Ð»Ñ ÐºÐ½Ð¾Ð¿ÐºÐ¸. Action: ДіÑ: Specify the action that will be performed in game while this button is being used. Advanced Розширені параметри Set Ðабір Set %1 Ðабір %1 CapturedWindowInfoDialog Captured Window Properties Information About Window Class: TextLabel Title: Path: Match By Properties Class Title Path Full Path File Name CommandLineUtility Profile location %1 is not an XML file. Профіль %1 не Ñ” XML файлом. Profile location %1 does not exist. Профіль %1 не Ñ–Ñнує. Controller identifier is not a valid value. Контролер має хибне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ–Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ‚Ð¾Ñ€Ð°. No set number was specified. Ðе вказаний набір значень. No controller was specified. Жодного контролеру не було вказано. No display string was specified. Жодного Ñ€Ñдка Ð´Ð»Ñ Ð¿Ð¾ÐºÐ°Ð·Ñƒ не було вказано. An invalid event generator was specified. No event generator string was specified. Qt style flag was detected but no style was specified. No log level specified. antimicro version An invalid set number '%1' was specified. Controller identifier '%s'' is not a valid value. Usage: antimicro [options...] [profile] Options Параметри Print help text. ВивеÑти довідку. Print version information. ВивеÑти верÑÑ–ÑŽ програми. Launch program in system tray only. ЗапуÑтити програму згорнутою у ÑиÑтемний лоток. Launch program with the tray menu disabled. ЗапуÑтити програму із заблокованим меню в лотку. Launch program without the main window displayed. ЗапуÑтити програму без показу головного вікна. Launch program with the configuration file selected as the default for selected controllers. Defaults to all controllers. Apply configuration file to a specific controller. Value can be a controller index, name, or GUID. Unload currently enabled profile(s). Value can be a controller index, name, or GUID. Start joysticks on a specific set. Value can be a controller index, name, or GUID. Advance profile loading set options. Launch program as a daemon. ЗапуÑтити програму в режимі демона. Enable logging. Use specified display for X11 calls. Useful for ssh. Choose between using XTest support and uinput support for event generation. Default: xtest. Choose between using SendInput and vmulti support for event generation. Default: sendinput. Print information about joysticks detected by SDL. Open game controller mapping window of selected controller. Value can be a controller index or GUID. DPadContextMenu Mouse (Normal) Мишка (Ñтандарт) Mouse (Inverted Horizontal) Мишка (Горизонтально інвертовано) Mouse (Inverted Vertical) Мишка (Вертикально інвертовано) Mouse (Inverted Horizontal + Vertical) Мишка (Інвертовано гор.+верт.) Arrows Стрілки Keys: W | A | S | D Клавіші: W | A | S | D NumPad NumPad None ВідÑутній Standard Стандарт Eight Way Ð’Ñ–Ñім Ñторін 4 Way Cardinal 4 оÑновні Ñторони 4 Way Diagonal 4 діагональні Ñторони Mouse Settings Параметри мишки DPadEditDialog Dialog Діалог Presets: Типовий набір: Mouse (Normal) Мишка (Ñтандарт) Mouse (Inverted Horizontal) Мишка (Горизонтально інвертовано) Mouse (Inverted Vertical) Мишка (Вертикально інвертовано) Mouse (Inverted Horizontal + Vertical) Мишка (Інвертовано гор.+верт.) Arrows Стрілки Keys: W | A | S | D Клавіші: W | A | S | D NumPad NumPad None ВідÑутній Dpad Mode: Режим DPad: Standard: 8 region dpad with two direction buttons active when the dpad is in a diagonal region. Eight Way: 8 region dpad with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region dpad with regions corresponding to the cardinal directions of the dpad. Useful for menus. 4 Way Diagonal: 4 region dpad with each region corresponding to a diagonal zone. &Name: Standard Стандарт Eight Way Ð’Ñ–Ñім Ñторін 4 Way Cardinal 4 оÑновні Ñторони 4 Way Diagonal 4 діагональні Ñторони DPad Delay: Затримка DPad'а: Time lapsed before a direction change is taken into effect. Ð§Ð°Ñ Ð·Ð°Ñ‚Ñ€Ð¸Ð¼ÐºÐ¸, через Ñкий зміна напрÑмку набуде чинноÑті. s Ñ Specify the name of a dpad. Ðазначте ім'Ñ Ð´Ð»Ñ DPad. Mouse Settings Параметри мишки Set Ðабір Set %1 Ðабір %1 EditAllDefaultAutoProfileDialog Default Profile Типовий профіль Profile: Профіль: Browse ОглÑнути Open Config Відкрити конфігурацію Profile file path is invalid. ШлÑÑ… до профілю некоректний. ExtraProfileSettingsDialog Extra Profile Settings Розширені параметри профілю Key Press Time: Ð§Ð°Ñ Ð½Ð°Ñ‚Ð¸Ñку клавіші: 0.00 ms 0.00 Ð¼Ñ Profile Name: Ім'Ñ Ð¿Ñ€Ð¾Ñ„Ñ–Ð»ÑŽ: s Ñ GameController Game Controller Ігровий контролер GameControllerDPad DPad DPad GameControllerMappingDialog Game Controller Mapping Ð’Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ñ–Ð³Ñ€Ð¾Ð²Ð¾Ð³Ð¾ контролеру <html><head/><body><p>antimicro makes use of the <a href="https://wiki.libsdl.org/CategoryGameController"><span style=" text-decoration: underline; color:#0057ae;">Game Controller API</span></a> provided by SDL 2 in order to abstract various gamepads to fit a unified standard. In order to make a button assignment, please highlight the mapping cell for the appropriate button row below. You can then press a button or move an axis on your gamepad and the cell will update with the physical button or axis that will be used.</p><p>antimicro will use the mapping that you specify to save a mapping string that will be loaded into SDL.</p></body></html> A A B B X X Y Y Back Ðазад Start Старт Guide Guide Left Shoulder Ліве плече Right Shoulder Праве плече Left Stick Click Клік лівого Ñтіку Right Stick Click Клік правого Ñтіку Left Stick X Лівий Ñтік X Left Stick Y Лівий Ñтік Y Right Stick X Правий Ñтік X Right Stick Y Правий Ñтік Y Left Trigger Лівий триґер Right Trigger Правий триґер DPad Up DPad Верх DPad Left DPad Ліво DPad Down DPad Ðиз DPad Right DPad Право Mapping Ð’Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ SDL 2 Game Controller Mapping String РÑдок Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»ÐµÑ€Ñƒ від SDL 2 Last Axis Event: Current Axis Detection Dead Zone: 5000 5000 10000 10000 15000 15000 20000 20000 25000 25000 30000 30000 32000 32000 Game Controller Mapping (%1) (#%2) Ð’Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ñ–Ð³Ñ€Ð¾Ð²Ð¾Ð³Ð¾ контролеру (%1) (#%2) Discard Controller Mapping? Скинути Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»ÐµÑ€Ñƒ? Discard mapping for this controller? If discarded, the controller will be reverted to a joystick once you refresh all joysticks. GameControllerSet Back Ðазад Guide Guide Start Старт LS Click Клік ЛС RS Click Клік ПС L Shoulder Л плече R Shoulder П плече L Trigger Л триґер R Trigger П триґер GameControllerTrigger Trigger Триґер JoyAxis Axis Ð’Ñ–ÑÑŒ JoyAxisButton Button Кнопка Negative Зворотній Positive ПрÑмий Unknown Ðевідомо JoyAxisContextMenu Mouse (Horizontal) Мишка (Горизонтально) Mouse (Inverted Horizontal) Мишка (Горизонтально інвертовано) Mouse (Vertical) Мишка (Вертикально) Mouse (Inverted Vertical) Мишка (Вертикально інвертовано) Arrows: Up | Down Стрілки: Вверх | Вниз Arrows: Left | Right Стрілки: Вліво | Вправо Keys: W | S Клавіші: W | S Keys: A | D Клавіші: A | D NumPad: KP_8 | KP_2 NumPad: KP_8 | KP_2 NumPad: KP_4 | KP_6 NumPad: KP_4 | KP_6 None ВідÑутній Mouse Settings Параметри мишки Left Mouse Button Right Mouse Button JoyButton Processing turbo for #%1 - %2 Finishing turbo for button #%1 - %2 Processing press for button #%1 - %2 Processing release for button #%1 - %2 Distance change for button #%1 - %2 Button Кнопка [NO KEY] [ÐЕМÐЄ КÐОПКИ] [Set %1 1W] [Ðабір %1 1W] [Set %1 2W] [Ðабір %1 2W] [Set %1 WH] [Ðабір %1 WH] JoyButtonContextMenu Toggle Перемкнути Turbo Турбо Clear ОчиÑтити Set Select Ð’Ñтановити вибір Disabled Вимкнено Set %1 Ðабір %1 Set %1 1W Ðабір %1 1W Set %1 2W Ðабір %1 2W Set %1 WH Ðабір %1 WH JoyButtonSlot Mouse Мишка Up Вверх Down Вниз Left Вліво Right Вправо LB ЛК MB СК RB ПК B4 К4 B5 К5 Pause Пауза Hold Ð£Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Cycle Цикл Distance ДиÑÑ‚Ð°Ð½Ñ†Ñ–Ñ Release Віджати Mouse Mod Мод. мишки Press Time Ð§Ð°Ñ Ð½Ð°Ñ‚Ð¸Ñку Delay Затримка Load %1 Set Change %1 [Text] %1 [Exec] %1 [NO KEY] [ÐЕМÐЄ КÐОПКИ] JoyControlStick Stick Стік JoyControlStickButton Up Верх Down Ðиз Left Ліво Right Право Button Кнопка JoyControlStickContextMenu Mouse (Normal) Мишка (Стандарт) Mouse (Inverted Horizontal) Мишка (Горизонтально інвертовано) Mouse (Inverted Vertical) Мишка (Вертикально інвертовано) Mouse (Inverted Horizontal + Vertical) Мишка (Інвертовано гор.+верт.) Arrows Стрілки Keys: W | A | S | D Клавіші: W | A | S | D NumPad NumPad None ВідÑутній Standard Стандарт Eight Way Ð’Ñ–Ñім Ñторін 4 Way Cardinal 4 оÑновні Ñторони 4 Way Diagonal 4 діагональні Ñторони Mouse Settings Параметри мишки JoyControlStickEditDialog Dialog Діалог X: X: 0 0 Y: Y: Distance: ДиÑтанціÑ: Bearing: ÐапрÑм: % Safe Zone: % Безпечна зона: Presets: Типовий набір: Mouse (Normal) Мишка (Ñтандарт) Mouse (Inverted Horizontal) Мишка (Горизонтально інвертовано) Mouse (Inverted Vertical) Мишка (Вертикально інвертовано) Mouse (Inverted Horizontal + Vertical) Мишка (Інвертовано гор.+верт.) Arrows Стрілки Keys: W | A | S | D Клавіші: W | A | S | D NumPad NumPad None ВідÑутній Stick Mode: Режим Ñтіка: Standard: 8 region stick with two direction buttons active when the stick is in a diagonal region. Eight Way: 8 region stick with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region stick with regions corresponding to the cardinal directions of the stick. Useful for menus. 4 Way Diagonal: 4 region stick with each region corresponding to a diagonal zone of the stick. Standard Стандарт Eight Way Ð’Ñ–Ñім Ñторін 4 Way Cardinal 4 оÑновні Ñторони 4 Way Diagonal 4 діагональні Ñторони Dead Zone: Сліпа зона: Dead zone value to use for an analog stick. Max Zone: МакÑимальна зона: Value when an analog stick is considered moved 100%. Diagonal Range: Діагональний діапазон: The area (in degrees) that each diagonal region occupies. Square Stick: КвадратніÑть Ñтіку: Percentage to modify a square stick coordinates to confine values to a circle % % Stick Delay: Затримка Ñтіка: Time lapsed before a direction change is taken into effect. Ð§Ð°Ñ Ð·Ð°Ñ‚Ñ€Ð¸Ð¼ÐºÐ¸, через Ñкий зміна напрÑмку набуде чинноÑті. s Ñ Modifier: Edit button that is active while the stick is active. This button is useful for assigning zones with modifier keys that can be used to assign walk/run functionality to an analog stick. PushButton Name: Ім'Ñ: Specify the name of an analog stick. Ðазначте ім'Ñ Ð´Ð»Ñ Ð°Ð½Ð°Ð»Ð¾Ð³Ð¾Ð²Ð¾Ð³Ð¾ Ñтіка. Mouse Settings Параметри мишки Set Ðабір Set %1 Ðабір %1 JoyControlStickModifierButton Modifier JoyDPad DPad DPad JoyDPadButton Up Верх Down Ðиз Left Ліво Right Право Button Кнопка JoyTabWidget <New> <Ðовий> Remove Вилучити Remove configuration from recent list. Вилучити конфігурацію з переліку чаÑтого кориÑтуваннÑ. Load Завантажити Load configuration file. Завантажити файл конфігурації. Save Зберегти Save changes to configuration file. Зберегти зміни до файлу конфігурації. Save As Зберегти Ñк Save changes to a new configuration file. Зберегти зміни в новий файл конфігурації. Sets Ðабори Copy from Set Копіювати з набору Settings Параметри Set 1 Ðабір 1 Set 2 Ðабір 2 Set 3 Ðабір 3 Set 4 Ðабір 4 Set 5 Ðабір 5 Set 6 Ðабір 6 Set 7 Ðабір 7 Set 8 Ðабір 8 Stick/Pad Assign ÐŸÑ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñтіків/DPad Controller Mapping Ð’Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»ÐµÑ€Ñƒ Quick Set Швидкий набір Names Імена Toggle button name displaying. Перемкнути показ команд на кнопках. Pref Параметри Change global profile settings. Змінити глобальні параметри профілю. Reset Скинути Revert changes to the configuration. Reload configuration file. Відновити зміни. Перезавантажити файл конфігурації. Open Config Відкрити конфігурацію Config Files (*.amgp *.xml) Save Config Зберегти конфігурацію Config File (*.%1.amgp) Set Ðабір Save Profile Changes? Зберегти зміни профілю? Changes to the new profile have not been saved. Would you like to save or discard the current profile? Зміни до нового профілю не збережені. Зберегти Ñ—Ñ… до поточного профілю? Changes to the profile "%1" have not been saved. Would you like to save or discard changes to the current profile? Зміни до профілю "%1" не збережені. Зберегти Ñ—Ñ… до поточного профілю? Sticks Стіки DPads DPad'и No buttons have been assigned. Please use Quick Set to assign keys to buttons or disable hiding empty buttons. Жодної кнопки не назначено. ВикориÑтовуйте «Швидкий набір» Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ ÐºÐ»Ð°Ð²Ñ–Ñˆ, або ж вимкніть Ð¿Ñ€Ð¸Ñ…Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿ÑƒÑтих кнопок. Set %1: %2 Ðабір %1: %2 Set %1 Ðабір %1 Copy Set Assignments Скопіювати набір значень Are you sure you want to copy the assignments and device properties from %1? ДійÑно бажаєте Ñкопіювати Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ– влаÑтивоÑті приÑтрою з %1? Joystick Joystick ДжойÑтик JoystickStatusWindow Properties ВлаÑтивоÑті Details Деталі Name: Ім'Ñ: %1 %1 Number: КількіÑть: Axes: Ð’Ñ–ÑÑŒ: Buttons: Кнопок: Hats: Міні джойÑтиків: GUID: GUID: Game Controller: Ігровий контролер: Axes Ð’Ñ–ÑÑŒ Buttons Кнопки Hats Міні джойÑтики %1 (#%2) Properties ВлаÑтивоÑті %1 (#%2) Axis %1 Ð’Ñ–ÑÑŒ %1 Hat %1 Міні джойÑтик %1 No ÐÑ– Yes Так MainSettingsDialog Edit Settings Змінити параметри General ОÑновні Controller Mappings Ð’Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»ÐµÑ€Ñƒ Language Мова Auto Profile Ðвто-профіль Mouse Мишка <html><head/><body><p>Specify the default directory that the program should use in file dialogs when loading a profile or saving a new profile.</p></body></html> <html><head/><body><p>Вкажіть типову теку, Ñку програма викориÑтовуватиме Ð´Ð»Ñ Ð·Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ„Ñ–Ð»Ñ–Ð².</p></body></html> Recent Profile Count: КількіÑть швидких профілів: <html><head/><body><p>Number of profiles that can be placed in recent profile list. 0 will result in the program not enforcing a limit on the number of profiles displayed.</p></body></html> <html><head/><body><p>КількіÑть профілів, Ñкі будуть показані в переліку чаÑто уживаних. Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ 0 трактуєтьÑÑ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¾ÑŽ, Ñк необмежена кількіÑть профілів Ð´Ð»Ñ Ð¿Ð¾ÐºÐ°Ð·Ñƒ.</p></body></html> Gamepad Poll Rate: Change the poll rate that the program uses to discover new events from gamepads. Defaults to 10 ms. Reducing the poll rate value could cause the application to use more CPU power so please test the setting that you use before using antimicro unattended. Hide main window when the main window close button is clicked instead of quitting the program. Приховувати головне вікно кнопкою Ð·Ð°ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð¼Ñ–Ñть виходу з програми. Close To Tray Закривати до лотку Have Windows start antimicro at system startup. Launch At Windows Startup ЗапуÑкати разом із Windows Display recent profiles for all controllers as a single list in the tray menu. Defaults to using sub-menus. Виводить чаÑто уживані профілі до вÑÑ–Ñ… контролерів єдиним переліком в меню лотку. Типово викориÑтовуєтьÑÑ Ð¿Ñ–Ð´Ð¼ÐµÐ½ÑŽ. Single Profile List in Tray Один перелік профілів в лотку Have the program minimize to the taskbar. By default, the program minimizes to the system tray if available. Вказує програмі згортатиÑÑŒ до панелі завдань. Зазвичай, програма згортаєтьÑÑ Ð´Ð¾ ÑиÑтемного лотку, Ñкщо Ñ” можливіÑть. Minimize to Taskbar Згортати до панелі завдань This option will cause the program to hide all buttons that have no slots assigned to them. The Quick Set dialog window will have to be used to bring up the edit dialog for gamepad buttons. Параметр вказує програмі приховувати вÑÑ– кнопки, Ñкім не назначено жодного Ñлоту. ВикориÑтовуйте діалог «Швидкий набір» аби повернути діалог Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ½Ð¾Ð¿Ð¾Ðº ігрового контролера. Hide Empty Buttons Приховати пуÑті кнопки When the program is launched, open the last known profile that was opened during the previous session. Під Ñ‡Ð°Ñ Ð·Ð°Ð¿ÑƒÑку програми, відкриваєтьÑÑ Ð¾Ñтанній відомий профіль, Ñкий був відкритий у попередній ÑеÑÑ–Ñ—. Auto Load Last Opened Profile Ðвтоматично завантажувати оÑтанній відкритий профіль Only show the system tray icon when the program first launches. Показувати лише піктограму в ÑиÑтемному лотку під Ñ‡Ð°Ñ Ð¿ÐµÑ€ÑˆÐ¾Ð³Ð¾ запуÑку. Launch in Tray ЗапуÑкати в лотку Associate .amgp files with antimicro in Windows Explorer. Associate Profiles Прив'Ñзати профілі Key Repeat Повтор клавіш Active keys will be repeatedly pressed when this option is enabled. Ðктивні клавіші повторно натиÑкатимутьÑÑ ÐºÐ¾Ð»Ð¸ цей параметр активний. Enable Specifies how much time should elapse before key repeating begins. Specifies how many times key presses will be performed per seconds. <html><head/><body><p>antimicro has been translated into many different languages by contributors. By default, the program will choose an appropriate translation based on your system's locale setting. However, you can make antimicro load a different translation depending on the language that you choose from the list below.</p></body></html> French Italian Japanese Russian Serbian Simplified Chinese Ukrainian Class Title Program Disable the "Enhanced Pointer Precision" Windows setting while antimicro is running. Disabling "Enhanced Pointer Precision" will allow mouse movement within antimicro to be more precise. Disable Enhance Pointer Precision Smoothing Histor&y Size: Weight &Modifier: Refresh Rate: The refresh rate is the amount of time that will elapse in between mouse events. Please be cautious when editing this setting as it will cause the program to use more CPU power. Setting this value too low can cause system instability. Please test the setting before using it unattended. Spring Пружинний Screen: Utilize the specified screen for spring mode. On Linux, the default is to use the primary screen. On Windows, the default is to use all available screens. Accel Numerator: 0 0 Accel Denominator: Accel Threshold: If the acceleration values for the virtual mouse have been changed by a different process, particularly when quitting an older game, then you might want to reset the acceleration values used by the virtual mouse. Reset Acceleration Delay: Затримка: Profi&le Directory: ms Ð¼Ñ Rate: ЧаÑтота: times/s разів/Ñ Below is a list of the custom mappings that have been saved. You can use the following table to delete mappings or have mappings temporarily disabled. You can also disable mappings that are included with SDL; just insert a new row with the appropriate joystick GUID and check disable. Settings will not take affect until you either refresh all joysticks or unplug that particular joystick. GUID GUID Mapping String РÑдок Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Disable? Вимкнути? Delete Вилучити Insert Ð’Ñтавити Default Типова Brazilian Portuguese Brazilian Portuguese English English German German Active Ðктивний Devices: ПриÑтрої: All Ð’ÑÑ– Device ПриÑтрій Profile Профіль Default? Типовий? Add Додати Edit Змінити Also, Windows users who want to use a low value should also check the "Disable Enhance Pointer Precision" checkbox if you haven't disabled the option in Windows. Select Default Profile Directory Обрати типову теку профілю Are you sure you want to delete the profile? ДійÑно вилучити профіль? MainWindow antimicro No Joysticks have been found. Please plug in a joystick and then choose the "Update Joysticks" option in the main menu Ðе знайдено жодного джойÑтика. Будь лаÑка, під'єднайте джойÑтик, Ñ– натиÑніть пункт «Оновити джойÑтики» в головному меню If events are not seen by a game, please click here to run this application as the Adminstrator. Якщо події в грі не ÑпоÑтерігаютьÑÑ, натиÑніть тут, аби запуÑтити програму з правами ÐдмініÑтратора. &App Прогр&ама &Options &Параметри &Help &Допомога &Quit &Вихід Ctrl+Q Ctrl+Q &Update Joysticks &Оновити джойÑтики Ctrl+U Ctrl+U &Hide &Згорнути Ctrl+H Ctrl+H &About Пр&о програму Ctrl+A Ctrl+A About Qt Про Qt Properties ВлаÑтивоÑті Key Checker Перевірка клавіш Home Page Ð”Ð¾Ð¼Ð°ÑˆÐ½Ñ Ñторінка GitHub Page Сторінка на GitHub Game Controller Mapping Ð’Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ñ–Ð³Ñ€Ð¾Ð²Ð¾Ð³Ð¾ контролеру Settings Параметри Stick/Pad Assign ÐŸÑ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñтіків/DPad Wiki Wiki Could not find a proper controller identifier. Exiting. (%1) (%1) Open File Відкрити файл &Restore &Відновити Run as Administrator? ЗапуÑтити із правами ÐдмініÑтратора? Are you sure that you want to run this program as Adminstrator? Some games run as Administrator which will cause events generated by antimicro to not be used by those games unless antimicro is also run as the Adminstrator. This is due to permission problems caused by User Account Control (UAC) options in Windows Vista and later. Failed to elevate program Ðе вдалоÑÑ Ð¿Ñ–Ð´Ð½Ñти права програмі Failed to restart this program as the Administrator Ðе вдалоÑÑŒ перезапуÑтити програму із правами ÐдмініÑтратора Could not find controller. Exiting. MouseAxisSettingsDialog Mouse Settings - Параметри мишки - Set %1 Ðабір %1 MouseButtonSettingsDialog Mouse Settings - Параметри мишки - Set %1 Ðабір %1 MouseControlStickSettingsDialog Mouse Settings Параметри мишки Set %1 Ðабір %1 MouseDPadSettingsDialog Mouse Settings Параметри мишки Set %1 Ðабір %1 MouseSettingsDialog Mouse Settings Параметри мишки Mouse Mode: Режим мишки: Cursor mode is used to move the mouse cursor around the screen relative to its current position depending on how much you move an axis or if a button is pressed. Spring mode is used to move the mouse cursor from the center of the screen depending on how much you move an axis. The mouse cursor will be returned to the center of the screen when the axis is moved back to the dead zone. Cursor КурÑор Spring Пружинний Acceleration: ПриÑкореннÑ: Enhanced Precision Покращена точніÑть Linear Лінійне Quadratic Квадратичне Cubic Кубічне Quadratic Extreme ЕкÑтремально квадратичне Power Function По Ñтепеневій функції Easing Quadratic ПроÑте квадратичне Easing Cubic ПроÑте кубічне Mouse Speed Settings Параметри швидкоÑті мишки Enable to change the horizontal and vertical speed boxes at the same time. Змінювати Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð³Ð¾Ð¸Ð·Ð¾Ð½Ñ‚Ð°Ð»ÑŒÐ½Ð¾Ñ— та вертикальної швидкоÑті разом. Change Together Змінювати разом Options for adding more acceleration to the mouse movement beyond what the acceleration curve would produce. Acceleration is added based on how quickly an axis is moved in one gamepad poll. This is meant to help work around some of the issues of the very limited input range available using typical gamepad analog sticks. Delta Acceleration &Multiplier: Mi&n Threshold: E&xtra Duration: Horizontal Speed: Горизонтальна швидкіÑть: 1 = 20 pps 1 = 20 pps Vertical Speed: Вертикальна швидкіÑть: Wheel Hori. Speed: Коліщатко горизонт.: Set the speed used for horizontal mouse wheel movement according to number of simulated notches per second. Ð’Ñтановіть швидкіÑть Ð´Ð»Ñ Ð³Ð¾Ñ€Ð¸Ð·Ð¾Ð½Ñ‚Ð°Ð»ÑŒÐ½Ð¾Ñ— прокрутки коліщатка миші відноÑно від чиÑла ÑимулÑції кроків за Ñекунду. 1 = 1 notch(es)/s 1 = 1 крок(ів)/Ñ Wheel Vert. Speed: Коліщатко вертикаль.: Set the speed used for vertical mouse wheel movement according to number of simulated notches per second. Ð’Ñтановіть швидкіÑть Ð´Ð»Ñ Ð²ÐµÑ€Ñ‚Ð¸ÐºÐ°Ð»ÑŒÐ½Ð¾Ñ— прокрутки коліщатка миші відноÑно від чиÑла ÑимулÑції кроків за Ñекунду. Sensitivity: ЧутливіÑть: For Power Function acceleration curve. Specifies the factor to use for curve sensitivity. When the value is above 1.0, the mouse movement will be accelerated faster at the low end of an axis. Easing Duration: % % Enhanced: Three tier curve that makes the mouse move slow on the low end of an axis and fast on the high end. Linear: Mouse moves proportionally to axis. Quadratic: Mouse accelerates slowly on low end. Cubic: Mouse accelerates slower than Quadratic. Quadratic Extreme: Raises mouse speed 1.5 times once 95% axis travel has been reached. Power Function: Allows for a more custom curve option. Easing Quadratic: Axis high end is gradually accelerated over a period of time using a Quadratic curve. Easing Cubic: Axis high end is gradually accelerated over a period of time using a Cubic curve. Hori&zontal Speed: &Vertical Speed: Sensitivit&y: Specifies the amount of time (in seconds) that will be required before the mouse is fully accelerated after reaching the high end of an axis. s Ñ Highest value to accelerate mouse movement by x x Start %: Acceleration begins at this percentage of the base multiplier Minimum amount of axis travel required for acceleration to begin Max Threshold: Maximum axis travel before acceleration has reached the multiplier value Extend the time that extra acceleration is applied. Axis travel will be taken into account. A slower flick will decrease the actual time that extra acceleration will be applied. Curve: Ease Out Sine Ease Out Quad Ease Out Cubic Spring Settings Параметри пружини Spring Width: Ширина пружини: Changes the width of the region that the cursor can move in spring mode. 0 will use the entire width of your screen. Spring Height: ВиÑота пружини: Changes the height of the region that the cursor can move in spring mode. 0 will use the entire height of your screen. Release Radius: Specifies that the spring area will be relative to the mouse position set by a non-relative spring. Relative ВідноÑний Mouse Status Стан мишки X: X: 0 (0 pps) 0 (0 pps) Y: Y: %n notch(es)/s %n крок/Ñ %n кроки/Ñ %n кроків/Ñ QKeyDisplayDialog Key Checker Перевірка клавіш <html><head/><body><p>Press a key on your keyboard to see how the key is detected by this application. The window will show the system native key value, the original value given by Qt (if applicable), and the custom value used by antimicro.</p><p>The antimicro key value and the Qt key value will usually be the same. antimicro tries to use the key values defined in Qt when possible. Check the page <a href="https://doc.qt.io/qt-4.8/qt.html#Key-enum"><span style=" text-decoration: underline; color:#0057ae;">https://doc.qt.io/qt-4.8/qt.html#Key-enum</span></a> for a list of values defined by Qt. If you discover that a key is not natively supported by this program, please report the problem to antimicro's <a href="https://github.com/AntiMicro/antimicro"><span style=" text-decoration: underline; color:#0057ae;">GitHub page</span></a> so that the program can be edited to support it directly. As it is, a custom prefix is added to unknown values so they can still be used; the main problem is that the profile will no longer be portable.</p></body></html> Event Handler: Обробник подій: Native Key Value: Ðативне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ ÐºÐ»Ð°Ð²Ñ–ÑˆÑ–: 0x00000000 0x00000000 Qt Key Value: Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ ÐºÐ»Ð°Ð²Ñ–ÑˆÑ– Qt: antimicro Key Value: QObject Daemon launched Демон завантажений Failed to launch daemon Помилка під Ñ‡Ð°Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð´ÐµÐ¼Ð¾Ð½Ñƒ Launching daemon ЗапуÑк демона Display string "%1" is not valid. Виведений Ñ€Ñдок «%1» не Ñ” вірним. Failed to set a signature id for the daemon Failed to change working directory to / Ðе вдалоÑÑŒ змінити робочу теку на / Quitting Program # of joysticks found: %1 # джойÑтиків знайдено: %1 List Joysticks: Перелік джойÑтиків: --------------- --------------- Joystick %1: ДжойÑтик %1: Index: %1 ІндекÑ: %1 GUID: %1 GUID: %1 Name: %1 Ім'Ñ: %1 Yes Так No ÐÑ– Game Controller: %1 Ігровий контролер: %1 # of Axes: %1 # Ð’Ñ–ÑÑ–: %1 # of Buttons: %1 # Кнопок: %1 # of Hats: %1 # Міні-падів: %1 Attempting to use fallback option %1 for event generation. Failed to open event generator. Exiting. Using %1 as the event generator. Could not raise process priority. Super Super Menu Меню Mute Mute Vol+ Vol+ Vol- Vol- Play/Pause Play/Pause Play Play Pause Pause Prev Prev Next Next Mail Пошта Home Home Media Media Search Пошук QuickSetDialog Quick Set Швидкий набір <html><head/><body><p>Please press a button or move an axis on %1 (<span style=" font-weight:600;">%2</span>).<br/>A dialog window will then appear which will<br/>allow you to make an assignment.</p></body></html> <html><head/><body><p>ÐатиÑніть кнопку, чи зміÑтіть віÑÑŒ по %1 (<span style=" font-weight:600;">%2</span>).<br/>З'ÑвитьÑÑ Ð´Ñ–Ð°Ð»Ð¾Ð³Ð¾Ð²Ðµ вікно<br/>в Ñкому зможете зробити переназначеннÑ.</p></body></html> Quick Set %1 Швидкий набір %1 SetAxisThrottleDialog Throttle Change Зміна Ñ‚Ñги The throttle setting for Axis %1 has been changed. Would you like to distribute this throttle change to all sets? Параметри Ñ‚Ñги були змінені Ð´Ð»Ñ Ð²Ñ–ÑÑ– %1. ЗаÑтоÑувати ці зміни до вÑÑ–Ñ… наборів? SetJoystick Set %1: %2 Ðабір %1: %2 Set %1 Ðабір %1 SetNamesDialog Set Name Settings Параметри наборів Set 1 Ðабір 1 Set 2 Ðабір 2 Set 3 Ðабір 3 Set 4 Ðабір 4 Set 5 Ðабір 5 Set 6 Ðабір 6 Set 7 Ðабір 7 Set 8 Ðабір 8 Name Ім'Ñ SimpleKeyGrabberButton Mouse Мишка SpringModeRegionPreview Spring Mode Preview ПереглÑд пружинного режиму UInputEventHandler Could not find a valid uinput device file. Please check that you have the uinput module loaded. lsmod | grep uinput Ðе можливо знайти прийнÑтний файл приÑтрою uinput. Перевірте, чи завантажений модуль uinput. lsmod | grep uinput Could not open uinput device file Please check that you have permission to write to the device Ðеможливо відкрити uinput файл приÑтрою Перевірте, чи маєте ви права на Ð·Ð°Ð¿Ð¸Ñ Ð´Ð¾ приÑтрою Using uinput device file %1 UInputHelper a a b b c c d d e e f f g g h h i i j j k k l l m m n n o o p p q q r r s s t t u u v v w w x x y y z z Esc Esc F1 F1 F2 F2 F3 F3 F4 F4 F5 F5 F6 F6 F7 F7 F8 F8 F9 F9 F10 F10 F11 F11 F12 F12 ` ` 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 0 0 - - = = BackSpace BackSpace Tab Tab [ [ ] ] \ \ CapsLock CapsLock ; ; ' ' Enter Enter Shift_L Shift_Л , , . . / / Ctrl_L Ctrl_Л Super_L Super_Л Alt_L Alt_Л Space Пробіл Alt_R Alt_П Menu Меню Ctrl_R Ctrl_П Shift_R Shift_П Up Вверх Left Вліво Down Вниз Right Вправо PrtSc PrtSc Ins Ins Del Del Home Home End End PgUp PgUp PgDn PgDn NumLock NumLock * * + + KP_Enter KP_Enter KP_1 KP_1 KP_2 KP_2 KP_3 KP_3 KP_4 KP_4 KP_5 KP_5 KP_6 KP_6 KP_7 KP_7 KP_8 KP_8 KP_9 KP_9 KP_0 KP_0 SCLK SCLK Pause Pause Super_R Super_П Mute Mute VolDn VolDn VolUp VolUp Play Play Stop Stop Prev Prev Next Next [NO KEY] [ÐЕМÐЄ КÐОПКИ] UnixWindowInfoDialog Captured Window Properties Information About Window Class: TextLabel Title: Path: Match By Properties Class Title Path VDPad VDPad VDPad VirtualKeyPushButton Space Пробіл Tab Tab Shift (L) Shift (Л) Shift (R) Shift (П) Ctrl (L) Ctrl (Л) Ctrl (R) Ctrl (П) Alt (L) Alt (Л) Alt (R) Alt (П) ` ` ~ ~ - - = = [ [ ] ] \ \ Caps Caps ; ; ' ' , , . . / / ESC ESC PRTSC PRTSC SCLK SCLK INS INS PGUP PGUP DEL DEL PGDN PGDN 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 0 0 NUM LK NUM LK * * + + E N T E R E N T E R < < : : Super (L) Super (Л) Menu Меню Up Вверх Down Вниз Left Вліво Right Вправо VirtualKeyboardMouseWidget Keyboard Клавіатура Mouse Мишка Left Mouse Вліво Up Mouse Вверх Left Button Mouse Ліва кнопка Middle Button Mouse Ð¡ÐµÑ€ÐµÐ´Ð½Ñ ÐºÐ½Ð¾Ð¿ÐºÐ° Right Button Mouse Права кнопка Wheel Up Mouse Коліщатко вверх Wheel Left Mouse Коліщатко вліво Wheel Right Mouse Коліщатко вправо Wheel Down Mouse Коліщатко вниз Down Mouse Вниз Right Mouse Вправо Button 4 Mouse Кнопка 4 Mouse 8 Mouse Мишка 8 Button 5 Mouse Кнопка 5 Mouse 9 Mouse Мишка 9 Mouse Settings Параметри мишки NONE ВідÑутній Applications Browser Back Browser Favorites Browser Forward Browser Home Browser Refresh Browser Search Browser Stop Calc Email Media Media Media Next Media Play Media Previous Media Stop Search Пошук Volume Down Volume Mute Volume Up VirtualMousePushButton INVALID ХИБÐИЙ WinAppProfileTimerDialog Capture Application Захопити програму After pressing the "Capture Application" button, please select the application window that you want to have a profile associated with. The active application will be captured after the selected number of seconds. ПіÑÐ»Ñ Ð½Ð°Ñ‚Ð¸ÑÐºÐ°Ð½Ð½Ñ Â«Ð—Ð°Ñ…Ð¾Ð¿Ð¸Ñ‚Ð¸ програму», зробіть активним вікно програм, Ñку ви хочете прив'Ñзати до поточного профілю. Ðктивне вікно буде захоплено через вказаний проміжок чаÑу. Timer: Таймер: Seconds Секунд Cancel СкаÑувати WinExtras [NO KEY] [ÐЕМÐЄ КÐОПКИ] AntiMicro Profile AntiMicro профіль X11Extras ESC ESC Tab Tab Space Пробіл DEL DEL Return Return KP_Enter KP_Enter Backspace Backspace xinput extension was not found. No mouse acceleration changes will occur. Ð Ð¾Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð½Ñ xinput не знайдено. Зміна швидкоÑті миші не викориÑтовуєтьÑÑ. xinput version must be at least 2.0. No mouse acceleration changes will occur. ВерÑÑ–Ñ xinput має бути вище 2.0. Зміна швидкоÑті миші не викориÑтовуєтьÑÑ. Virtual pointer found with id=%1. Віртуальний вказівник знайдено із id=%1. PtrFeedbackClass was not found for virtual pointer.No change to mouse acceleration will occur for device with id=%1 Ðе знайдено PtrFeedbackClass Ð´Ð»Ñ Ð²Ñ–Ñ€Ñ‚ÑƒÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ вказівника. Зміна швидкоÑті миші не викориÑтовуєтьÑÑ Ð´Ð»Ñ Ð¿Ñ€Ð¸Ñтрою із id=%1 Changing mouse acceleration for device with id=%1 Зміна приÑÐºÐ¾Ñ€ÐµÐ½Ð½Ñ Ð¼Ð¸ÑˆÐºÐ¸ Ð´Ð»Ñ Ð¿Ñ€Ð¸Ñтрою із id=%1 XMLConfigReader Could not write updated profile XML to file %1. Ðеможливо запиÑати оновлений профіль до файлу %1. XMLConfigWriter Could not write to profile at %1. Ðеможливо запиÑати профіль Ñк %1. antimicro-2.23/share/antimicro/translations/antimicro_zh_CN.ts000066400000000000000000013362131300750276700246730ustar00rootroot00000000000000 AboutDialog About 关于 antimicro antimicro Version 版本 Info ä¿¡æ¯ Changelog 更新日志 Since December 30, 2012, I have been working on antimicro in my spare time. What originally started as a fork of QJoyPad and a way to learn proper event-driven programming has turned into something much bigger than I originally intended. Although I have spent a lot of time learning new techniques, finding out more about the domain of KB+M emulation, and spending Friday nights bashing my head against my keyboard, it has been a fun and enriching experience overall. The need for this program came from me using similar programs on Windows to play several games that did not provide native controller support. Although some alternatives existed on Linux, there wasn't really anything that I felt was good enough in terms of functionality or in-game controls in order to really enjoy games that I wanted to play with using KB+M emulation. QJoyPad was the main program that I had used in the past although it had aged a lot and it didn't provide some basic functionality that I thought was essential. The project was dead as it had not been updated in several years so I decided to make my own. Since then, I have tried to find out what the other programs do right and then improve upon it. I have also discovered some neat tricks along the way and I have learned more about how native gamepad controls are implemented in some games than I ever really wanted to know. Although there are definitely areas where this program could improve, I find that this program offers the best in-game control experience for playing older, and some newer, games that do not provide native controller support. Development of this program is not as high of a priority for me anymore. This is mainly due to the fact that the Steam Controller works pretty well for the task of playing PC games compared to using an Xbox 360 controller. However, it does look like there is still a reason for this program to exist for a while. 自2012å¹´12月30日以æ¥ï¼Œæˆ‘利用业余时间编写 antimicroã€‚è¿™ä¸ªé¡¹ç›®æœ¬æ¥æ˜¯ QJoyPad 的派生,用æ¥å­¦ä¹ äº‹ä»¶é©±åŠ¨ç¼–ç¨‹ï¼Œæ²¡æƒ³åˆ°è§„æ¨¡å˜å¾—å¦‚æ­¤ä¹‹å¤§ã€‚å°½ç®¡æˆ‘èŠ±äº†å¾ˆå¤šæ—¶é—´åŽ»å­¦ä¹ æ–°çš„æŠ€å·§ã€æŽ¢ç´¢é”®é¼ æ¨¡æ‹Ÿçš„é¢†åŸŸã€æ¯å‘¨äº”晚上用头撞键盘,我ä»ç„¶è§‰å¾—这是一段有趣并且充实的ç»åŽ†ã€‚ 对这个程åºçš„éœ€æ±‚æ¥æºäºŽæˆ‘想在 Windows 上使用类似的程åºçŽ©ä¸€äº›åŽŸç”Ÿä¸æ”¯æŒæ‰‹æŸ„的游æˆã€‚虽然 Linux 上有其它替代å“,但是我并没有找到在功能上或者游æˆå†…控制足够好,以至于我å¯ä»¥ä½¿ç”¨é”®é¼ æ¨¡æ‹Ÿæ¥äº«å—游æˆçš„工具。QJoyPad 是我过去主è¦ä½¿ç”¨çš„工具,尽管它éžå¸¸å¤è€è€Œä¸”ä¸æä¾›ä¸€äº›æˆ‘è®¤ä¸ºéžå¸¸å…³é”®çš„功能。那个项目已ç»åœæ­¢å¼€å‘很多年,所以我决定编写一个我自己的工具。 ä»Žé‚£æ—¶èµ·ï¼Œæˆ‘ä¸æ–­å¯»æ‰¾å…¶å®ƒç¨‹åºçš„长处,然åŽåœ¨å®ƒä»¬çš„基础上继续开å‘。在此期间,我还å‘现了一些ä¸é”™çš„å°æŠ€å·§ï¼Œå¹¶ä¸”å­¦åˆ°äº†å¾ˆå¤šå…³äºŽæ¸¸æˆå¦‚ä½•å®žçŽ°åŽŸç”Ÿæ”¯æŒæ‰‹æŸ„çš„çŸ¥è¯†ã€‚è¿™äº›çŸ¥è¯†è¿œè¿œå¹¿äºŽæˆ‘ä¹‹å‰æƒ³å­¦çš„范围。尽管 antimicro 还有很多å¯ä»¥æ”¹è¿›çš„地方,我还是认为它æä¾›äº†æœ€å¥½çš„æ¸¸æˆå†…控制体验,ä¸ç®¡æ˜¯é’ˆå¯¹è€ä¸€äº›è¿˜æ˜¯æ–°ä¸€äº›çš„åŽŸç”Ÿä¸æ”¯æŒæ‰‹æŸ„的游æˆã€‚ å¼€å‘这个程åºå¯¹æˆ‘æ¥è¯´å·²ç»ä¸åƒä»¥å¾€é‚£æ ·é«˜ä¼˜å…ˆçº§äº†ã€‚è¿™ä¸»è¦æ˜¯å› ä¸ºç›¸æ¯”较 Xbox 360 手柄æ¥è¯´ï¼ŒSteam 手柄å¯ä»¥å¾ˆå¥½åœ°è¿›è¡Œ PC 游æˆã€‚然而,这个程åºä¼¼ä¹Žä»ç„¶æœ‰ç†ç”±å†å­˜åœ¨ä¸€æ®µæ—¶é—´ã€‚ Copyright: 2013 - 2016 版æƒï¼š2013 - 2016 Credits 致谢 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Originally developed by Travis Nickles &lt;nickles.travis@gmail.com&gt;, now maintained by the AntiMicro group at https://github.com/AntiMicro.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Contributors:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;"><br /></span>Zerro Alvein</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">aybe</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jeff Backus &lt;jeff.backus@gmail.com&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Arthur Moore<br />Anton Tornqvist &lt;antont@inbox.lv&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7185</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">DarkStarSword</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">est31</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ProfessorKaos64</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">qwerty12</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA0</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Translators:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VaGNaroK &lt;vagnarokalkimist@gmail.com&gt; - Brazilian Portuguese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx - Chinese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Belleguic Terence &lt;hizo@free.fr&gt; - French</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Leonard Koenig &lt;leonard.r.koenig@googlemail.com&gt; - German</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phob - German</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">tou omiya - Japanese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Dmitriy Koshel &lt;form.eater@gmail.com&gt; - Russian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jay Alexander Fleming &lt;tito.nehru.naser@gmail.com&gt; - Serbian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">burunduk - Ukrainian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Flavio HR &lt;flavio.hrx@gmail.com&gt; - Spanish</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA - wazaaaaa00&lt;@&gt;gmail&lt;.&gt;com - Italian</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">原作者 Travis Nickles &lt;nickles.travis@gmail.com&gt;。<br />现由 AntiMicro å¼€å‘组 (https://github.com/AntiMicro) 维护。</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">贡献者:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;"><br /></span>Zerro Alvein</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">aybe</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jeff Backus &lt;jeff.backus@gmail.com&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Arthur Moore<br />Anton Tornqvist &lt;antont@inbox.lv&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7185</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">DarkStarSword</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">est31</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ProfessorKaos64</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">qwerty12</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA0</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">翻译:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VaGNaroK &lt;vagnarokalkimist@gmail.com&gt; - 巴西葡è„牙语</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx - 简体中文</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Belleguic Terence &lt;hizo@free.fr&gt; - 法语</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Leonard Koenig &lt;leonard.r.koenig@googlemail.com&gt; - 德语</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phob - 德语</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">tou omiya - 日语</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Dmitriy Koshel &lt;form.eater@gmail.com&gt; - 俄语</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jay Alexander Fleming &lt;tito.nehru.naser@gmail.com&gt; - 塞尔维亚语</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">burunduk - 乌克兰语</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Flavio HR &lt;flavio.hrx@gmail.com&gt; - 西ç­ç‰™è¯­</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA - wazaaaaa00&lt;@&gt;gmail&lt;.&gt;com - æ„大利语</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">GNU GENERAL PUBLIC LICENSE</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Version 3, 29 June 2007</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Preamble</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Developers that use the GNU GPL protect your rights with two steps:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">(1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The precise terms and conditions for copying, distribution and modification follow.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">TERMS AND CONDITIONS</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">0. Definitions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;This License&quot; refers to version 3 of the GNU General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Copyright&quot; also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;The Program&quot; refers to any copyrightable work licensed under this License. Each licensee is addressed as &quot;you&quot;. &quot;Licensees&quot; and &quot;recipients&quot; may be individuals or organizations.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;modify&quot; a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a &quot;modified version&quot; of the earlier work or a work &quot;based on&quot; the earlier work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;covered work&quot; means either the unmodified Program or a work based on the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;propagate&quot; a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;convey&quot; a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An interactive user interface displays &quot;Appropriate Legal Notices&quot; to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">1. Source Code.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;source code&quot; for a work means the preferred form of the work for making modifications to it. &quot;Object code&quot; means any non-source form of a work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;Standard Interface&quot; means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;System Libraries&quot; of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A &quot;Major Component&quot;, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;Corresponding Source&quot; for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source for a work in source code form is that same work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">2. Basic Permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">3. Protecting Users' Legal Rights From Anti-Circumvention Law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">4. Conveying Verbatim Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">5. Conveying Modified Source Versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) The work must carry prominent notices stating that you modified it, and giving a relevant date.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to &quot;keep intact all notices&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an &quot;aggregate&quot; if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">6. Conveying Non-Source Forms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;User Product&quot; is either (1) a &quot;consumer product&quot;, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, &quot;normally used&quot; refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Installation Information&quot; for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">7. Additional Terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Additional permissions&quot; are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Limiting the use for publicity purposes of names of licensors or authors of the material; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All other non-permissive additional terms are considered &quot;further restrictions&quot; within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">8. Termination.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">9. Acceptance Not Required for Having Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">10. Automatic Licensing of Downstream Recipients.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An &quot;entity transaction&quot; is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">11. Patents.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;contributor&quot; is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's &quot;contributor version&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A contributor's &quot;essential patent claims&quot; are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, &quot;control&quot; includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">In the following three paragraphs, a &quot;patent license&quot; is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To &quot;grant&quot; such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. &quot;Knowingly relying&quot; means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A patent license is &quot;discriminatory&quot; if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">12. No Surrender of Others' Freedom.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">13. Use with the GNU Affero General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">14. Revised Versions of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License &quot;or any later version&quot; applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">15. Disclaimer of Warranty.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM &quot;AS IS&quot; WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">16. Limitation of Liability.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">17. Interpretation of Sections 15 and 16.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.</span></p></body></html> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">GNU GENERAL PUBLIC LICENSE</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Version 3, 29 June 2007</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Preamble</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Developers that use the GNU GPL protect your rights with two steps:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">(1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The precise terms and conditions for copying, distribution and modification follow.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">TERMS AND CONDITIONS</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">0. Definitions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;This License&quot; refers to version 3 of the GNU General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Copyright&quot; also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;The Program&quot; refers to any copyrightable work licensed under this License. Each licensee is addressed as &quot;you&quot;. &quot;Licensees&quot; and &quot;recipients&quot; may be individuals or organizations.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;modify&quot; a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a &quot;modified version&quot; of the earlier work or a work &quot;based on&quot; the earlier work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;covered work&quot; means either the unmodified Program or a work based on the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;propagate&quot; a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;convey&quot; a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An interactive user interface displays &quot;Appropriate Legal Notices&quot; to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">1. Source Code.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;source code&quot; for a work means the preferred form of the work for making modifications to it. &quot;Object code&quot; means any non-source form of a work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;Standard Interface&quot; means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;System Libraries&quot; of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A &quot;Major Component&quot;, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;Corresponding Source&quot; for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source for a work in source code form is that same work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">2. Basic Permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">3. Protecting Users' Legal Rights From Anti-Circumvention Law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">4. Conveying Verbatim Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">5. Conveying Modified Source Versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) The work must carry prominent notices stating that you modified it, and giving a relevant date.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to &quot;keep intact all notices&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an &quot;aggregate&quot; if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">6. Conveying Non-Source Forms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;User Product&quot; is either (1) a &quot;consumer product&quot;, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, &quot;normally used&quot; refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Installation Information&quot; for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">7. Additional Terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Additional permissions&quot; are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Limiting the use for publicity purposes of names of licensors or authors of the material; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All other non-permissive additional terms are considered &quot;further restrictions&quot; within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">8. Termination.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">9. Acceptance Not Required for Having Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">10. Automatic Licensing of Downstream Recipients.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An &quot;entity transaction&quot; is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">11. Patents.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;contributor&quot; is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's &quot;contributor version&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A contributor's &quot;essential patent claims&quot; are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, &quot;control&quot; includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">In the following three paragraphs, a &quot;patent license&quot; is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To &quot;grant&quot; such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. &quot;Knowingly relying&quot; means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A patent license is &quot;discriminatory&quot; if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">12. No Surrender of Others' Freedom.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">13. Use with the GNU Affero General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">14. Revised Versions of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License &quot;or any later version&quot; applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">15. Disclaimer of Warranty.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM &quot;AS IS&quot; WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">16. Limitation of Liability.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">17. Interpretation of Sections 15 and 16.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.</span></p></body></html> About Development å…³äºŽå¼€å‘ License è®¸å¯ Program Version %1 程åºç‰ˆæœ¬ %1 Program Compiled on %1 at %2 编译时间 %1 %2 Built Against SDL %1 使用 SDL %1 构建 Running With SDL %1 使用 SDL %1 è¿è¡Œ Using Qt %1 使用 Qt %1 Using Event Handler: %1 使用事件处ç†ç¨‹åºï¼š%1 AddEditAutoProfileDialog Auto Profile Dialog 自动é…ç½®æ–‡ä»¶å¯¹è¯æ¡† Profile: é…置文件: Browse æµè§ˆ Window: 窗å£: Select Window. Click on the appropriate application window and the application file path will be populated in the form. 选择窗å£ã€‚ å•击应用程åºçš„窗å£ï¼Œç¨‹åºæ–‡ä»¶è·¯å¾„将被自动填入表格。 Detect Window Properties 检测窗å£å±žæ€§ Class: 类: Title: 标题: Application: 应用程åºï¼š Select 选择 Devices: 设备: Select this profile to be the default loaded for the specified device. The selection will be used instead of the all default profile option. 将这个é…置文件设定为上述设备的默认é…置文件。 这个é…置文件将å–代全局默认é…置文件选项。 Set as Default for Controller 设为上述设备的默认é…置文件 A different profile is already selected as the default for this device. 这个设备已被指定了å¦ä¸€ä¸ªä¸åŒçš„默认é…置文件。 Current (%1) å½“å‰ (%1) Open Config 打开é…置文件 Select Program é€‰æ‹©ç¨‹åº Programs (*.exe) ç¨‹åº (*.exe) Please use the main default profile selection. 请使用全局默认é…置文件选项。 Please select a window by using the mouse. Press Escape if you want to cancel. 请使用鼠标选择窗å£ã€‚按 Esc 键喿¶ˆã€‚ Capture Application Window æ•æ‰åº”用程åºçª—å£ Could not obtain information for the selected window. 无法获得所选窗å£çš„ä¿¡æ¯ã€‚ Application Capture Failed åº”ç”¨ç¨‹åºæ•æ‰å¤±è´¥ Profile file path is invalid. é…置文件路径无效。 No window matching property was specified. 未指定窗å£åŒ¹é…属性。 Program path is invalid or not executable. 程åºè·¯å¾„无效或éžå¯æ‰§è¡Œæ–‡ä»¶ã€‚ File is not an .exe file. æ–‡ä»¶ä¸æ˜¯ .exe 文件。 No window matching property was selected. 未选择窗å£åŒ¹é…属性。 AdvanceButtonDialog Advanced 高级选项 Assignments åˆ†é… Toggle 开关 Turbo è¿žå‘ Set Selector 设置选择器 Blank or KB/M 空白或键鼠 Hold 按下 Pause æš‚åœ Cycle 周期 Distance è·ç¦» Insert æ’å…¥ Delete 删除 Clear All 清除所有 Time: 时间: 0.01s 0.01ç§’ 0s 0ç§’ Insert a pause that occurs in between key presses. 在按键间æ’入暂åœã€‚ Release 释放 Insert a new blank slot. æ’入新动作。 Delete a slot. 删除所选动作。 Clear all currently assigned slots. 清除所有动作。 Specify the duration of an inserted Pause or Hold slot. 为“暂åœâ€æˆ–“按下â€åŠ¨ä½œæŒ‡å®šæ‰€éœ€æ—¶é•¿ã€‚ 0m 0分 &Mouse Speed Mod: 鼠标速度更改 (&M): Specify the range past an axis dead zone in which a sequence of actions will execute. 为“è·ç¦»â€åŠ¨ä½œæŒ‡å®šæ‰€éœ€çš„è¶…è¿‡ä¸çµæ•区的è·ç¦»ã€‚ Distance: è·ç¦»ï¼š % % Mouse Mod é¼ æ ‡å˜é€Ÿ Press Time 按下时间 Delay 延迟 Execute è¿è¡Œ Load 载入 Set Change è®¾ç½®æ”¹å˜ Text Entry 文本键入 Placeholder å ä½ç¬¦ 0 0 Set the percentage that mouse speeds will be modified by. 设置鼠标移动速度百分比。 Auto Reset Cycle After 在此时间之åŽå–消未完æˆçš„“周期â€åŠ¨ä½œ seconds ç§’ Executable: 坿‰§è¡Œæ–‡ä»¶ï¼š ... ... Arguments: 傿•°ï¼š Enabled å¯ç”¨ Mode: 模å¼ï¼š <html><head/><body><p>Normal: Repeatedly press and release a button by the chosen rate.</p><p>Gradient: Modify the button press and button release delay based on how far an axis has been moved. The rate will remain the same.</p><p>Pulse: Modify how many times a button is pressed and released per second. The button delay will remain the same.</p></body></html> <html><head/><body><p>正常:以所选频率é‡å¤æŒ‰ä¸‹å¹¶é‡Šæ”¾æŒ‰é”®ã€‚</p><p>梯度:根æ®è½´ç§»åŠ¨å¹…åº¦è°ƒæ•´æŒ‰é’®è¢«æŒ‰ä¸‹å’Œé‡Šæ”¾çš„å»¶è¿Ÿã€‚é¢‘çŽ‡ä¿æŒä¸å˜ã€‚</p><p>脉冲:调整æ¯ç§’æŒ‰é’®è¢«æŒ‰ä¸‹å’Œé‡Šæ”¾çš„æ¬¡æ•°ã€‚æŒ‰é’®å»¶è¿Ÿä¿æŒä¸å˜ã€‚</p></body></html> Normal 正常 Gradient 梯度 Pulse 脉冲 Delay: 延迟: 0.10s 0.10ç§’ Rate: 频率: 10.0/s 10.0/ç§’ Disabled ç¦ç”¨ Select Set 1 One Way å•å‘选择设置1 Select Set 1 Two Way åŒå‘选择设置1 Select Set 1 While Held 按下时选择设置1 Select Set 2 One Way å•å‘选择设置2 Select Set 2 Two Way åŒå‘选择设置2 Select Set 2 While Held 按下时选择设置2 Select Set 3 One Way å•å‘选择设置3 Select Set 3 Two Way åŒå‘选择设置3 Select Set 3 While Held 按下时选择设置3 Select Set 4 One Way å•å‘选择设置4 Select Set 4 Two Way åŒå‘选择设置4 Select Set 4 While Held 按下时选择设置4 Select Set 5 One Way å•å‘选择设置5 Select Set 5 Two Way åŒå‘选择设置5 Select Set 5 While Held 按下时选择设置5 Select Set 6 One Way å•å‘选择设置6 Select Set 6 Two Way åŒå‘选择设置6 Select Set 6 While Held 按下时选择设置6 Select Set 7 One Way å•å‘选择设置7 Select Set 7 Two Way åŒå‘选择设置7 Select Set 7 While Held 按下时选择设置7 Select Set 8 One Way å•å‘选择设置8 Select Set 8 Two Way åŒå‘选择设置8 Select Set 8 While Held 按下时选择设置8 sec. 秒。 /sec. /秒。 Set %1 设置%1 Select Set %1 选择设置%1 One Way å•å‘ Two Way åŒå‘ While Held 按下时 Choose Executable é€‰æ‹©å¯æ‰§è¡Œæ–‡ä»¶ Slots past a Cycle action will be executed on the next button press. Multiple cycles can be added in order to create partitions in a sequence. “周期â€åŠ¨ä½œä¹‹åŽçš„åŠ¨ä½œå°†åœ¨ä¸‹ä¸€æ¬¡æŒ‰ä¸‹ç›¸åŒæŒ‰é’®çš„æ—¶å€™è¢«æ‰§è¡Œã€‚å¯ä»¥æ·»åŠ å¤šä¸ªâ€œå‘¨æœŸâ€åŠ¨ä½œæ¥åˆ›å»ºä¸€ä¸ªæŒ‰é”®åºåˆ—中ä¸åŒçš„å­åºåˆ—。 Delays the time that the next slot is activated by the time specified. Slots activated before the delay will remain active after the delay time has passed. æ ¹æ®æŒ‡å®šæ—¶é•¿å»¶è¿Ÿä¸‹ä¸ªåŠ¨ä½œå¼€å§‹æ‰§è¡Œçš„æ—¶é—´ã€‚å»¶è¿Ÿä¹‹å‰å¤„于活动状æ€çš„动作将在延迟结æŸåŽä¿æŒæ´»åŠ¨çŠ¶æ€ã€‚ Distance action specifies that the slots afterwards will only be executed when an axis is moved a certain range past the designated dead zone. “è·ç¦»â€åŠ¨ä½œä¹‹åŽçš„åŠ¨ä½œåªæœ‰åœ¨è½´ç§»å‡ºä¸çµæ•区并超过指定è·ç¦»ä¹‹åŽæ‰ä¼šè¢«æ‰§è¡Œã€‚ Insert a hold action. Slots after the action will only be executed if the button is held past the interval specified. æ’入一个“按下â€åŠ¨ä½œã€‚â€œæŒ‰ä¸‹â€åŠ¨ä½œä¹‹åŽçš„åŠ¨ä½œåªæœ‰åœ¨æŒ‰é’®è¢«æŒ‰ä¸‹è¶…è¿‡æŒ‡å®šçš„æ—¶é•¿ä¹‹åŽæ‰ä¼šè¢«æ‰§è¡Œã€‚ Chose a profile to load when this slot is activated. 当该动作被执行时,载入所选é…置文件。 Mouse mod action will modify all mouse speed settings by a specified percentage while the action is being processed. This can be useful for slowing down the mouse while sniping. “鼠标å˜é€Ÿâ€åŠ¨ä½œè¢«å¤„ç†æ—¶ï¼Œå°†æ ¹æ®æŒ‡å®šçš„ç™¾åˆ†æ¯”æ”¹å˜æ‰€æœ‰é¼ æ ‡é€Ÿåº¦ã€‚è¿™å¯ä»¥ç”¨åœ¨ç‹™å‡»æ—¶å‡ç¼“鼠标速度。 Specify the time that keys past this slot should be held down. æŒ‰é’®è¢«æŒ‰ä¸‹è¶…è¿‡æŒ‡å®šçš„æ—¶é•¿å°†ä¿æŒè¢«æŒ‰ä¸‹çš„状æ€ã€‚ Insert a release action. Slots after the action will only be executed after a button release if the button was held past the interval specified. æ’入一个“释放â€åŠ¨ä½œã€‚â€œé‡Šæ”¾â€åŠ¨ä½œä¹‹åŽçš„åŠ¨ä½œåªæœ‰åœ¨æŒ‰é’®è¢«æŒ‰ä¸‹è¶…è¿‡æŒ‡å®šæ—¶é•¿å¹¶è¢«é‡Šæ”¾ä¹‹åŽæ‰ä¼šè¢«æ‰§è¡Œã€‚ Change to selected set once slot is activated. 该动作被执行时,切æ¢åˆ°æ‰€é€‰çš„设置。 Full string will be typed when a slot is activated. 当该动作被执行时,整个字符串将被键入。 Execute program when slot is activated. 当该动作被执行时,è¿è¡Œä¸€ä¸ªç¨‹åºã€‚ Choose Profile 选择é…置文件 Config Files (*.amgp *.xml) é…置文件 (*.amgp *.xml) AdvanceStickAssignmentDialog Stick/Pad Assignment 摇æ†/åå­—é”®åˆ†é… Sticks æ‘‡æ† DPads åå­—é”® %1 (Joystick %2) %1(手柄%2) Stick 1 手柄1 Enabled å¯ç”¨ Assign åˆ†é… X Axis: Xè½´: Y Axis: Y轴: Stick 2 手柄2 Number of Physical DPads: %1 物ç†å字键数:%1 Virtual DPad 1 虚拟åå­—é”®1 Up: 上: Down: 下: Note: This window is meant for backwards compatibility with profiles made before antimicro 2.0. Since version 2.0, use of the Game Controller Mapping window is preferred. 注æ„ï¼šè¿™ä¸ªçª—å£æ˜¯ä¸ºäº†å…¼å®¹ antimicro 2.0 版之å‰åˆ›å»ºçš„é…置文件。自 antimicro 2.0 起,推èä½¿ç”¨æ¸¸æˆæŽ§åˆ¶å™¨æ˜ å°„çª—å£ã€‚ Left: 左: Right: å³ï¼š Axis %1 è½´%1 Axis %1 - è½´%1 - Axis %1 + è½´%1 + Button %1 按钮%1 Move stick 1 along the X axis 沿X轴移动摇æ†1 Move stick 1 along the Y axis 沿Y轴移动摇æ†1 Move stick 2 along the X axis 沿X轴移动摇æ†2 Move stick 2 along the Y axis 沿Y轴移动摇æ†2 Press a button or move an axis 按任æ„键或移动任æ„è½´ AxisEditDialog Axis è½´ Mouse (Horizontal) 鼠标(水平) Mouse (Inverted Horizontal) 鼠标(水平翻转) Mouse (Vertical) 鼠标(垂直) Mouse (Inverted Vertical) 鼠标(垂直翻转) Arrows: Up | Down æ–¹å‘键:上|下 Arrows: Left | Right æ–¹å‘键:左|å³ Keys: W | S 按键:W | S Keys: A | D 按键:A | D NumPad: KP_8 | KP_2 数字键盘:8 | 2 NumPad: KP_4 | KP_6 数字键盘:4 | 6 None æ—  Set the value to use as the limit for an axis. Useful for a worn out analog stick. 设置轴的最大值。 å¯¹è€æ—§ç£¨æŸçš„æ¨¡æ‹Ÿæ‘‡æ†å°¤å…¶æœ‰å¸®åŠ©ã€‚ Negative Half Throttle è´ŸåŠé˜€ Positive Half Throttle æ­£åŠé˜€ Name: å称: Specify the name of an axis. 指定轴的å称。 Mouse Settings 鼠标设置 Set the value of the dead zone for an axis. 设置轴的ä¸çµæ•区。 Presets: 预设: Dead Zone: ä¸çµæ•区: Max Zone: 最大区: [NO KEY] [无按键] Throttle setting that determines the behavior of how to interpret an axis hold or release. 阀设置决定如何判断一个轴的按下和释放。 Negative Throttle 负阀 Normal 正常 Positive Throttle 正阀 Current Value: 当å‰å€¼ï¼š Set 设置 Set %1 设置%1 Left Mouse Button 鼠标左键 Right Mouse Button é¼ æ ‡å³é”® ButtonEditDialog Dialog å¯¹è¯æ¡† To make a new assignment, press any keyboard key or click a button in the Keyboard or Mouse tab è‹¥æƒ³åˆ†é…æŒ‰é”®ï¼Œè¯·æŒ‰é”®ç›˜ä¸Šä»»æ„键或在键盘ã€é¼ æ ‡é¡µä¸Šç‚¹å‡»æŒ‰é’® Placeholder å ä½ç¬¦ Toggle 开关 Enables a key press or release to only occur when a controller button is pressed. å½“æ¸¸æˆæŽ§åˆ¶å™¨æŒ‰é’®è¢«æŒ‰ä¸‹æ—¶ï¼ŒæŒ‰ä¸‹æˆ–é‡Šæ”¾æŸä¸ªæŒ‰é”®ï¼Œå¹¶ä¸€ç›´ä¿æŒæ­¤çжæ€ã€‚ Enables rapid key presses and releases. Turbo controller. 快速按下和释放æŸä¸ªé”®ã€‚ è¿žå‘æ¸¸æˆæŽ§åˆ¶å™¨ã€‚ Turbo è¿žå‘ Current: 当å‰ï¼š Slots 动作 Na&me: åç§° (&m): Specify the name of a button. 指定按钮的å称。 Action: 动作: Specify the action that will be performed in game while this button is being used. 指定游æˆä¸­è¿™ä¸ªæŒ‰é’®è¢«æŒ‰ä¸‹æ—¶çš„动作。 Advanced 高级选项 Set 设置 Set %1 设置%1 CapturedWindowInfoDialog Captured Window Properties æ•获的窗å£å±žæ€§ Information About Window 窗å£ä¿¡æ¯ Class: 类: TextLabel 文本标签 Title: 标题: Path: 路径: Match By Properties æ ¹æ®å±žæ€§åŒ¹é… Class ç±» Title 标题 Path 路径 Full Path 全路径 File Name 文件å CommandLineUtility Profile location %1 is not an XML file. é…置文件 %1 䏿˜¯ä¸€ä¸ª XML 文件。 Profile location %1 does not exist. é…置文件 %1 ä¸å­˜åœ¨ã€‚ An invalid set number '%1' was specified. æŒ‡å®šçš„è®¾ç½®ç¼–å· "%1" 无效。 Controller identifier '%s'' is not a valid value. æ¸¸æˆæŽ§åˆ¶å™¨æ ‡è¯†ç¬¦ "%s" 无效。 No display string was specified. 未指定显示字符串。 Controller identifier is not a valid value. æ¸¸æˆæŽ§åˆ¶å™¨æ ‡è¯†ç¬¦æ— æ•ˆã€‚ No set number was specified. 未指定设置编å·ã€‚ No controller was specified. æœªæŒ‡å®šæ¸¸æˆæŽ§åˆ¶å™¨ã€‚ An invalid event generator was specified. 指定的事件å‘生器无效。 No event generator string was specified. 未指定事件å‘生器字符串。 Qt style flag was detected but no style was specified. 检测到 Qt æ ·å¼æ ‡è¯†ï¼Œä½†æœªæŒ‡å®šæ ·å¼ã€‚ No log level specified. 未指定日志级别。 antimicro version antimicro 版本 Usage: antimicro [options...] [profile] 用法:antimicro [选项] [é…置文件] Options 选项 Print help text. 打å°å¸®åŠ©æ–‡æœ¬ã€‚ Print version information. 打å°ç‰ˆæœ¬ä¿¡æ¯ã€‚ Launch program in system tray only. å¯åŠ¨åŽæœ€å°åŒ–到系统托盘。 Launch program with the tray menu disabled. å¯åЍåŽç¦ç”¨ç³»ç»Ÿæ‰˜ç›˜èœå•。 Launch program without the main window displayed. å¯åЍåŽä¸æ˜¾ç¤ºä¸»çª—å£ã€‚ Launch program with the configuration file selected as the default for selected controllers. Defaults to all controllers. å¯åЍåŽå°†æŒ‡å®šçš„é…置文件作为默认é…ç½®æ–‡ä»¶ã€‚é»˜è®¤åº”ç”¨åˆ°æ‰€æœ‰æ¸¸æˆæŽ§åˆ¶å™¨ã€‚ Apply configuration file to a specific controller. Value can be a controller index, name, or GUID. 应用é…ç½®æ–‡ä»¶åˆ°æŒ‡å®šçš„æ¸¸æˆæŽ§åˆ¶å™¨ã€‚å€¼å¯ä»¥æ˜¯ç¼–å·ã€å称或全局唯一标识符。 Unload currently enabled profile(s). Value can be a controller index, name, or GUID. å¸è½½å½“å‰ç”Ÿæ•ˆçš„é…置文件。值å¯ä»¥æ˜¯æŽ§åˆ¶å™¨ç¼–å·ã€å称或全局唯一标识符。 Start joysticks on a specific set. Value can be a controller index, name, or GUID. ä¸ºæ‘‡æ†æŒ‡å®šè®¾ç½®ç¼–å·ã€‚值å¯ä»¥æ˜¯æŽ§åˆ¶å™¨ç¼–å·ã€å称或全局唯一标识符。 Advance profile loading set options. 切æ¢åˆ°ä¸‹ä¸€ä¸ªé…置文件载入选项。 Launch program as a daemon. 以åŽå°æœåŠ¡æ–¹å¼å¯åŠ¨ç¨‹åºã€‚ Enable logging. 开坿—¥å¿—。 Use specified display for X11 calls. Useful for ssh. 为 X11 调用指定显示设备。对 ssh 尤其有用。 Choose between using XTest support and uinput support for event generation. Default: xtest. 为事件å‘生器选择 XTest æ”¯æŒæˆ– uinput 支æŒã€‚默认:XTest。 Choose between using SendInput and vmulti support for event generation. Default: sendinput. 为事件å‘生器选择使用 SendInput 或 vmulti 支æŒã€‚默认:SendInput。 Print information about joysticks detected by SDL. æ‰“å° SDL 检测到的摇æ†ã€‚ Open game controller mapping window of selected controller. Value can be a controller index or GUID. ä¸ºæ‰€é€‰çš„æ¸¸æˆæŽ§åˆ¶å™¨æ‰“å¼€æ¸¸æˆæŽ§åˆ¶å™¨æ˜ å°„çª—å£ã€‚值å¯ä»¥æ˜¯æŽ§åˆ¶å™¨ç¼–å·æˆ–全局唯一标识符。 DPadContextMenu Mouse (Normal) 鼠标(正常) Mouse (Inverted Horizontal) 鼠标(水平翻转) Mouse (Inverted Vertical) 鼠标(垂直翻转) Mouse (Inverted Horizontal + Vertical) 鼠标(水平翻转 + 垂直翻转) Arrows æ–¹å‘é”® Keys: W | A | S | D 按键:W | A | S | D NumPad 数字键盘 None æ—  Standard 标准 Eight Way å…«å‘ 4 Way Cardinal æ­£å››å‘ 4 Way Diagonal æ–œå››å‘ Mouse Settings 鼠标设置 DPadEditDialog Dialog å¯¹è¯æ¡† Presets: 预设: Mouse (Normal) 鼠标(正常) Mouse (Inverted Horizontal) 鼠标(水平翻转) Mouse (Inverted Vertical) 鼠标(垂直翻转) Mouse (Inverted Horizontal + Vertical) 鼠标(水平翻转 + 垂直翻转) Arrows æ–¹å‘é”® Keys: W | A | S | D 按键:W | A | S | D NumPad 数字键盘 None æ—  Dpad Mode: å字键模å¼ï¼š &Name: åç§° (&N): 4 Way Cardinal æ­£å››å‘ 4 Way Diagonal æ–œå››å‘ DPad Delay: å字键延迟: Time lapsed before a direction change is taken into effect. æ–¹å‘æ”¹å˜ç”Ÿæ•ˆå‰çš„延迟。 s ç§’ Specify the name of a dpad. 指定å字键的å称。 Mouse Settings 鼠标设置 Standard 标准 Standard: 8 region dpad with two direction buttons active when the dpad is in a diagonal region. Eight Way: 8 region dpad with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region dpad with regions corresponding to the cardinal directions of the dpad. Useful for menus. 4 Way Diagonal: 4 region dpad with each region corresponding to a diagonal zone. 标准:å字键有八个区域。当å字键处于对角线区域时,两个方å‘çš„æŒ‰é”®åŒæ—¶è¢«æ¿€æ´»ã€‚ å…«å‘:å字键有八个区域。æ¯ä¸ªåŒºåŸŸæœ‰è‡ªå·±çš„æ–¹å‘按键。åŒä¸€æ—¶é—´ä»…æœ‰ä¸€ä¸ªæ–¹å‘æŒ‰é”®è¢«æ¿€æ´»ã€‚尤其适用于类 Rouge 游æˆã€‚ 正四å‘:å字键有四个区域,分别对应上下左å³å››ä¸ªæ–¹å‘。尤其适用于èœå•选择。 斜四å‘:å字键有四个区域,分别对应对角线的四个方å‘。 Eight Way å…«å‘ Set 设置 Set %1 设置%1 EditAllDefaultAutoProfileDialog Default Profile 默认é…置文件 Profile: é…置文件: Browse æµè§ˆ Open Config 打开é…置文件 Profile file path is invalid. é…置文件路径无效。 ExtraProfileSettingsDialog Extra Profile Settings 附加é…置文件设置 Key Press Time: 按键按下时间: 0.00 ms 0.00毫秒 Profile Name: é…置文件å称: s ç§’ GameController Game Controller æ¸¸æˆæŽ§åˆ¶å™¨ GameControllerDPad DPad åå­—é”® GameControllerMappingDialog Game Controller Mapping æ¸¸æˆæŽ§åˆ¶å™¨æ˜ å°„ <html><head/><body><p>antimicro makes use of the <a href="https://wiki.libsdl.org/CategoryGameController"><span style=" text-decoration: underline; color:#0057ae;">Game Controller API</span></a> provided by SDL 2 in order to abstract various gamepads to fit a unified standard. In order to make a button assignment, please highlight the mapping cell for the appropriate button row below. You can then press a button or move an axis on your gamepad and the cell will update with the physical button or axis that will be used.</p><p>antimicro will use the mapping that you specify to save a mapping string that will be loaded into SDL.</p></body></html> <html><head/><body><p>antimicro 使用 SDL 2 çš„<a href="https://wiki.libsdl.org/CategoryGameController"><span style=" text-decoration: underline; color:#0057ae;">æ¸¸æˆæŽ§åˆ¶å™¨åº”ç”¨ç¨‹åºæŽ¥å£</span></a>把å„å¼å„样的手柄进行抽象,使它们适用于统一的标准。若è¦è¿›è¡ŒæŒ‰é’®åˆ†é…,请选择下é¢ç›¸åº”的按钮映射å•å…ƒæ ¼ã€‚ä¹‹åŽæ‚¨å¯ä»¥æŒ‰ä¸€ä¸ªæŒ‰é’®æˆ–者移动手柄上的一个轴,映射å•元格将更新以匹é…è¿™ä¸ªç‰©ç†æŒ‰é”®æˆ–轴。</p><p>antimicro 将把您指定的映射ä¿å­˜ä¸ºä¸€ä¸ªå­—符串,而这个字符串将被加载到 SDL 中。</p></body></html> A Aé”® B Bé”® X Xé”® Y Yé”® Back åŽé€€é”® Start 开始键 Guide 导航键 Left Shoulder 左肩键 Right Shoulder å³è‚©é”® Left Stick Click 左摇æ†ç‚¹å‡» Right Stick Click 峿‘‡æ†ç‚¹å‡» Left Stick X 左摇æ†Xè½´ Left Stick Y 左摇æ†Yè½´ Right Stick X 峿‘‡æ†Xè½´ Right Stick Y 峿‘‡æ†Yè½´ Left Trigger 左扳机 Right Trigger 峿‰³æœº DPad Up å字键上 DPad Left å字键左 DPad Down å字键下 DPad Right åå­—é”®å³ Mapping 映射 SDL 2 Game Controller Mapping String SDL æ¸¸æˆæŽ§åˆ¶å™¨æ˜ å°„å­—ç¬¦ä¸² Last Axis Event: 最近轴事件: Current Axis Detection Dead Zone: 当å‰è½´ä¸çµæ•区: 5000 5000 10000 10000 15000 15000 20000 20000 25000 25000 30000 30000 32000 32000 Game Controller Mapping (%1) (#%2) æ¸¸æˆæŽ§åˆ¶å™¨æ˜ å°„ (%1) (#%2) Discard Controller Mapping? æ”¾å¼ƒä¿®æ”¹æ¸¸æˆæŽ§åˆ¶å™¨æ˜ å°„ï¼Ÿ Discard mapping for this controller? If discarded, the controller will be reverted to a joystick once you refresh all joysticks. æ”¾å¼ƒä¿®æ”¹è¿™ä¸ªæ¸¸æˆæŽ§åˆ¶å™¨çš„æ˜ å°„ï¼Ÿ å¦‚æžœæ”¾å¼ƒï¼Œè¿™ä¸ªæ¸¸æˆæŽ§åˆ¶å™¨å°†åœ¨æ‚¨åˆ·æ–°æ‰€æœ‰æ‘‡æ†æ—¶è¢«é‡æ–°è¯†åˆ«ä¸ºä¸€ä¸ªæ‘‡æ†ã€‚ GameControllerSet Back åŽé€€é”® Guide 导航键 Start 开始键 LS Click 左摇æ†ç‚¹å‡» RS Click 峿‘‡æ†ç‚¹å‡» L Shoulder 左肩键 R Shoulder å³è‚©é”® L Trigger 左扳机 R Trigger 峿‰³æœº GameControllerTrigger Trigger 扳机 JoyAxis Axis è½´ JoyAxisButton Negative è´Ÿ Positive æ­£ Unknown 未知 Button 按钮 JoyAxisContextMenu Mouse (Horizontal) 鼠标(水平) Mouse (Inverted Horizontal) 鼠标(水平翻转) Mouse (Vertical) 鼠标(垂直) Mouse (Inverted Vertical) 鼠标(垂直翻转) Arrows: Up | Down æ–¹å‘键:上|下 Arrows: Left | Right æ–¹å‘键:左|å³ Keys: W | S 按键:W | S Keys: A | D 按键:A | D NumPad: KP_8 | KP_2 数字键盘:8 | 2 NumPad: KP_4 | KP_6 数字键盘:4 | 6 None æ—  Mouse Settings 鼠标设置 Left Mouse Button 鼠标左键 Right Mouse Button é¼ æ ‡å³é”® JoyButton Processing turbo for #%1 - %2 æ­£åœ¨å¤„ç†æŒ‰é’®#%1-%2çš„è¿žå‘ Finishing turbo for button #%1 - %2 æ­£åœ¨å®ŒæˆæŒ‰é’®#%1-%2çš„è¿žå‘ Processing press for button #%1 - %2 æ­£åœ¨å¤„ç†æŒ‰ä¸‹æŒ‰é’®#%1-%2 Processing release for button #%1 - %2 正在处ç†é‡Šæ”¾æŒ‰é’®#%1-%2 Distance change for button #%1 - %2 按钮#%1-%2è·ç¦»æ”¹å˜ Button 按钮 [NO KEY] [无按键] [Set %1 1W] [å•å‘选择设置%1] [Set %1 2W] [åŒå‘选择设置%1] [Set %1 WH] [按下时选择设置%1] JoyButtonContextMenu Toggle 开关 Turbo è¿žå‘ Clear 清除 Set Select 选择设置 Disabled ç¦ç”¨ Set %1 设置%1 Set %1 1W å•å‘选择设置%1 Set %1 2W åŒå‘选择设置%1 Set %1 WH 按下时选择设置%1 JoyButtonSlot Mouse é¼ æ ‡ Up 上 Down 下 Left å·¦ Right å³ LB 鼠标左键 MB 鼠标中键 RB é¼ æ ‡å³é”® B4 按钮4 B5 按钮5 Pause æš‚åœ Hold 按下 Cycle 周期 Distance è·ç¦» Release 释放 Mouse Mod é¼ æ ‡å˜é€Ÿ Press Time 按下时间 Delay 延迟 Load %1 载入%1 Set Change %1 设置改å˜%1 [Text] %1 [文本]%1 [Exec] %1 [è¿è¡Œ]%1 [NO KEY] [无按键] JoyControlStick Stick æ‘‡æ† JoyControlStickButton Up 上 Down 下 Left å·¦ Right å³ Button 按钮 JoyControlStickContextMenu Mouse (Normal) 鼠标(正常) Mouse (Inverted Horizontal) 鼠标(水平翻转) Mouse (Inverted Vertical) 鼠标(垂直翻转) Mouse (Inverted Horizontal + Vertical) 鼠标(水平翻转 + 垂直翻转) Arrows æ–¹å‘é”® Keys: W | A | S | D 按键:W | A | S | D NumPad 数字键盘 None æ—  Standard 标准 Eight Way å…«å‘ 4 Way Cardinal æ­£å››å‘ 4 Way Diagonal æ–œå››å‘ Mouse Settings 鼠标设置 JoyControlStickEditDialog Dialog å¯¹è¯æ¡† X: X轴: 0 0 Y: Y轴: Distance: è·ç¦»ï¼š Presets: 预设: Mouse (Normal) 鼠标(正常) Mouse (Inverted Horizontal) 鼠标(水平翻转) Mouse (Inverted Vertical) 鼠标(垂直翻转) Mouse (Inverted Horizontal + Vertical) 鼠标(水平翻转 + 垂直翻转) Arrows æ–¹å‘é”® Keys: W | A | S | D 按键:W | A | S | D NumPad 数字键盘 None æ—  Stick Mode: æ‘‡æ†æ¨¡å¼ï¼š Standard: 8 region stick with two direction buttons active when the stick is in a diagonal region. Eight Way: 8 region stick with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region stick with regions corresponding to the cardinal directions of the stick. Useful for menus. 4 Way Diagonal: 4 region stick with each region corresponding to a diagonal zone of the stick. æ ‡å‡†ï¼šæ‘‡æ†æœ‰å…«ä¸ªåŒºåŸŸã€‚当摇æ†å¤„于对角线区域时,两个方å‘çš„æŒ‰é”®åŒæ—¶è¢«æ¿€æ´»ã€‚ å…«å‘ï¼šæ‘‡æ†æœ‰å…«ä¸ªåŒºåŸŸã€‚æ¯ä¸ªåŒºåŸŸæœ‰è‡ªå·±çš„æ–¹å‘按键。åŒä¸€æ—¶é—´ä»…æœ‰ä¸€ä¸ªæ–¹å‘æŒ‰é”®è¢«æ¿€æ´»ã€‚尤其适用于类 Rouge 游æˆã€‚ 正四å‘ï¼šæ‘‡æ†æœ‰å››ä¸ªåŒºåŸŸï¼Œåˆ†åˆ«å¯¹åº”上下左å³å››ä¸ªæ–¹å‘。尤其适用于èœå•选择。 斜四å‘ï¼šæ‘‡æ†æœ‰å››ä¸ªåŒºåŸŸï¼Œåˆ†åˆ«å¯¹åº”对角线的四个方å‘。 4 Way Cardinal æ­£å››å‘ 4 Way Diagonal æ–œå››å‘ Dead zone value to use for an analog stick. 设置模拟摇æ†çš„ä¸çµæ•区。 Value when an analog stick is considered moved 100%. 设置模拟摇æ†çš„æœ€å¤§å€¼ã€‚当达到这个值时,模拟摇æ†è¢«è®¤ä¸ºç§»åŠ¨åˆ°äº†100%çš„ä½ç½®ã€‚ The area (in degrees) that each diagonal region occupies. æ¯ä¸ªå¯¹è§’线区域的角度数。 Square Stick: 方形摇æ†ï¼š Percentage to modify a square stick coordinates to confine values to a circle 这个百分比用æ¥è°ƒæ•´æ–¹å½¢æ‘‡æ†çš„åæ ‡å€¼ä½¿å…¶è¢«é™åˆ¶åœ¨ä¸€ä¸ªåœ†é‡Œ % % Stick Delay: 摇æ†å»¶è¿Ÿï¼š Time lapsed before a direction change is taken into effect. æ–¹å‘æ”¹å˜ç”Ÿæ•ˆå‰çš„延迟。 s ç§’ Modifier: 修饰键: Edit button that is active while the stick is active. This button is useful for assigning zones with modifier keys that can be used to assign walk/run functionality to an analog stick. 编辑当摇æ†è¢«æ¿€æ´»æ—¶åŒæ—¶æ¿€æ´»çš„æŒ‰é’®ã€‚ 这个按钮尤其适用于分é…带有修饰键的区域,例如在模拟摇æ†ä¸Šåˆ†é…行走/跑步的功能。 PushButton 按钮 Name: å称: Specify the name of an analog stick. 指定模拟摇æ†çš„å称。 Mouse Settings 鼠标设置 Standard 标准 Bearing: æ–¹å‘: % Safe Zone: 安全区(%): Eight Way å…«å‘ Dead Zone: ä¸çµæ•区: Max Zone: 最大区: Diagonal Range: 对角线区域范围: Set 设置 Set %1 设置%1 JoyControlStickModifierButton Modifier 修饰 JoyDPad DPad åå­—é”® JoyDPadButton Up 上 Down 下 Left å·¦ Right å³ Button 按钮 JoyTabWidget <New> <æ–°> Remove 移除 Remove configuration from recent list. 从最近使用列表中移除é…置。 Load 载入 Load configuration file. 载入é…置文件。 Save ä¿å­˜ Save changes to configuration file. ä¿å­˜æ›´æ”¹åˆ°é…置文件。 Save As å¦å­˜ä¸º Save changes to a new configuration file. ä¿å­˜æ›´æ”¹åˆ°æ–°çš„é…置文件。 Sets 设置 Copy from Set 从设置å¤åˆ¶ Settings 设置 Set 1 设置1 Set 2 设置2 Set 3 设置3 Set 4 设置4 Set 5 设置5 Set 6 设置6 Set 7 设置7 Set 8 设置8 Stick/Pad Assign 摇æ†/åå­—é”®åˆ†é… Controller Mapping æ¸¸æˆæŽ§åˆ¶å™¨æ˜ å°„ Quick Set 快速设置 Names åç§° Toggle button name displaying. 开关按钮å称显示。 Pref å好设置 Change global profile settings. 改å˜å…¨å±€é…置文件设置。 Reset é‡ç½® Revert changes to the configuration. Reload configuration file. è¿˜åŽŸè®¾ç½®çš„æ›´æ”¹ã€‚é‡æ–°åŠ è½½é…置文件。 Open Config 打开é…置文件 Config Files (*.amgp *.xml) é…置文件 (*.amgp *.xml) Config File (*.%1.amgp) é…置文件 (*.%1.amgp) Save Profile Changes? ä¿å­˜é…置文件更改? Changes to the new profile have not been saved. Would you like to save or discard the current profile? æ–°é…置文件的更改尚未ä¿å­˜ã€‚您想ä¿å­˜è¿˜æ˜¯æ”¾å¼ƒä¿®æ”¹å½“å‰çš„é…置文件? Changes to the profile "%1" have not been saved. Would you like to save or discard changes to the current profile? é…置文件“%1â€çš„æ›´æ”¹å°šæœªä¿å­˜ã€‚您想ä¿å­˜è¿˜æ˜¯æ”¾å¼ƒä¿®æ”¹æ­¤é…置文件? Sticks æ‘‡æ† DPads åå­—é”® No buttons have been assigned. Please use Quick Set to assign keys to buttons or disable hiding empty buttons. 按钮未被分é…ã€‚è¯·ä½¿ç”¨â€œå¿«é€Ÿè®¾ç½®â€æ¥å°†æŒ‰é”®åˆ†é…åˆ°æŒ‰é’®ï¼Œæˆ–å–æ¶ˆéšè—空白按钮。 Set %1: %2 设置%1:%2 Set %1 设置%1 Copy Set Assignments å¤åˆ¶è®¾ç½®åˆ†é…ä¿¡æ¯ Are you sure you want to copy the assignments and device properties from %1? 您确定è¦ä»Ž %1 å¤åˆ¶åˆ†é…ä¿¡æ¯å’Œè®¾å¤‡å±žæ€§å—? Save Config ä¿å­˜é…置文件 Set 设置 Joystick Joystick æ‘‡æ† JoystickStatusWindow Properties 属性 Details è¯¦ç»†ä¿¡æ¯ Name: å称: %1 %1 Number: ç¼–å·ï¼š Axes: 轴数: Buttons: 按钮数: Hats: 帽å­å¼€å…³æ•°ï¼š GUID: 全局唯一标识符: Game Controller: 是å¦ä¸ºæ‰‹æŸ„: Axes è½´ Buttons 按钮 Hats 帽å­å¼€å…³ %1 (#%2) Properties %1 (#%2) 属性 Axis %1 è½´%1 Hat %1 帽å­å¼€å…³%1 No å¦ Yes 是 MainSettingsDialog Edit Settings 编辑设置 General 常规 Controller Mappings æ¸¸æˆæŽ§åˆ¶å™¨æ˜ å°„ Language 语言 Auto Profile 自动é…置文件 Mouse é¼ æ ‡ <html><head/><body><p>Specify the default directory that the program should use in file dialogs when loading a profile or saving a new profile.</p></body></html> <html><head/><body><p>指定本程åºåœ¨åŠ è½½æˆ–ä¿å­˜ä¸€ä¸ªé…ç½®æ–‡ä»¶æ—¶ï¼Œæ–‡ä»¶å¯¹è¯æ¡†ä¸­é»˜è®¤ä½¿ç”¨çš„路径。</p></body></html> Recent Profile Count: 最近使用的é…置文件数: <html><head/><body><p>Number of profiles that can be placed in recent profile list. 0 will result in the program not enforcing a limit on the number of profiles displayed.</p></body></html> <html><head/><body><p>最近使用的é…置文件列表中é…置文件的数é‡ã€‚设为0将显示所有最近使用的é…置文件。</p></body></html> Gamepad Poll Rate: 手柄轮询速率: Change the poll rate that the program uses to discover new events from gamepads. Defaults to 10 ms. Reducing the poll rate value could cause the application to use more CPU power so please test the setting that you use before using antimicro unattended. 改å˜è½®è¯¢é€Ÿçއæ¥å‘现新的手柄事件。默认10毫秒。 é™ä½Žè½®è¯¢é€Ÿçއå¯èƒ½ä¼šå¯¼è‡´æœ¬ç¨‹åºä½¿ç”¨æ›´å¤šçš„处ç†å™¨èµ„æºã€‚请在以无人值守方å¼ä½¿ç”¨å‰æµ‹è¯•此选项。 Hide main window when the main window close button is clicked instead of quitting the program. 点击关闭按钮时,最å°åŒ–主窗å£åˆ°ç³»ç»Ÿæ‰˜ç›˜è€Œä¸æ˜¯é€€å‡ºç¨‹åºã€‚ Close To Tray 关闭时最å°åŒ–到系统托盘 Launch At Windows Startup Windows 开机自å¯åЍ Display recent profiles for all controllers as a single list in the tray menu. Defaults to using sub-menus. 在系统托盘èœå•中以å•ä¸€åˆ—è¡¨æ˜¾ç¤ºæ‰€æœ‰æ¸¸æˆæŽ§åˆ¶å™¨çš„æœ€è¿‘ä½¿ç”¨çš„é…置文件。 默认是使用å­èœå•。 Single Profile List in Tray 系统托盘èœå•中使用å•一é…置文件列表 Have the program minimize to the taskbar. By default, the program minimizes to the system tray if available. ä½¿æœ¬ç¨‹åºæœ€å°åŒ–到任务æ ã€‚ 如果å¯èƒ½ï¼Œé»˜è®¤æƒ…况下本程åºå°†æœ€å°åŒ–到系统托盘。 Minimize to Taskbar 最å°åŒ–åˆ°ä»»åŠ¡æ  This option will cause the program to hide all buttons that have no slots assigned to them. The Quick Set dialog window will have to be used to bring up the edit dialog for gamepad buttons. 此选项将使本程åºéšè—æ‰€æœ‰æœªåˆ†é…æ§½çš„æŒ‰é’®ã€‚ 您需è¦ä½¿ç”¨â€œå¿«é€Ÿè®¾ç½®â€å¯¹è¯æ¡†æ¥æ‰“å¼€æ‰‹æŸ„æŒ‰é’®çš„ç¼–è¾‘å¯¹è¯æ¡†ã€‚ Hide Empty Buttons éšè—空白按钮 When the program is launched, open the last known profile that was opened during the previous session. 本程åºå¯åŠ¨æ—¶ï¼Œæ‰“å¼€ä¸Šæ¬¡ä½¿ç”¨çš„é…置文件。 Auto Load Last Opened Profile 自动加载上次打开的é…置文件 Only show the system tray icon when the program first launches. 首次å¯åŠ¨æœ¬ç¨‹åºæ—¶åªæ˜¾ç¤ºç³»ç»Ÿæ‰˜ç›˜ã€‚ Launch in Tray å¯åŠ¨æ—¶æœ€å°åŒ–到系统托盘 Associate Profiles å…³è”é…置文件 Key Repeat é”®é‡å¤ Active keys will be repeatedly pressed when this option is enabled. 此选项å¯ç”¨åŽï¼Œå¤„于活动状æ€çš„æŒ‰é”®å°†ä¸€ç›´è¢«é‡å¤æŒ‰ä¸‹ã€‚ Enable å¯ç”¨ Italian æ„大利语 Simplified Chinese 简体中文 Class ç±» Title 标题 Program ç¨‹åº Disable the "Enhanced Pointer Precision" Windows setting while antimicro is running. Disabling "Enhanced Pointer Precision" will allow mouse movement within antimicro to be more precise. 在 antimicro è¿è¡Œæ—¶ç¦ç”¨ Windows 的“æé«˜æŒ‡é’ˆç²¾ç¡®åº¦â€é€‰é¡¹ã€‚ ç¦ç”¨â€œæé«˜æŒ‡é’ˆç²¾ç¡®åº¦â€å¯ä½¿é¼ æ ‡åœ¨å¼€å¯ antimicro 的情况下更精准地移动。 Disable Enhance Pointer Precision ç¦ç”¨æé«˜æŒ‡é’ˆç²¾ç¡®åº¦ Smoothing 平滑 Refresh Rate: 刷新率: The refresh rate is the amount of time that will elapse in between mouse events. Please be cautious when editing this setting as it will cause the program to use more CPU power. Setting this value too low can cause system instability. Please test the setting before using it unattended. 刷新率是鼠标事件之间间隔的时间。 请å°å¿ƒä¿®æ”¹æ­¤é€‰é¡¹ï¼Œå› ä¸ºå®ƒå¯èƒ½ä¼šå¯¼è‡´æœ¬ç¨‹åºä½¿ç”¨æ›´å¤šçš„处ç†å™¨èµ„æºã€‚ 此选项的值过低å¯èƒ½ä¼šå¯¼è‡´ç³»ç»Ÿä¸ç¨³å®šã€‚ 请在以无人值守方å¼ä½¿ç”¨å‰æµ‹è¯•此选项。 Accel Numerator: 加速度分å­ï¼š 0 0 Accel Denominator: 加速度分æ¯ï¼š Accel Threshold: 加速度阈值: If the acceleration values for the virtual mouse have been changed by a different process, particularly when quitting an older game, then you might want to reset the acceleration values used by the virtual mouse. 如果虚拟鼠标的加速度值被å¦ä¸€ä¸ªè¿›ç¨‹æ”¹å˜ï¼Œå°¤å…¶æ˜¯åœ¨é€€å‡ºè€æ¸¸æˆçš„æ—¶å€™ï¼Œæ‚¨å¯èƒ½éœ€è¦é‡ç½®è™šæ‹Ÿé¼ æ ‡ä½¿ç”¨çš„加速度值。 Reset Acceleration é‡ç½®åŠ é€Ÿåº¦ Delay: 延迟: Profi&le Directory: é…置文件目录 (&l): Have Windows start antimicro at system startup. 在 Windows å¯åŠ¨æ—¶è¿è¡Œæœ¬ç¨‹åºã€‚ Associate .amgp files with antimicro in Windows Explorer. 在 Windows 资æºç®¡ç†å™¨ä¸­å°† .amgp 文件关è”到 antimicro。 Specifies how much time should elapse before key repeating begins. 指定开始键é‡å¤ä¹‹å‰çš„延迟时间。 ms 毫秒 Rate: 频率: Specifies how many times key presses will be performed per seconds. 指定æ¯ç§’按键多少次。 times/s 次/ç§’ Below is a list of the custom mappings that have been saved. You can use the following table to delete mappings or have mappings temporarily disabled. You can also disable mappings that are included with SDL; just insert a new row with the appropriate joystick GUID and check disable. Settings will not take affect until you either refresh all joysticks or unplug that particular joystick. 䏋颿˜¯å·²ä¿å­˜çš„自定义映射。您å¯ä»¥ä½¿ç”¨ä¸‹è¡¨åˆ é™¤æˆ–临时ç¦ç”¨ä¸€ä¸ªæ˜ å°„。您还å¯ä»¥ç¦ç”¨ SDL 中包å«çš„æ˜ å°„。您åªéœ€è¦æ’入新的一行,指定摇æ†çš„全局统一标识符,然åŽå‹¾é€‰ç¦ç”¨ã€‚ è®¾ç½®ä»…åœ¨æ‚¨åˆ·æ–°æ‰€æœ‰æ‘‡æ†æˆ–者拔出那个被ç¦ç”¨çš„æ‘‡æ†ä¹‹åŽç”Ÿæ•ˆã€‚ GUID 全局唯一标识符 Mapping String 映射字符串 Disable? ç¦ç”¨ï¼Ÿ Delete 删除 Insert æ’å…¥ <html><head/><body><p>antimicro has been translated into many different languages by contributors. By default, the program will choose an appropriate translation based on your system's locale setting. However, you can make antimicro load a different translation depending on the language that you choose from the list below.</p></body></html> <html><head/><body><p>antimicro 已被贡献者翻译为多ç§è¯­è¨€ã€‚默认情况下,本程åºå°†æ ¹æ®æ‚¨ç³»ç»Ÿçš„区域设置选择相应的语言。然而,您也å¯ä»¥è®© antimicro 加载以下列表中的任æ„语言。</p></body></html> Default 默认 Brazilian Portuguese 巴西葡è„牙语 English 英语 French 法语 German 德语 Japanese 日语 Russian 俄语 Serbian 塞尔维亚语 Ukrainian 乌克兰语 Active å¯ç”¨ Devices: 设备: All 所有 Device 设备 Profile é…置文件 Default? 默认? Add 添加 Edit 编辑 Histor&y Size: 历å²ç¼“å†²å¤§å° (&y): Weight &Modifier: æƒé‡ä¿®é¥°å› æ•° (&M): Spring 弹簧 Screen: å±å¹•: Utilize the specified screen for spring mode. On Linux, the default is to use the primary screen. On Windows, the default is to use all available screens. 在弹簧模å¼ä¸­ä½¿ç”¨æŒ‡å®šçš„å±å¹•。 在 Linux 系统上,默认使用主å±å¹•。 在 Windows 系统上,默认使用所有å¯ç”¨å±å¹•。 Also, Windows users who want to use a low value should also check the "Disable Enhance Pointer Precision" checkbox if you haven't disabled the option in Windows. å¦å¤–,对于希望使用较低值的 Windows 用户,如果您未ç¦ç”¨ Windows 的“æé«˜æŒ‡é’ˆç²¾ç¡®åº¦â€é€‰é¡¹ï¼Œè¯·å‹¾é€‰æœ¬ç¨‹åºä¸­çš„“ç¦ç”¨æé«˜æŒ‡é’ˆç²¾ç¡®åº¦â€å¤é€‰æ¡†ã€‚ Select Default Profile Directory 选择默认é…置文件目录 Are you sure you want to delete the profile? 您确认è¦åˆ é™¤è¿™ä¸ªé…置文件å—? MainWindow antimicro antimicro No Joysticks have been found. Please plug in a joystick and then choose the "Update Joysticks" option in the main menu 未找到摇æ†ã€‚ 请æ’入一个摇æ†ç„¶åŽé€‰æ‹©â€œé€‰é¡¹â€èœå•下的“更新摇æ†â€ If events are not seen by a game, please click here to run this application as the Adminstrator. å¦‚æžœæ¸¸æˆæ— æ³•识别事件,请点击这里以管ç†å‘˜æƒé™è¿è¡Œæœ¬ç¨‹åºã€‚ &App ç¨‹åº (&A) &Options 选项 (&O) &Help 帮助 (&H) &Quit 退出 (&Q) Ctrl+Q Ctrl+Q &Update Joysticks æ›´æ–°æ‘‡æ† (&U) Ctrl+U Ctrl+U &Hide éšè— (&H) Ctrl+H Ctrl+H &About 关于 (&A) Ctrl+A Ctrl+A About Qt 关于 Qt Properties 属性 Key Checker 按键检查器 Home Page 主页 GitHub Page GitHub é¡µé¢ Game Controller Mapping æ¸¸æˆæŽ§åˆ¶å™¨æ˜ å°„ Settings 设置 Stick/Pad Assign 摇æ†/åå­—é”®åˆ†é… Wiki ç»´åŸºé¡µé¢ Could not find a proper controller identifier. Exiting. 无法找到åˆé€‚çš„æ¸¸æˆæŽ§åˆ¶å™¨æ ‡è¯†ç¬¦ã€‚æ­£åœ¨é€€å‡ºã€‚ (%1) (%1) Open File 打开文件 &Restore 还原 (&R) Run as Administrator? 以管ç†å‘˜æƒé™è¿è¡Œï¼Ÿ Are you sure that you want to run this program as Adminstrator? Some games run as Administrator which will cause events generated by antimicro to not be used by those games unless antimicro is also run as the Adminstrator. This is due to permission problems caused by User Account Control (UAC) options in Windows Vista and later. 您确定è¦ä½¿ç”¨ç®¡ç†å‘˜æƒé™è¿è¡Œæœ¬ç¨‹åºå—? 有些以管ç†å‘˜æƒé™è¿è¡Œçš„æ¸¸æˆæ— æ³•识别 antimicro 生æˆçš„äº‹ä»¶ï¼Œé™¤éž antimicro 也使用管ç†å‘˜æƒé™è¿è¡Œã€‚这是由于 Windows Vista åŠä»¥åŽç³»ç»Ÿä¸­ç”¨æˆ·å¸æˆ·æŽ§åˆ¶ (UAC) 导致的æƒé™é—®é¢˜ã€‚ Failed to elevate program 无法æå‡æœ¬ç¨‹åºæƒé™ Failed to restart this program as the Administrator 无法以管ç†å‘˜æƒé™é‡æ–°è¿è¡Œæœ¬ç¨‹åº Could not find controller. Exiting. æ— æ³•æ‰¾åˆ°æ¸¸æˆæŽ§åˆ¶å™¨ã€‚æ­£åœ¨é€€å‡ºã€‚ MouseAxisSettingsDialog Mouse Settings - 鼠标设置 - Set %1 设置%1 MouseButtonSettingsDialog Mouse Settings - 鼠标设置 - Set %1 设置%1 MouseControlStickSettingsDialog Mouse Settings 鼠标设置 Set %1 设置%1 MouseDPadSettingsDialog Mouse Settings 鼠标设置 Set %1 设置%1 MouseSettingsDialog Mouse Settings 鼠标设置 Mouse Mode: 鼠标模å¼ï¼š Cursor mode is used to move the mouse cursor around the screen relative to its current position depending on how much you move an axis or if a button is pressed. Spring mode is used to move the mouse cursor from the center of the screen depending on how much you move an axis. The mouse cursor will be returned to the center of the screen when the axis is moved back to the dead zone. 光标:移动时,鼠标光标以当å‰ä½ç½®ä¸ºåŸºå‡†ï¼Œç§»åЍè·ç¦»å–决于您移动轴或按下按钮的幅度。 弹簧:移动时,鼠标光标以å±å¹•中心为基准,移动è·ç¦»å–决于您移动轴的幅度。轴移回ä¸çµæ•区之åŽï¼Œé¼ æ ‡å…‰æ ‡å°†å›žåˆ°å±å¹•中心。 Cursor 光标 Spring 弹簧 Acceleration: 加速模å¼ï¼š Enhanced: Three tier curve that makes the mouse move slow on the low end of an axis and fast on the high end. Linear: Mouse moves proportionally to axis. Quadratic: Mouse accelerates slowly on low end. Cubic: Mouse accelerates slower than Quadratic. Quadratic Extreme: Raises mouse speed 1.5 times once 95% axis travel has been reached. Power Function: Allows for a more custom curve option. Easing Quadratic: Axis high end is gradually accelerated over a period of time using a Quadratic curve. Easing Cubic: Axis high end is gradually accelerated over a period of time using a Cubic curve. å¢žå¼ºç²¾åº¦ï¼šä¸‰çº§æ›²çº¿ä½¿å¾—é¼ æ ‡å…‰æ ‡åœ¨è½´ç§»åŠ¨å¹…åº¦è¾ƒå°æ—¶ç§»åŠ¨æ…¢ï¼Œè½´ç§»åŠ¨å¹…åº¦è¾ƒå¤§æ—¶ç§»åŠ¨å¿«ã€‚ çº¿æ€§ï¼šé¼ æ ‡ç§»åŠ¨é€Ÿåº¦å’Œè½´ç§»åŠ¨å¹…åº¦æˆæ¯”例。 å¹³æ–¹ï¼šé¼ æ ‡å…‰æ ‡åœ¨è½´ç§»åŠ¨å¹…åº¦è¾ƒå°æ—¶ç¼“慢加速。 ç«‹æ–¹ï¼šé¼ æ ‡åŠ é€Ÿåº¦æ¯”å¹³æ–¹æ¨¡å¼æ…¢ã€‚ æžé™å¹³æ–¹ï¼šè½´ç§»åЍè·ç¦»è¾¾åˆ°95%åŽæå‡1.5å€é¼ æ ‡é€Ÿåº¦ã€‚ 指数函数:å…许更多自定义曲线选项。 å¹³æ–¹ç¼“åŠ¨ï¼šè½´ç§»åŠ¨å¹…åº¦è¾ƒå¤§æ—¶ï¼Œé¼ æ ‡é€Ÿåº¦éšæ—¶é—´ä»¥å¹³æ–¹æ›²çº¿å¢žåŠ ã€‚ ç«‹æ–¹ç¼“åŠ¨ï¼šè½´ç§»åŠ¨å¹…åº¦è¾ƒå¤§æ—¶ï¼Œé¼ æ ‡é€Ÿåº¦éšæ—¶é—´ä»¥ç«‹æ–¹æ›²çº¿å¢žåŠ ã€‚ Enhanced Precision 增强精度 Linear 线性 Quadratic 平方 Cubic ç«‹æ–¹ Quadratic Extreme æžé™å¹³æ–¹ Power Function 指数函数 Easing Quadratic 平方缓动 Easing Cubic 立方缓动 Mouse Speed Settings 鼠标速度设置 Enable to change the horizontal and vertical speed boxes at the same time. åŒæ—¶æ”¹å˜æ°´å¹³å’Œåž‚直速度。 Change Together åŒæ—¶æ›´æ”¹ Options for adding more acceleration to the mouse movement beyond what the acceleration curve would produce. Acceleration is added based on how quickly an axis is moved in one gamepad poll. This is meant to help work around some of the issues of the very limited input range available using typical gamepad analog sticks. 在加速曲线之上为鼠标移动增添é¢å¤–加速。 加速度基于手柄在一次采样时间内轴移动的速度。 这些选项是为了绕过æŸäº›ç”±äºŽæ‰‹æŸ„模拟摇æ†çš„è¾“å…¥èŒƒå›´æœ‰é™æ‰€å¸¦æ¥çš„问题。 Delta Acceleration é¢å¤–加速 &Multiplier: 倿•° (&M): Mi&n Threshold: 最å°é˜ˆå€¼ (&N): E&xtra Duration: é¢å¤–加速时长 (&X): 1 = 20 pps 1级=20åƒç´ /ç§’ Wheel Hori. Speed: 滚轮水平速度: Set the speed used for horizontal mouse wheel movement according to number of simulated notches per second. æ ¹æ®æ¯ç§’模拟滚动凹槽数设置鼠标滚轮水平滚动速度。 Set the speed used for vertical mouse wheel movement according to number of simulated notches per second. æ ¹æ®æ¯ç§’模拟滚动凹槽数设置鼠标滚轮垂直滚动速度。 Sensitivit&y: çµæ•度 (&Y): For Power Function acceleration curve. Specifies the factor to use for curve sensitivity. When the value is above 1.0, the mouse movement will be accelerated faster at the low end of an axis. 仅用于指数函数加速曲线。 æŒ‡å®šæ›²çº¿æ•æ„Ÿåº¦ç³»æ•°ã€‚当该值大于1.0æ—¶ï¼Œå¢žå¤§è½´ç§»åŠ¨å¹…åº¦è¾ƒå°æ—¶çš„鼠标加速度。 Easing Duration: 缓动时长: Specifies the amount of time (in seconds) that will be required before the mouse is fully accelerated after reaching the high end of an axis. 轴移动幅度达到最大åŽï¼Œé¼ æ ‡åœ¨æ­¤æ—¶é•¿ï¼ˆä»¥ç§’为å•ä½ï¼‰å†…加速到最大速度。 s ç§’ Highest value to accelerate mouse movement by 鼠标速度的最大加速值 x x Start %: 起始百分比: Acceleration begins at this percentage of the base multiplier åŠ é€Ÿä»¥åŸºç¡€å€æ•°çš„æ­¤ç™¾åˆ†æ¯”速率开始 % % Minimum amount of axis travel required for acceleration to begin 轴的移动幅度大于此最å°é˜ˆå€¼ä¹‹åŽåŠ é€Ÿæ‰å¼€å§‹ Max Threshold: 最大阈值: Maximum axis travel before acceleration has reached the multiplier value è½´çš„ç§»åŠ¨å¹…åº¦è¾¾åˆ°æ­¤æœ€å¤§é˜ˆå€¼æ—¶åŠ é€Ÿè¾¾åˆ°ä¸Šè¿°å€æ•°å€¼ Extend the time that extra acceleration is applied. Axis travel will be taken into account. A slower flick will decrease the actual time that extra acceleration will be applied. 此期间内é¢å¤–加速生效。 轴的移动幅度考虑在内。缓慢的轴移动将å‡å°å®žé™…çš„é¢å¤–加速生效时间。 Curve: 曲线: Ease Out Sine 正弦滑出缓动 Ease Out Quad 平方滑出缓动 Ease Out Cubic 立方滑出缓动 Release Radius: 释放åŠå¾„: Specifies that the spring area will be relative to the mouse position set by a non-relative spring. 弹簧区域将相对于鼠标指针的ä½ç½®ã€‚鼠标指针的ä½ç½®å¯ç”±å…¶å®ƒéžå¼¹ç°§æ¨¡å¼æŒ‡å®šã€‚ Relative 相对 Mouse Status é¼ æ ‡çŠ¶æ€ X: X轴: 0 (0 pps) 0(0åƒç´ /秒) Y: Y轴: 1 = 1 notch(es)/s 1级=1凹槽/ç§’ Hori&zontal Speed: 水平速度 (&Z): &Vertical Speed: 垂直速度 (&V): Wheel Vert. Speed: 滚轮垂直速度: Spring Settings 弹簧设置 Spring Width: 弹簧区域宽度: Changes the width of the region that the cursor can move in spring mode. 0 will use the entire width of your screen. 设置鼠标以弹簧模å¼ç§»åŠ¨çš„åŒºåŸŸçš„å®½åº¦ã€‚è®¾ä¸º0时将使用您整个å±å¹•的宽度。 Spring Height: 弹簧区域高度: Changes the height of the region that the cursor can move in spring mode. 0 will use the entire height of your screen. 设置鼠标以弹簧模å¼ç§»åŠ¨çš„åŒºåŸŸçš„é«˜åº¦ã€‚è®¾ä¸º0时将使用您整个å±å¹•的高度。 %n notch(es)/s %n凹槽/ç§’ QKeyDisplayDialog Key Checker 按键检查器 <html><head/><body><p>Press a key on your keyboard to see how the key is detected by this application. The window will show the system native key value, the original value given by Qt (if applicable), and the custom value used by antimicro.</p><p>The antimicro key value and the Qt key value will usually be the same. antimicro tries to use the key values defined in Qt when possible. Check the page <a href="https://doc.qt.io/qt-4.8/qt.html#Key-enum"><span style=" text-decoration: underline; color:#0057ae;">https://doc.qt.io/qt-4.8/qt.html#Key-enum</span></a> for a list of values defined by Qt. If you discover that a key is not natively supported by this program, please report the problem to antimicro's <a href="https://github.com/AntiMicro/antimicro"><span style=" text-decoration: underline; color:#0057ae;">GitHub page</span></a> so that the program can be edited to support it directly. As it is, a custom prefix is added to unknown values so they can still be used; the main problem is that the profile will no longer be portable.</p></body></html> <html><head/><body><p>按下您键盘上的一个键æ¥è§‚察本程åºå¦‚何检测按键。本窗å£å°†æ˜¾ç¤ºç³»ç»ŸåŽŸç”Ÿé”®å€¼ã€Qt 原始键值(如果å¯ç”¨ï¼‰å’Œ antimicro 使用的自定义键值。</p><p>antimicro 键值和 Qt 键值通常是一样的。如果å¯èƒ½ï¼Œantimicro 将优先使用 Qt 中已定义的键值。如果想了解 Qt ä¸­å·²å®šä¹‰çš„é”®å€¼åˆ—è¡¨ï¼Œè¯·æŸ¥çœ‹é¡µé¢ <a href="https://doc.qt.io/qt-4.8/qt.html#Key-enum"><span style=" text-decoration: underline; color:#0057ae;">https://doc.qt.io/qt-4.8/qt.html#Key-enum</span></a>。如果您å‘现æŸä¸ªé”®æ²¡æœ‰è¢«æœ¬ç¨‹åºåŽŸç”Ÿæ”¯æŒï¼Œè¯·å°†é—®é¢˜æŠ¥å‘Šè‡³ antimicro çš„ <a href="https://github.com/AntiMicro/antimicro"><span style=" text-decoration: underline; color:#0057ae;">GitHub 页é¢</span></a>,以便我们修改程åºåŽç›´æŽ¥æ”¯æŒè¿™ä¸ªé”®ã€‚如您所è§ï¼ŒæœªçŸ¥çš„键值将被附加一个自定义å‰ç¼€ã€‚这样一æ¥ï¼Œå®ƒä»¬å°±èƒ½è¢«ä½¿ç”¨äº†ï¼Œä¸è¿‡æœ€å¤§çš„é—®é¢˜æ˜¯å«æœ‰è¿™ä¸ªé”®çš„é…置文件将无法在其它地方使用。</p></body></html> Event Handler: 事件处ç†ç¨‹åºï¼š Native Key Value: 系统原生键值: 0x00000000 0x00000000 Qt Key Value: Qt 原始键值: antimicro Key Value: antimicro 自定义键值: QObject Super Super Menu Menu Mute Mute Vol+ Vol+ Vol- Vol- Play/Pause Play/Pause Play Play Pause Pause Prev Prev Next Next Mail Mail Home Home Media Media Search Search Daemon launched åŽå°æœåС已å¯åЍ Failed to launch daemon 无法å¯åЍåŽå°æœåŠ¡ Launching daemon 正在å¯åЍåŽå°æœåŠ¡ Display string "%1" is not valid. 显示字符串“%1â€æ— æ•ˆã€‚ Failed to set a signature id for the daemon 无法为åŽå°æœåŠ¡è®¾ç½®ç­¾åID Failed to change working directory to / 无法切æ¢å·¥ä½œè·¯å¾„到根目录 Quitting Program æ­£åœ¨é€€å‡ºç¨‹åº # of joysticks found: %1 å·²å‘çŽ°æ‘‡æ†æ•°ï¼š%1 List Joysticks: 摇æ†åˆ—表: --------------- --------------- Joystick %1: 摇æ†%1: Index: %1 ç¼–å·ï¼š%1 GUID: %1 全局唯一标识符:%1 Name: %1 å称:%1 Yes 是 No å¦ Game Controller: %1 æ¸¸æˆæŽ§åˆ¶å™¨ï¼š%1 # of Axes: %1 轴数:%1 # of Buttons: %1 按钮数:%1 # of Hats: %1 帽å­å¼€å…³æ•°ï¼š%1 Attempting to use fallback option %1 for event generation. å°è¯•为事件生æˆä½¿ç”¨åŽå¤‡é€‰é¡¹ %1。 Failed to open event generator. Exiting. 无法打开事件å‘生器。正在退出。 Using %1 as the event generator. 使用 %1 作为事件å‘生器。 Could not raise process priority. 无法æå‡è¿›ç¨‹ä¼˜å…ˆçº§ã€‚ QuickSetDialog Quick Set 快速设置 <html><head/><body><p>Please press a button or move an axis on %1 (<span style=" font-weight:600;">%2</span>).<br/>A dialog window will then appear which will<br/>allow you to make an assignment.</p></body></html> <html><head/><body><p>请在 %1(<span style=" font-weight:600;">%2</span>)上按任æ„键或移动任æ„轴。<br/>之åŽä¸€ä¸ªå¯¹è¯æ¡†ä¼šå¼¹å‡ºå¹¶å…许您设置按键分é…。</p></body></html> Quick Set %1 快速设置 %1 SetAxisThrottleDialog Throttle Change é˜€è®¾ç½®æ”¹å˜ The throttle setting for Axis %1 has been changed. Would you like to distribute this throttle change to all sets? è½´%1的阀设置已改å˜ã€‚ 您想将这个阀设置的改å˜åº”用到所有设置å—? SetJoystick Set %1: %2 设置%1:%2 Set %1 设置%1 SetNamesDialog Set Name Settings 指定设置åç§° Set 1 设置1 Set 2 设置2 Set 3 设置3 Set 4 设置4 Set 5 设置5 Set 6 设置6 Set 7 设置7 Set 8 设置8 Name åç§° SimpleKeyGrabberButton Mouse é¼ æ ‡ SpringModeRegionPreview Spring Mode Preview 弹簧模å¼é¢„览 UInputEventHandler Could not find a valid uinput device file. Please check that you have the uinput module loaded. lsmod | grep uinput 无法找到任何有效的 uinput 设备文件。 请确认您加载了 uinput 模å—: lsmod | grep uinput Could not open uinput device file Please check that you have permission to write to the device 无法打开 uinput 设备文件 请确认您有写入该设备的æƒé™ Using uinput device file %1 使用 uinput 设备文件%1 UInputHelper a a b b c c d d e e f f g g h h i i j j k k l l m m n n o o p p q q r r s s t t u u v v w w x x y y z z Esc Esc F1 F1 F2 F2 F3 F3 F4 F4 F5 F5 F6 F6 F7 F7 F8 F8 F9 F9 F10 F10 F11 F11 F12 F12 ` ` 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 0 0 - - = = BackSpace BackSpace Tab Tab [ [ ] ] \ \ CapsLock CapsLock ; ; ' ' Enter Enter Shift_L Shift_L , , . . / / Ctrl_L Ctrl_L Super_L Super_L Alt_L Alt_L Space Space Alt_R Alt_R Menu Menu Ctrl_R Ctrl_R Shift_R Shift_R Up Up Left Left Down Down Right Right PrtSc PrtSc Ins Ins Del Del Home Home End End PgUp PgUp PgDn PgDn NumLock NumLock * * + + KP_Enter KP_Enter KP_1 KP_1 KP_2 KP_2 KP_3 KP_3 KP_4 KP_4 KP_5 KP_5 KP_6 KP_6 KP_7 KP_7 KP_8 KP_8 KP_9 KP_9 KP_0 KP_0 SCLK SCLK Pause Pause Super_R Super_R Mute Mute VolDn VolDn VolUp VolUp Play Play Stop Stop Prev Prev Next Next [NO KEY] [NO KEY] UnixWindowInfoDialog Captured Window Properties æ•获的窗å£å±žæ€§ Information About Window 窗å£ä¿¡æ¯ Class: 类: TextLabel 文本标签 Title: 标题: Path: 路径: Match By Properties æ ¹æ®å±žæ€§åŒ¹é… Class ç±» Title 标题 Path 路径 VDPad VDPad 虚拟åå­—é”® VirtualKeyPushButton Space Space Tab Tab Shift (L) Shift (L) Shift (R) Shift (R) Ctrl (L) Ctrl (L) Ctrl (R) Ctrl (R) Alt (L) Alt (L) Alt (R) Alt (R) ` ` ~ ~ - - = = [ [ ] ] \ \ Caps Caps ; ; ' ' , , . . / / ESC ESC PRTSC PRTSC SCLK SCLK INS INS PGUP PGUP DEL DEL PGDN PGDN 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 0 0 NUM LK NUM LK * * + + E N T E R E N T E R < < : : Super (L) Super (L) Menu Menu Up Up Down Down Left Left Right Right VirtualKeyboardMouseWidget Keyboard 键盘 Mouse é¼ æ ‡ Mouse Settings 鼠标设置 Left Mouse å·¦ Up Mouse 上 Left Button Mouse 左键 Middle Button Mouse 中键 Right Button Mouse å³é”® Wheel Up Mouse 滚轮å‘上 Wheel Left Mouse 滚轮å‘å·¦ Wheel Right Mouse 滚轮å‘å³ Wheel Down Mouse 滚轮å‘下 Down Mouse 下 Right Mouse å³ Button 4 Mouse 按钮4 Mouse 8 Mouse 按钮8 Button 5 Mouse 按钮5 Mouse 9 Mouse 按钮9 NONE æ—  Applications åº”ç”¨ç¨‹åº Browser Back æµè§ˆå™¨åŽé€€ Browser Favorites æµè§ˆå™¨æ”¶è— Browser Forward æµè§ˆå™¨å‰è¿› Browser Home æµè§ˆå™¨ä¸»é¡µ Browser Refresh æµè§ˆå™¨åˆ·æ–° Browser Search æµè§ˆå™¨æœç´¢ Browser Stop æµè§ˆå™¨åœæ­¢ Calc 计算器 Email 邮件 Media 多媒体 Media Next 多媒体下一首 Media Play 多媒体播放 Media Previous 多媒体上一首 Media Stop å¤šåª’ä½“åœæ­¢ Search æœç´¢ Volume Down 音é‡å‡å° Volume Mute é™éŸ³ Volume Up 音é‡å¢žåŠ  VirtualMousePushButton INVALID 无效 WinAppProfileTimerDialog Capture Application æ•æ‰åº”ç”¨ç¨‹åº After pressing the "Capture Application" button, please select the application window that you want to have a profile associated with. The active application will be captured after the selected number of seconds. æŒ‰ä¸‹â€œæ•æ‰åº”用程åºâ€æŒ‰é’®ä¹‹åŽï¼Œè¯·é€‰æ‹©æ‚¨æƒ³è¦å…³è”é…置文件的应用程åºçª—å£ã€‚活动的应用程åºå°†åœ¨æŒ‡å®šçš„秒数之åŽè¢«æ•æ‰ã€‚ Timer: 计时器: Seconds ç§’ Cancel å–æ¶ˆ WinExtras [NO KEY] [无按键] AntiMicro Profile antimicro é…置文件 X11Extras ESC ESC Tab Tab Space Space DEL DEL Return Return KP_Enter KP_Enter Backspace Backspace xinput extension was not found. No mouse acceleration changes will occur. 未找到 XInput 扩展。鼠标加速选项将无效。 xinput version must be at least 2.0. No mouse acceleration changes will occur. XInput 版本必需至少为2.0。鼠标加速选项将无效。 Virtual pointer found with id=%1. å‘现虚拟指针 ID=%1。 PtrFeedbackClass was not found for virtual pointer.No change to mouse acceleration will occur for device with id=%1 未找到虚拟指针的 PtrFeedbackClass。鼠标加速选项在 ID=%1 的设备上将无效 Changing mouse acceleration for device with id=%1 æ­£åœ¨æ”¹å˜ ID=%1 的设备上的鼠标加速选项 XMLConfigReader Could not write updated profile XML to file %1. 无法将更新åŽçš„é…ç½® XML 写入文件 %1。 XMLConfigWriter Could not write to profile at %1. 无法写入é…置文件 %1。 antimicro-2.23/share/blank.txt000066400000000000000000000000001300750276700163540ustar00rootroot00000000000000antimicro-2.23/src/000077500000000000000000000000001300750276700142235ustar00rootroot00000000000000antimicro-2.23/src/aboutdialog.cpp000066400000000000000000000064021300750276700172230ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #ifdef USE_SDL_2 #include #else #include #endif #include "aboutdialog.h" #include "ui_aboutdialog.h" #include "common.h" #include "eventhandlerfactory.h" AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AboutDialog) { ui->setupUi(this); ui->versionLabel->setText(PadderCommon::programVersion); fillInfoTextBrowser(); } AboutDialog::~AboutDialog() { delete ui; } void AboutDialog::fillInfoTextBrowser() { QStringList finalInfoText; finalInfoText.append(tr("Program Version %1").arg(PadderCommon::programVersion)); finalInfoText.append(tr("Program Compiled on %1 at %2").arg(__DATE__).arg(__TIME__)); QString sdlCompiledVersionNumber("%1.%2.%3"); QString sdlLinkedVersionNumber("%1.%2.%3"); SDL_version compiledver; SDL_version linkedver; SDL_VERSION(&compiledver); #ifdef USE_SDL_2 SDL_GetVersion(&linkedver); #else linkedver = *(SDL_Linked_Version()); #endif sdlCompiledVersionNumber = sdlCompiledVersionNumber.arg(compiledver.major).arg(compiledver.minor).arg(compiledver.patch); finalInfoText.append(tr("Built Against SDL %1").arg(sdlCompiledVersionNumber)); sdlLinkedVersionNumber = sdlLinkedVersionNumber.arg(linkedver.major).arg(linkedver.minor).arg(linkedver.patch); finalInfoText.append(tr("Running With SDL %1").arg(sdlLinkedVersionNumber)); finalInfoText.append(tr("Using Qt %1").arg(qVersion())); BaseEventHandler *handler = 0; EventHandlerFactory *factory = EventHandlerFactory::getInstance(); if (factory) { handler = factory->handler(); } if (handler) { finalInfoText.append(tr("Using Event Handler: %1").arg(handler->getName())); } ui->infoTextBrowser->setText(finalInfoText.join("\n")); // Read Changelog text from resource and put text in text box. QResource changelogFile(":/Changelog"); QFile temp(changelogFile.absoluteFilePath()); temp.open(QIODevice::Text | QIODevice::ReadOnly); QTextStream changelogStream(&temp); QString changelogText = changelogStream.readAll(); temp.close(); ui->changelogPlainTextEdit->setPlainText(changelogText); } void AboutDialog::changeEvent(QEvent *event) { if (event->type() == QEvent::LanguageChange) { retranslateUi(); } QDialog::changeEvent(event); } void AboutDialog::retranslateUi() { ui->retranslateUi(this); ui->versionLabel->setText(PadderCommon::programVersion); } antimicro-2.23/src/aboutdialog.h000066400000000000000000000022221300750276700166640ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef ABOUTDIALOG_H #define ABOUTDIALOG_H #include namespace Ui { class AboutDialog; } class AboutDialog : public QDialog { Q_OBJECT public: explicit AboutDialog(QWidget *parent = 0); ~AboutDialog(); private: Ui::AboutDialog *ui; protected: void fillInfoTextBrowser(); virtual void changeEvent(QEvent *event); void retranslateUi(); }; #endif // ABOUTDIALOG_H antimicro-2.23/src/aboutdialog.ui000066400000000000000000002147401300750276700170640ustar00rootroot00000000000000 AboutDialog 0 0 640 480 640 480 About 10 6 50 110 0 0 64 64 :/images/antimicro.png 0 0 14 75 true antimicro Qt::AlignHCenter|Qt::AlignTop 0 -1 0 0 11 Version Qt::AlignCenter 4 false Credits 0 0 IBeamCursor <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Originally developed by Travis Nickles &lt;nickles.travis@gmail.com&gt;, now maintained by the AntiMicro group at https://github.com/AntiMicro.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Contributors:</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;"><br /></span>Zerro Alvein</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">aybe</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jeff Backus &lt;jeff.backus@gmail.com&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Arthur Moore<br />Anton Tornqvist &lt;antont@inbox.lv&gt;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">7185</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">DarkStarSword</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">est31</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ProfessorKaos64</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">qwerty12</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA0</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt; font-weight:600;">Translators:</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt; font-weight:600;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">VaGNaroK &lt;vagnarokalkimist@gmail.com&gt; - Brazilian Portuguese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">zzpxyx - Chinese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Belleguic Terence &lt;hizo@free.fr&gt; - French</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'DejaVu Sans';">Leonard Koenig &lt;leonard.r.koenig@googlemail.com&gt; - German</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">phob - German</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">tou omiya - Japanese</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Dmitriy Koshel &lt;form.eater@gmail.com&gt; - Russian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Jay Alexander Fleming &lt;tito.nehru.naser@gmail.com&gt; - Serbian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">burunduk - Ukrainian</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Flavio HR &lt;flavio.hrx@gmail.com&gt; - Spanish</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">WAZAAAAA - wazaaaaa00&lt;@&gt;gmail&lt;.&gt;com - Italian</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> true Info License 0 0 IBeamCursor <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">GNU GENERAL PUBLIC LICENSE</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Version 3, 29 June 2007</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Preamble</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Developers that use the GNU GPL protect your rights with two steps:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">(1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The precise terms and conditions for copying, distribution and modification follow.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">TERMS AND CONDITIONS</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">0. Definitions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;This License&quot; refers to version 3 of the GNU General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Copyright&quot; also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;The Program&quot; refers to any copyrightable work licensed under this License. Each licensee is addressed as &quot;you&quot;. &quot;Licensees&quot; and &quot;recipients&quot; may be individuals or organizations.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;modify&quot; a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a &quot;modified version&quot; of the earlier work or a work &quot;based on&quot; the earlier work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;covered work&quot; means either the unmodified Program or a work based on the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;propagate&quot; a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">To &quot;convey&quot; a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An interactive user interface displays &quot;Appropriate Legal Notices&quot; to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">1. Source Code.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;source code&quot; for a work means the preferred form of the work for making modifications to it. &quot;Object code&quot; means any non-source form of a work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;Standard Interface&quot; means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;System Libraries&quot; of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A &quot;Major Component&quot;, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The &quot;Corresponding Source&quot; for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Corresponding Source for a work in source code form is that same work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">2. Basic Permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">3. Protecting Users' Legal Rights From Anti-Circumvention Law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">4. Conveying Verbatim Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">5. Conveying Modified Source Versions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) The work must carry prominent notices stating that you modified it, and giving a relevant date.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to &quot;keep intact all notices&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an &quot;aggregate&quot; if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">6. Conveying Non-Source Forms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;User Product&quot; is either (1) a &quot;consumer product&quot;, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, &quot;normally used&quot; refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Installation Information&quot; for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">7. Additional Terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">&quot;Additional permissions&quot; are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">d) Limiting the use for publicity purposes of names of licensors or authors of the material; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">All other non-permissive additional terms are considered &quot;further restrictions&quot; within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">8. Termination.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">9. Acceptance Not Required for Having Copies.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">10. Automatic Licensing of Downstream Recipients.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">An &quot;entity transaction&quot; is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">11. Patents.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A &quot;contributor&quot; is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's &quot;contributor version&quot;.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A contributor's &quot;essential patent claims&quot; are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, &quot;control&quot; includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">In the following three paragraphs, a &quot;patent license&quot; is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To &quot;grant&quot; such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. &quot;Knowingly relying&quot; means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">A patent license is &quot;discriminatory&quot; if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">12. No Surrender of Others' Freedom.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">13. Use with the GNU Affero General Public License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">14. Revised Versions of this License.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License &quot;or any later version&quot; applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">15. Disclaimer of Warranty.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM &quot;AS IS&quot; WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">16. Limitation of Liability.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">17. Interpretation of Sections 15 and 16.</span></p> <p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.</span></p></body></html> false Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse true Changelog true About Development 30 Since December 30, 2012, I have been working on antimicro in my spare time. What originally started as a fork of QJoyPad and a way to learn proper event-driven programming has turned into something much bigger than I originally intended. Although I have spent a lot of time learning new techniques, finding out more about the domain of KB+M emulation, and spending Friday nights bashing my head against my keyboard, it has been a fun and enriching experience overall. The need for this program came from me using similar programs on Windows to play several games that did not provide native controller support. Although some alternatives existed on Linux, there wasn't really anything that I felt was good enough in terms of functionality or in-game controls in order to really enjoy games that I wanted to play with using KB+M emulation. QJoyPad was the main program that I had used in the past although it had aged a lot and it didn't provide some basic functionality that I thought was essential. The project was dead as it had not been updated in several years so I decided to make my own. Since then, I have tried to find out what the other programs do right and then improve upon it. I have also discovered some neat tricks along the way and I have learned more about how native gamepad controls are implemented in some games than I ever really wanted to know. Although there are definitely areas where this program could improve, I find that this program offers the best in-game control experience for playing older, and some newer, games that do not provide native controller support. Development of this program is not as high of a priority for me anymore. This is mainly due to the fact that the Steam Controller works pretty well for the task of playing PC games compared to using an Xbox 360 controller. However, it does look like there is still a reason for this program to exist for a while. --- As of May 24, 2016, this project has moved to https://github.com/AntiMicro/antimicro. Additionally, project management has passed from Travis (Ryochan7) to the AntiMicro organization due to Travis having other interests and priorities. Copyright: 2013 - 2016 Qt::AlignBottom|Qt::AlignRight|Qt::AlignTrailing -1 Qt::Horizontal 40 20 QDialogButtonBox::Close versionLabel copyrightLabel tabWidget buttonBox accepted() AboutDialog accept() 63 473 319 239 buttonBox rejected() AboutDialog reject() 478 462 319 239 antimicro-2.23/src/addeditautoprofiledialog.cpp000066400000000000000000000424701300750276700217660ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include #include #include #include #include "addeditautoprofiledialog.h" #include "ui_addeditautoprofiledialog.h" #if defined(Q_OS_UNIX) #ifdef WITH_X11 #include "unixcapturewindowutility.h" #include "capturedwindowinfodialog.h" #include "x11extras.h" #endif #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include #endif #elif defined(Q_OS_WIN) #include "winappprofiletimerdialog.h" #include "capturedwindowinfodialog.h" #include "winextras.h" #endif #include "common.h" AddEditAutoProfileDialog::AddEditAutoProfileDialog(AutoProfileInfo *info, AntiMicroSettings *settings, QList *devices, QList &reservedGUIDS, bool edit, QWidget *parent) : QDialog(parent), ui(new Ui::AddEditAutoProfileDialog) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); this->info = info; this->settings = settings; this->editForm = edit; this->devices = devices; this->originalGUID = info->getGUID(); this->originalExe = info->getExe(); this->originalWindowClass = info->getWindowClass(); this->originalWindowName = info->getWindowName(); QListIterator iterGUIDs(reservedGUIDS); while (iterGUIDs.hasNext()) { QString guid = iterGUIDs.next(); if (!this->reservedGUIDs.contains(guid)) { this->reservedGUIDs.append(guid); } } bool allowDefault = false; if (info->getGUID() != "all" && info->getGUID() != "" && !this->reservedGUIDs.contains(info->getGUID())) { allowDefault = true; } if (allowDefault && info->getExe().isEmpty()) { ui->asDefaultCheckBox->setEnabled(true); if (info->isCurrentDefault()) { ui->asDefaultCheckBox->setChecked(true); } } else { ui->asDefaultCheckBox->setToolTip(tr("A different profile is already selected as the default for this device.")); } //if (!edit) //{ ui->devicesComboBox->addItem("all"); QListIterator iter(*devices); int found = -1; int numItems = 1; while (iter.hasNext()) { InputDevice *device = iter.next(); ui->devicesComboBox->addItem(device->getSDLName(), QVariant::fromValue(device)); if (device->getGUIDString() == info->getGUID()) { found = numItems; } numItems++; } if (!info->getGUID().isEmpty() && info->getGUID() != "all") { if (found >= 0) { ui->devicesComboBox->setCurrentIndex(found); } else { ui->devicesComboBox->addItem(tr("Current (%1)").arg(info->getDeviceName())); ui->devicesComboBox->setCurrentIndex(ui->devicesComboBox->count()-1); } } //} ui->profileLineEdit->setText(info->getProfileLocation()); ui->applicationLineEdit->setText(info->getExe()); ui->winClassLineEdit->setText(info->getWindowClass()); ui->winNameLineEdit->setText(info->getWindowName()); #ifdef Q_OS_UNIX ui->selectWindowPushButton->setVisible(false); #elif defined(Q_OS_WIN) ui->detectWinPropsSelectWindowPushButton->setVisible(false); ui->winClassLineEdit->setVisible(false); ui->winClassLabel->setVisible(false); //ui->winNameLineEdit->setVisible(false); //ui->winNameLabel->setVisible(false); #endif connect(ui->profileBrowsePushButton, SIGNAL(clicked()), this, SLOT(openProfileBrowseDialog())); connect(ui->applicationPushButton, SIGNAL(clicked()), this, SLOT(openApplicationBrowseDialog())); connect(ui->devicesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkForReservedGUIDs(int))); connect(ui->applicationLineEdit, SIGNAL(textChanged(QString)), this, SLOT(checkForDefaultStatus())); connect(ui->winClassLineEdit, SIGNAL(textChanged(QString)), this, SLOT(checkForDefaultStatus())); connect(ui->winNameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(checkForDefaultStatus())); #if defined(Q_OS_UNIX) connect(ui->detectWinPropsSelectWindowPushButton, SIGNAL(clicked()), this, SLOT(showCaptureHelpWindow())); #elif defined(Q_OS_WIN) connect(ui->selectWindowPushButton, SIGNAL(clicked()), this, SLOT(openWinAppProfileDialog())); #endif connect(this, SIGNAL(accepted()), this, SLOT(saveAutoProfileInformation())); } AddEditAutoProfileDialog::~AddEditAutoProfileDialog() { delete ui; } void AddEditAutoProfileDialog::openProfileBrowseDialog() { QString lookupDir = PadderCommon::preferredProfileDir(settings); QString filename = QFileDialog::getOpenFileName(this, tr("Open Config"), lookupDir, QString("Config Files (*.amgp *.xml)")); if (!filename.isNull() && !filename.isEmpty()) { ui->profileLineEdit->setText(QDir::toNativeSeparators(filename)); } } void AddEditAutoProfileDialog::openApplicationBrowseDialog() { /*QString filename; QFileDialog dialog(this, tr("Select Program"), QDir::homePath()); dialog.setFilter(QDir::Files | QDir::Executable); if (dialog.exec()) { filename = dialog.selectedFiles().first(); }*/ #ifdef Q_OS_WIN QString filename = QFileDialog::getOpenFileName(this, tr("Select Program"), QDir::homePath(), tr("Programs (*.exe)")); #else QString filename = QFileDialog::getOpenFileName(this, tr("Select Program"), QDir::homePath(), QString()); #endif if (!filename.isNull() && !filename.isEmpty()) { QFileInfo exe(filename); if (exe.exists() && exe.isExecutable()) { ui->applicationLineEdit->setText(filename); } } } AutoProfileInfo* AddEditAutoProfileDialog::getAutoProfile() { return info; } void AddEditAutoProfileDialog::saveAutoProfileInformation() { info->setProfileLocation(ui->profileLineEdit->text()); int deviceIndex = ui->devicesComboBox->currentIndex(); if (deviceIndex > 0) { QVariant temp = ui->devicesComboBox->itemData(deviceIndex, Qt::UserRole); // Assume that if the following is not true, the GUID should // not be changed. if (!temp.isNull()) { InputDevice *device = ui->devicesComboBox->itemData(deviceIndex, Qt::UserRole).value(); info->setGUID(device->getGUIDString()); info->setDeviceName(device->getSDLName()); } } else { info->setGUID("all"); info->setDeviceName(""); } info->setExe(ui->applicationLineEdit->text()); info->setWindowClass(ui->winClassLineEdit->text()); info->setWindowName(ui->winNameLineEdit->text()); info->setDefaultState(ui->asDefaultCheckBox->isChecked()); //info->setActive(true); } void AddEditAutoProfileDialog::checkForReservedGUIDs(int index) { QVariant data = ui->devicesComboBox->itemData(index); if (index == 0) { ui->asDefaultCheckBox->setChecked(false); ui->asDefaultCheckBox->setEnabled(false); ui->asDefaultCheckBox->setToolTip(tr("Please use the main default profile selection.")); } else if (!data.isNull()) { InputDevice *device = data.value(); if (reservedGUIDs.contains(device->getGUIDString())) { ui->asDefaultCheckBox->setChecked(false); ui->asDefaultCheckBox->setEnabled(false); ui->asDefaultCheckBox->setToolTip(tr("A different profile is already selected as the default for this device.")); } else { ui->asDefaultCheckBox->setEnabled(true); ui->asDefaultCheckBox->setToolTip(tr("Select this profile to be the default loaded for\nthe specified device. The selection will be used instead\nof the all default profile option.")); } } } QString AddEditAutoProfileDialog::getOriginalGUID() { return originalGUID; } QString AddEditAutoProfileDialog::getOriginalExe() { return originalExe; } QString AddEditAutoProfileDialog::getOriginalWindowClass() { return originalWindowClass; } QString AddEditAutoProfileDialog::getOriginalWindowName() { return originalWindowName; } #ifdef Q_OS_UNIX /** * @brief Display a simple message box and attempt to capture a window using the mouse */ void AddEditAutoProfileDialog::showCaptureHelpWindow() { #ifdef WITH_X11 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif QMessageBox *box = new QMessageBox(this); box->setText(tr("Please select a window by using the mouse. Press Escape if you want to cancel.")); box->setWindowTitle(tr("Capture Application Window")); box->setStandardButtons(QMessageBox::NoButton); box->setModal(true); box->show(); UnixCaptureWindowUtility *util = new UnixCaptureWindowUtility(); QThread *thread = new QThread(this); util->moveToThread(thread); connect(thread, SIGNAL(started()), util, SLOT(attemptWindowCapture())); connect(util, SIGNAL(captureFinished()), thread, SLOT(quit())); connect(util, SIGNAL(captureFinished()), box, SLOT(hide())); connect(util, SIGNAL(captureFinished()), this, SLOT(checkForGrabbedWindow()), Qt::QueuedConnection); connect(thread, SIGNAL(finished()), box, SLOT(deleteLater())); connect(util, SIGNAL(destroyed()), thread, SLOT(deleteLater())); thread->start(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #endif } /** * @brief Check if there is a program path saved in an UnixCaptureWindowUtility * object */ void AddEditAutoProfileDialog::checkForGrabbedWindow() { #ifdef WITH_X11 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif UnixCaptureWindowUtility *util = static_cast(sender()); unsigned long targetWindow = util->getTargetWindow(); bool escaped = !util->hasFailed(); bool failed = false; QString path; if (targetWindow != None) { // Attempt to find the appropriate window below the root window // that was clicked. //qDebug() << "ORIGINAL: " << QString::number(targetWindow, 16); unsigned long tempWindow = X11Extras::getInstance()->findClientWindow(targetWindow); if (tempWindow > 0) { targetWindow = tempWindow; } //qDebug() << "ADJUSTED: " << QString::number(targetWindow, 16); } if (targetWindow != None) { CapturedWindowInfoDialog *dialog = new CapturedWindowInfoDialog(targetWindow, this); connect(dialog, SIGNAL(accepted()), this, SLOT(windowPropAssignment())); dialog->show(); /*QString ham = X11Info::getInstance()->getWindowTitle(targetWindow); int pid = X11Info::getInstance()->getApplicationPid(targetWindow); if (pid > 0) { //qDebug() << "THIS ID: " << pid; QString exepath = X11Info::getInstance()->getApplicationLocation(pid); if (!exepath.isEmpty()) { path = exepath; } else if (!failed) { failed = true; } } else if (!failed) { failed = true; }*/ } else if (!escaped) { failed = true; } /*if (!path.isEmpty()) { ui->applicationLineEdit->setText(path); }*/ // Ensure that the operation was not cancelled (Escape wasn't pressed). if (failed) { QMessageBox box; box.setText(tr("Could not obtain information for the selected window.")); box.setWindowTitle(tr("Application Capture Failed")); box.setStandardButtons(QMessageBox::Close); box.raise(); box.exec(); } util->deleteLater(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #endif } #endif void AddEditAutoProfileDialog::windowPropAssignment() { disconnect(ui->applicationLineEdit, SIGNAL(textChanged(QString)), this, SLOT(checkForDefaultStatus())); disconnect(ui->winClassLineEdit, SIGNAL(textChanged(QString)), this, SLOT(checkForDefaultStatus())); disconnect(ui->winNameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(checkForDefaultStatus())); CapturedWindowInfoDialog *dialog = static_cast(sender()); if (dialog->getSelectedOptions() & CapturedWindowInfoDialog::WindowPath) { if (dialog->useFullWindowPath()) { ui->applicationLineEdit->setText(dialog->getWindowPath()); } else { QString temp; temp = QFileInfo(dialog->getWindowPath()).fileName(); ui->applicationLineEdit->setText(temp); } } else { ui->applicationLineEdit->clear(); } if (dialog->getSelectedOptions() & CapturedWindowInfoDialog::WindowClass) { ui->winClassLineEdit->setText(dialog->getWindowClass()); } else { ui->winClassLineEdit->clear(); } if (dialog->getSelectedOptions() & CapturedWindowInfoDialog::WindowName) { ui->winNameLineEdit->setText(dialog->getWindowName()); } else { ui->winNameLineEdit->clear(); } checkForDefaultStatus(); connect(ui->applicationLineEdit, SIGNAL(textChanged(QString)), this, SLOT(checkForDefaultStatus())); connect(ui->winClassLineEdit, SIGNAL(textChanged(QString)), this, SLOT(checkForDefaultStatus())); connect(ui->winNameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(checkForDefaultStatus())); } void AddEditAutoProfileDialog::checkForDefaultStatus() { bool status = ui->applicationLineEdit->text().length() > 0; status = status ? status : ui->winClassLineEdit->text().length() > 0; status = status ? status : ui->winNameLineEdit->text().length() > 0; if (status) { ui->asDefaultCheckBox->setChecked(false); ui->asDefaultCheckBox->setEnabled(false); } else { ui->asDefaultCheckBox->setEnabled(true); } } /** * @brief Validate the form that is contained in this window */ void AddEditAutoProfileDialog::accept() { bool validForm = true; bool propertyFound = false; QString errorString; if (ui->profileLineEdit->text().length() > 0) { QString profileFilename = ui->profileLineEdit->text(); QFileInfo info(profileFilename); if (!info.exists()) { validForm = false; errorString = tr("Profile file path is invalid."); } } if (validForm && (ui->applicationLineEdit->text().isEmpty() && ui->winClassLineEdit->text().isEmpty() && ui->winNameLineEdit->text().isEmpty())) { validForm = false; errorString = tr("No window matching property was specified."); } else { propertyFound = true; } if (validForm && !ui->applicationLineEdit->text().isEmpty()) { QString exeFileName = ui->applicationLineEdit->text(); QFileInfo info(exeFileName); if (info.isAbsolute() && (!info.exists() || !info.isExecutable())) { validForm = false; errorString = tr("Program path is invalid or not executable."); } #ifdef Q_OS_WIN else if (!info.isAbsolute() && (info.fileName() != exeFileName || info.suffix() != "exe")) { validForm = false; errorString = tr("File is not an .exe file."); } #endif } if (validForm && !propertyFound && !ui->asDefaultCheckBox->isChecked()) { validForm = false; errorString = tr("No window matching property was selected."); } if (validForm) { QDialog::accept(); } else { QMessageBox msgBox; msgBox.setText(errorString); msgBox.setStandardButtons(QMessageBox::Close); msgBox.exec(); } } #ifdef Q_OS_WIN void AddEditAutoProfileDialog::openWinAppProfileDialog() { WinAppProfileTimerDialog *dialog = new WinAppProfileTimerDialog(this); connect(dialog, SIGNAL(accepted()), this, SLOT(captureWindowsApplicationPath())); dialog->show(); } void AddEditAutoProfileDialog::captureWindowsApplicationPath() { CapturedWindowInfoDialog *dialog = new CapturedWindowInfoDialog(this); connect(dialog, SIGNAL(accepted()), this, SLOT(windowPropAssignment())); dialog->show(); /*QString temp = WinExtras::getForegroundWindowExePath(); if (!temp.isEmpty()) { ui->applicationLineEdit->setText(temp); } */ } #endif antimicro-2.23/src/addeditautoprofiledialog.h000066400000000000000000000045371300750276700214350ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef ADDEDITAUTOPROFILEDIALOG_H #define ADDEDITAUTOPROFILEDIALOG_H #include #include "autoprofileinfo.h" #include "inputdevice.h" #include "antimicrosettings.h" namespace Ui { class AddEditAutoProfileDialog; } class AddEditAutoProfileDialog : public QDialog { Q_OBJECT public: explicit AddEditAutoProfileDialog(AutoProfileInfo *info, AntiMicroSettings *settings, QList *devices, QList &reservedGUIDS, bool edit=false, QWidget *parent = 0); ~AddEditAutoProfileDialog(); AutoProfileInfo* getAutoProfile(); QString getOriginalGUID(); QString getOriginalExe(); QString getOriginalWindowClass(); QString getOriginalWindowName(); protected: virtual void accept(); AutoProfileInfo *info; QList *devices; AntiMicroSettings *settings; bool editForm; bool defaultInfo; QList reservedGUIDs; QString originalGUID; QString originalExe; QString originalWindowClass; QString originalWindowName; private: Ui::AddEditAutoProfileDialog *ui; signals: void captureFinished(); private slots: void openProfileBrowseDialog(); void openApplicationBrowseDialog(); void saveAutoProfileInformation(); void checkForReservedGUIDs(int index); void checkForDefaultStatus(); void windowPropAssignment(); #ifdef Q_OS_WIN void openWinAppProfileDialog(); void captureWindowsApplicationPath(); #else void showCaptureHelpWindow(); void checkForGrabbedWindow(); #endif }; #endif // ADDEDITAUTOPROFILEDIALOG_H antimicro-2.23/src/addeditautoprofiledialog.ui000066400000000000000000000145101300750276700216130ustar00rootroot00000000000000 AddEditAutoProfileDialog 0 0 478 327 Auto Profile Dialog true Profile: profileLineEdit Browse Window: false false 6 4 Select Window. Click on the appropriate application window and the application file path will be populated in the form. Detect Window Properties Class: applicationLineEdit Title: applicationLineEdit Application: applicationLineEdit Browse Select Window. Click on the appropriate application window and the application file path will be populated in the form. Select Devices: devicesComboBox false Select this profile to be the default loaded for the specified device. The selection will be used instead of the all default profile option. Set as Default for Controller Qt::Horizontal Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() AddEditAutoProfileDialog accept() 248 254 157 274 buttonBox rejected() AddEditAutoProfileDialog reject() 316 260 286 274 antimicro-2.23/src/advancebuttondialog.cpp000066400000000000000000001547571300750276700207670ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include #include #include #include #include #include #include #include #include "advancebuttondialog.h" #include "ui_advancebuttondialog.h" #include "event.h" #include "inputdevice.h" //#include "logger.h" const int AdvanceButtonDialog::MINIMUMTURBO = 2; AdvanceButtonDialog::AdvanceButtonDialog(JoyButton *button, QWidget *parent) : QDialog(parent, Qt::Window), ui(new Ui::AdvanceButtonDialog), helper(button) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); PadderCommon::inputDaemonMutex.lock(); this->button = button; oldRow = 0; helper.moveToThread(button->thread()); if (this->button->getToggleState()) { ui->toggleCheckbox->setChecked(true); } if (this->button->isUsingTurbo()) { ui->turboCheckbox->setChecked(true); ui->turboSlider->setEnabled(true); } int interval = this->button->getTurboInterval() / 10; if (interval < MINIMUMTURBO) { interval = JoyButton::ENABLEDTURBODEFAULT / 10; } ui->turboSlider->setValue(interval); this->changeTurboText(interval); QListIterator iter(*(this->button->getAssignedSlots())); while (iter.hasNext()) { JoyButtonSlot *buttonslot = iter.next(); SimpleKeyGrabberButton *existingCode = new SimpleKeyGrabberButton(this); existingCode->setText(buttonslot->getSlotString()); if (buttonslot->getSlotMode() == JoyButtonSlot::JoyLoadProfile) { if (!buttonslot->getTextData().isEmpty()) { existingCode->setValue(buttonslot->getTextData(), JoyButtonSlot::JoyLoadProfile); existingCode->setToolTip(buttonslot->getTextData()); } } else if (buttonslot->getSlotMode() == JoyButtonSlot::JoyTextEntry) { if (!buttonslot->getTextData().isEmpty()) { existingCode->setValue(buttonslot->getTextData(), JoyButtonSlot::JoyTextEntry); existingCode->setToolTip(buttonslot->getTextData()); } } else if (buttonslot->getSlotMode() == JoyButtonSlot::JoyExecute) { if (!buttonslot->getTextData().isEmpty()) { existingCode->setValue(buttonslot->getTextData(), JoyButtonSlot::JoyExecute); existingCode->setToolTip(buttonslot->getTextData()); if (buttonslot->getExtraData().canConvert()) { QString argumentsTemp = buttonslot->getExtraData().toString(); existingCode->getValue()->setExtraData(argumentsTemp); } } } else { existingCode->setValue(buttonslot->getSlotCode(), buttonslot->getSlotCodeAlias(), buttonslot->getSlotMode()); } QListWidgetItem *item = new QListWidgetItem(ui->slotListWidget); item->setData(Qt::UserRole, QVariant::fromValue(existingCode)); QHBoxLayout *layout= new QHBoxLayout(); layout->setContentsMargins(10, 0, 10, 0); layout->addWidget(existingCode); QWidget *widget = new QWidget(); widget->setLayout(layout); item->setSizeHint(widget->sizeHint()); ui->slotListWidget->setItemWidget(item, widget); connectButtonEvents(existingCode); } appendBlankKeyGrabber(); populateSetSelectionComboBox(); populateSlotSetSelectionComboBox(); if (this->button->getSetSelection() > -1 && this->button->getChangeSetCondition() != JoyButton::SetChangeDisabled) { int selectIndex = (int)this->button->getChangeSetCondition(); selectIndex += this->button->getSetSelection() * 3; if (this->button->getOriginSet() < this->button->getSetSelection()) { selectIndex -= 3; } ui->setSelectionComboBox->setCurrentIndex(selectIndex); } fillTimeComboBoxes(); ui->actionTenthsComboBox->setCurrentIndex(1); updateActionTimeLabel(); changeTurboForSequences(); if (button->isCycleResetActive()) { ui->autoResetCycleCheckBox->setEnabled(true); ui->autoResetCycleCheckBox->setChecked(true); checkCycleResetWidgetStatus(true); } if (button->getCycleResetTime() != 0) { populateAutoResetInterval(); } updateWindowTitleButtonName(); if (this->button->isPartRealAxis() && this->button->isUsingTurbo()) { ui->turboModeComboBox->setEnabled(true); } else if (!this->button->isPartRealAxis()) { ui->turboModeComboBox->setVisible(false); ui->turboModeLabel->setVisible(false); } findTurboModeComboIndex(); // Don't show Set Selector page for modifier buttons if (this->button->isModifierButton()) { delete ui->listWidget->item(3); } //performStatsWidgetRefresh(ui->slotListWidget->currentItem()); changeSlotHelpText(ui->slotTypeComboBox->currentIndex()); PadderCommon::inputDaemonMutex.unlock(); ui->resetCycleDoubleSpinBox->setMaximum(static_cast(JoyButton::MAXCYCLERESETTIME * 0.001)); connect(ui->turboCheckbox, SIGNAL(clicked(bool)), ui->turboSlider, SLOT(setEnabled(bool))); connect(ui->turboSlider, SIGNAL(valueChanged(int)), this, SLOT(checkTurboIntervalValue(int))); connect(ui->insertSlotButton, SIGNAL(clicked()), this, SLOT(insertSlot())); connect(ui->deleteSlotButton, SIGNAL(clicked()), this, SLOT(deleteSlot())); connect(ui->clearAllPushButton, SIGNAL(clicked()), this, SLOT(clearAllSlots())); connect(ui->slotTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeSlotTypeDisplay(int))); connect(ui->slotTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeSlotHelpText(int))); connect(ui->actionHundredthsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateActionTimeLabel())); connect(ui->actionSecondsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateActionTimeLabel())); connect(ui->actionMinutesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateActionTimeLabel())); connect(ui->actionTenthsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateActionTimeLabel())); connect(ui->toggleCheckbox, SIGNAL(clicked(bool)), button, SLOT(setToggle(bool))); connect(ui->turboCheckbox, SIGNAL(clicked(bool)), this, SLOT(checkTurboSetting(bool))); connect(ui->setSelectionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateSetSelection())); connect(ui->slotListWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(performStatsWidgetRefresh(QListWidgetItem*))); connect(ui->actionHundredthsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkSlotTimeUpdate())); connect(ui->actionTenthsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkSlotTimeUpdate())); connect(ui->actionSecondsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkSlotTimeUpdate())); connect(ui->actionMinutesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkSlotTimeUpdate())); connect(ui->slotSetChangeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkSlotSetChangeUpdate())); connect(ui->distanceSpinBox, SIGNAL(valueChanged(int)), this, SLOT(checkSlotDistanceUpdate())); connect(ui->mouseSpeedModSpinBox, SIGNAL(valueChanged(int)), this, SLOT(checkSlotMouseModUpdate())); connect(ui->autoResetCycleCheckBox, SIGNAL(clicked(bool)), this, SLOT(checkCycleResetWidgetStatus(bool))); connect(ui->autoResetCycleCheckBox, SIGNAL(clicked(bool)), this, SLOT(setButtonCycleReset(bool))); connect(ui->resetCycleDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(setButtonCycleResetInterval(double))); connect(button, SIGNAL(toggleChanged(bool)), ui->toggleCheckbox, SLOT(setChecked(bool))); connect(button, SIGNAL(turboChanged(bool)), this, SLOT(checkTurboSetting(bool))); connect(ui->turboModeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setButtonTurboMode(int))); connect(ui->loadProfilePushButton, SIGNAL(clicked()), this, SLOT(showSelectProfileWindow())); connect(ui->execToolButton, SIGNAL(clicked(bool)), this, SLOT(showFindExecutableWindow(bool))); } AdvanceButtonDialog::~AdvanceButtonDialog() { delete ui; } void AdvanceButtonDialog::changeTurboText(int value) { if (value >= MINIMUMTURBO) { double delay = value / 100.0; double clicks = 100.0 / (double)value; QString delaytext = QString::number(delay, 'g', 3).append(" ").append(tr("sec.")); QString labeltext = QString::number(clicks, 'g', 2).append(" ").append(tr("/sec.")); ui->delayValueLabel->setText(delaytext); ui->rateValueLabel->setText(labeltext); } } void AdvanceButtonDialog::updateSlotsScrollArea(int value) { int index = ui->slotListWidget->currentRow(); int itemcount = ui->slotListWidget->count(); if (index == (itemcount - 1) && value >= 0) { // New slot added on the old blank button. Append // new blank button to the end of the list. appendBlankKeyGrabber(); } // Go through all grabber buttons in list and possibly resize widgets. for (int i = 0; i < ui->slotListWidget->count(); i++) { QListWidgetItem *item = ui->slotListWidget->item(i); QWidget *widget = ui->slotListWidget->itemWidget(item); item->setSizeHint(widget->sizeHint()); } // Alter interface if turbo cannot be used. changeTurboForSequences(); emit slotsChanged(); } void AdvanceButtonDialog::connectButtonEvents(SimpleKeyGrabberButton *button) { connect(button, SIGNAL(clicked()), this, SLOT(changeSelectedSlot())); connect(button, SIGNAL(buttonCodeChanged(int)), this, SLOT(updateSelectedSlot(int))); //connect(button, SIGNAL(buttonCodeChanged(int)), this, SLOT(updateSlotsScrollArea(int))); } void AdvanceButtonDialog::updateSelectedSlot(int value) { SimpleKeyGrabberButton *grabbutton = static_cast(sender()); JoyButtonSlot *tempbuttonslot = grabbutton->getValue(); int index = ui->slotListWidget->currentRow(); QMetaObject::invokeMethod(&helper, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, tempbuttonslot->getSlotCode()), Q_ARG(unsigned int, tempbuttonslot->getSlotCodeAlias()), Q_ARG(int, index), Q_ARG(JoyButtonSlot::JoySlotInputAction, tempbuttonslot->getSlotMode())); updateSlotsScrollArea(value); } void AdvanceButtonDialog::deleteSlot() { int index = ui->slotListWidget->currentRow(); int itemcount = ui->slotListWidget->count(); QListWidgetItem *item = ui->slotListWidget->takeItem(index); delete item; item = 0; // Deleted last button. Replace with new blank button if (index == itemcount - 1) { appendBlankKeyGrabber(); } changeTurboForSequences(); QMetaObject::invokeMethod(&helper, "removeAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, index)); index = qMax(0, index-1); performStatsWidgetRefresh(ui->slotListWidget->item(index)); emit slotsChanged(); } void AdvanceButtonDialog::changeSelectedSlot() { SimpleKeyGrabberButton *button = static_cast(sender()); bool leave = false; for (int i = 0; i < ui->slotListWidget->count() && !leave; i++) { QListWidgetItem *item = ui->slotListWidget->item(i); SimpleKeyGrabberButton *tempbutton = item->data(Qt::UserRole) .value(); if (button == tempbutton) { ui->slotListWidget->setCurrentRow(i); leave = true; oldRow = i; } } } void AdvanceButtonDialog::appendBlankKeyGrabber() { SimpleKeyGrabberButton *blankButton = new SimpleKeyGrabberButton(this); QListWidgetItem *item = new QListWidgetItem(ui->slotListWidget); item->setData(Qt::UserRole, QVariant::fromValue(blankButton)); QHBoxLayout *layout= new QHBoxLayout(); layout->setContentsMargins(10, 0, 10, 0); layout->addWidget(blankButton); QWidget *widget = new QWidget(); widget->setLayout(layout); item->setSizeHint(widget->sizeHint()); ui->slotListWidget->setItemWidget(item, widget); ui->slotListWidget->setCurrentItem(item); connectButtonEvents(blankButton); ui->slotTypeComboBox->setCurrentIndex(KBMouseSlot); } void AdvanceButtonDialog::insertSlot() { int current = ui->slotListWidget->currentRow(); int count = ui->slotListWidget->count(); int slotTypeIndex = ui->slotTypeComboBox->currentIndex(); if (slotTypeIndex == KBMouseSlot) { if (current != (count - 1)) { SimpleKeyGrabberButton *blankButton = new SimpleKeyGrabberButton(this); QListWidgetItem *item = new QListWidgetItem(); ui->slotListWidget->insertItem(current, item); item->setData(Qt::UserRole, QVariant::fromValue(blankButton)); QHBoxLayout *layout= new QHBoxLayout(); layout->addWidget(blankButton); QWidget *widget = new QWidget(); widget->setLayout(layout); item->setSizeHint(widget->sizeHint()); ui->slotListWidget->setItemWidget(item, widget); ui->slotListWidget->setCurrentItem(item); connectButtonEvents(blankButton); blankButton->refreshButtonLabel(); QMetaObject::invokeMethod(&helper, "insertAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, 0), Q_ARG(uint, 0), Q_ARG(int, current)); updateSlotsScrollArea(0); } } else if (slotTypeIndex == CycleSlot) { insertCycleSlot(); } else if (slotTypeIndex == DelaySlot) { insertDelaySlot(); } else if (slotTypeIndex == DistanceSlot) { insertDistanceSlot(); } else if (slotTypeIndex == HoldSlot) { insertHoldSlot(); } else if (slotTypeIndex == LoadSlot) { showSelectProfileWindow(); } else if (slotTypeIndex == MouseModSlot) { insertMouseSpeedModSlot(); } else if (slotTypeIndex == PauseSlot) { insertPauseSlot(); } else if (slotTypeIndex == PressTimeSlot) { insertKeyPressSlot(); } else if (slotTypeIndex == ReleaseSlot) { insertReleaseSlot(); } else if (slotTypeIndex == SetChangeSlot) { insertSetChangeSlot(); } else if (slotTypeIndex == TextEntry) { insertTextEntrySlot(); } else if (slotTypeIndex == ExecuteSlot) { insertExecuteSlot(); } } void AdvanceButtonDialog::insertPauseSlot() { int index = ui->slotListWidget->currentRow(); SimpleKeyGrabberButton *tempbutton = ui->slotListWidget->currentItem() ->data(Qt::UserRole).value(); int actionTime = actionTimeConvert(); if (actionTime >= 0) { tempbutton->setValue(actionTime, JoyButtonSlot::JoyPause); QMetaObject::invokeMethod(&helper, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, actionTime), Q_ARG(unsigned int, 0), Q_ARG(int, index), Q_ARG(JoyButtonSlot::JoySlotInputAction, JoyButtonSlot::JoyPause)); updateSlotsScrollArea(actionTime); } } void AdvanceButtonDialog::insertReleaseSlot() { int index = ui->slotListWidget->currentRow(); SimpleKeyGrabberButton *tempbutton = ui->slotListWidget->currentItem() ->data(Qt::UserRole).value(); int actionTime = actionTimeConvert(); if (actionTime >= 0) { tempbutton->setValue(actionTime, JoyButtonSlot::JoyRelease); QMetaObject::invokeMethod(&helper, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, actionTime), Q_ARG(unsigned int, 0), Q_ARG(int, index), Q_ARG(JoyButtonSlot::JoySlotInputAction, JoyButtonSlot::JoyRelease)); updateSlotsScrollArea(actionTime); } } void AdvanceButtonDialog::insertHoldSlot() { int index = ui->slotListWidget->currentRow(); SimpleKeyGrabberButton *tempbutton = ui->slotListWidget->currentItem() ->data(Qt::UserRole).value(); int actionTime = actionTimeConvert(); if (actionTime > 0) { tempbutton->setValue(actionTime, JoyButtonSlot::JoyHold); QMetaObject::invokeMethod(&helper, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, actionTime), Q_ARG(unsigned int, 0), Q_ARG(int, index), Q_ARG(JoyButtonSlot::JoySlotInputAction, JoyButtonSlot::JoyHold)); updateSlotsScrollArea(actionTime); } } void AdvanceButtonDialog::insertSetChangeSlot() { int index = ui->slotListWidget->currentRow(); SimpleKeyGrabberButton *tempbutton = ui->slotListWidget->currentItem() ->data(Qt::UserRole).value(); int currentIndex = ui->slotSetChangeComboBox->currentIndex(); unsigned int setIndex = ui->slotSetChangeComboBox->itemData(currentIndex).toInt(); if (setIndex >= 0) { tempbutton->setValue(setIndex, JoyButtonSlot::JoySetChange); QMetaObject::invokeMethod(&helper, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, setIndex), Q_ARG(unsigned int, 0), Q_ARG(int, index), Q_ARG(JoyButtonSlot::JoySlotInputAction, JoyButtonSlot::JoySetChange)); updateSlotsScrollArea(setIndex); } } int AdvanceButtonDialog::actionTimeConvert() { int minutesIndex = ui->actionMinutesComboBox->currentIndex(); int secondsIndex = ui->actionSecondsComboBox->currentIndex(); int hundredthsIndex = ui->actionHundredthsComboBox->currentIndex(); int tenthsIndex = ui->actionTenthsComboBox->currentIndex(); int tempMilliSeconds = minutesIndex * 1000 * 60; tempMilliSeconds += secondsIndex * 1000; tempMilliSeconds += tenthsIndex * 100; tempMilliSeconds += hundredthsIndex * 10; return tempMilliSeconds; } void AdvanceButtonDialog::refreshTimeComboBoxes(JoyButtonSlot *slot) { disconnectTimeBoxesEvents(); int slottime = slot->getSlotCode(); int tempMinutes = slottime / 1000 / 60; int tempSeconds = slottime / 1000 % 60; int tempTenthsSeconds = (slottime % 1000) / 100; int tempHundredthsSeconds = (slottime % 1000 % 100) / 10; ui->actionMinutesComboBox->setCurrentIndex(tempMinutes); ui->actionSecondsComboBox->setCurrentIndex(tempSeconds); ui->actionTenthsComboBox->setCurrentIndex(tempTenthsSeconds); ui->actionHundredthsComboBox->setCurrentIndex(tempHundredthsSeconds); updateActionTimeLabel(); connectTimeBoxesEvents(); } void AdvanceButtonDialog::updateActionTimeLabel() { int actionTime = actionTimeConvert(); int minutes = actionTime / 1000 / 60; double hundredths = actionTime % 1000 / 1000.0; double seconds = (actionTime / 1000 % 60) + hundredths; QString temp; temp.append(QString::number(minutes)).append("m "); temp.append(QString::number(seconds, 'f', 2)).append("s"); ui->actionTimeLabel->setText(temp); } void AdvanceButtonDialog::clearAllSlots() { ui->slotListWidget->clear(); appendBlankKeyGrabber(); changeTurboForSequences(); QMetaObject::invokeMethod(button, "clearSlotsEventReset", Qt::BlockingQueuedConnection); performStatsWidgetRefresh(ui->slotListWidget->currentItem()); emit slotsChanged(); } void AdvanceButtonDialog::changeTurboForSequences() { bool containsSequences = false; for (int i = 0; i < ui->slotListWidget->count() && !containsSequences; i++) { SimpleKeyGrabberButton *button = ui->slotListWidget->item(i) ->data(Qt::UserRole).value(); JoyButtonSlot *tempbuttonslot = button->getValue(); if (tempbuttonslot->getSlotCode() > 0 && (tempbuttonslot->getSlotMode() == JoyButtonSlot::JoyPause || tempbuttonslot->getSlotMode() == JoyButtonSlot::JoyHold || tempbuttonslot->getSlotMode() == JoyButtonSlot::JoyDistance ) ) { containsSequences = true; } } if (containsSequences) { if (ui->turboCheckbox->isChecked()) { ui->turboCheckbox->setChecked(false); this->button->setUseTurbo(false); emit turboChanged(false); } if (ui->turboCheckbox->isEnabled()) { ui->turboCheckbox->setEnabled(false); emit turboButtonEnabledChange(false); } } else { if (!ui->turboCheckbox->isEnabled()) { ui->turboCheckbox->setEnabled(true); emit turboButtonEnabledChange(true); } } } void AdvanceButtonDialog::insertCycleSlot() { int index = ui->slotListWidget->currentRow(); SimpleKeyGrabberButton *tempbutton = ui->slotListWidget->currentItem() ->data(Qt::UserRole).value(); tempbutton->setValue(1, JoyButtonSlot::JoyCycle); QMetaObject::invokeMethod(&helper, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, 1), Q_ARG(unsigned int, 0), Q_ARG(int, index), Q_ARG(JoyButtonSlot::JoySlotInputAction, JoyButtonSlot::JoyCycle)); updateSlotsScrollArea(1); } void AdvanceButtonDialog::insertDistanceSlot() { int index = ui->slotListWidget->currentRow(); SimpleKeyGrabberButton *tempbutton = ui->slotListWidget->currentItem() ->data(Qt::UserRole).value(); int tempDistance = 0; for (int i = 0; i < ui->slotListWidget->count(); i++) { SimpleKeyGrabberButton *button = ui->slotListWidget->item(i) ->data(Qt::UserRole).value(); JoyButtonSlot *tempbuttonslot = button->getValue(); if (tempbuttonslot->getSlotMode() == JoyButtonSlot::JoyDistance) { tempDistance += tempbuttonslot->getSlotCode(); } else if (tempbuttonslot->getSlotMode() == JoyButtonSlot::JoyCycle) { tempDistance = 0; } } int testDistance = ui->distanceSpinBox->value(); if (testDistance + tempDistance <= 100) { tempbutton->setValue(testDistance, JoyButtonSlot::JoyDistance); QMetaObject::invokeMethod(&helper, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, testDistance), Q_ARG(unsigned int, 0), Q_ARG(int, index), Q_ARG(JoyButtonSlot::JoySlotInputAction, JoyButtonSlot::JoyDistance)); updateSlotsScrollArea(testDistance); } } void AdvanceButtonDialog::placeNewSlot(JoyButtonSlot *slot) { int index = ui->slotListWidget->currentRow(); SimpleKeyGrabberButton *tempbutton = ui->slotListWidget->currentItem() ->data(Qt::UserRole).value(); tempbutton->setValue(slot->getSlotCode(), slot->getSlotCodeAlias(), slot->getSlotMode()); QMetaObject::invokeMethod(&helper, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, slot->getSlotCode()), Q_ARG(unsigned int, slot->getSlotCodeAlias()), Q_ARG(int, index), Q_ARG(JoyButtonSlot::JoySlotInputAction, slot->getSlotMode())); updateSlotsScrollArea(slot->getSlotCode()); slot->deleteLater(); } void AdvanceButtonDialog::updateTurboIntervalValue(int value) { if (value >= MINIMUMTURBO) { button->setTurboInterval(value * 10); } } void AdvanceButtonDialog::checkTurboSetting(bool state) { ui->turboCheckbox->setChecked(state); ui->turboSlider->setEnabled(state); if (this->button->isPartRealAxis()) { ui->turboModeComboBox->setEnabled(state); } changeTurboForSequences(); button->setUseTurbo(state); if (button->getTurboInterval() / 10 >= MINIMUMTURBO) { ui->turboSlider->setValue(button->getTurboInterval() / 10); } } void AdvanceButtonDialog::updateSetSelection() { PadderCommon::inputDaemonMutex.lock(); int condition_choice = 0; int chosen_set = -1; JoyButton::SetChangeCondition set_selection_condition = JoyButton::SetChangeDisabled; if (ui->setSelectionComboBox->currentIndex() > 0) { condition_choice = (ui->setSelectionComboBox->currentIndex() + 2) % 3; chosen_set = (ui->setSelectionComboBox->currentIndex() - 1) / 3; // Above removed rows if (button->getOriginSet() > chosen_set) { chosen_set = (ui->setSelectionComboBox->currentIndex() - 1) / 3; } // Below removed rows else { chosen_set = (ui->setSelectionComboBox->currentIndex() + 2) / 3; } //qDebug() << "CONDITION: " << QString::number(condition_choice) << endl; if (condition_choice == 0) { set_selection_condition = JoyButton::SetChangeOneWay; } else if (condition_choice == 1) { set_selection_condition = JoyButton::SetChangeTwoWay; } else if (condition_choice == 2) { set_selection_condition = JoyButton::SetChangeWhileHeld; } //qDebug() << "CHOSEN SET: " << chosen_set << endl; } else { chosen_set = -1; set_selection_condition = JoyButton::SetChangeDisabled; } if (chosen_set > -1 && set_selection_condition != JoyButton::SetChangeDisabled) { // First, remove old condition for the button in both sets. // After that, make the new assignment. button->setChangeSetCondition(JoyButton::SetChangeDisabled); button->setChangeSetSelection(chosen_set); button->setChangeSetCondition(set_selection_condition); } else { button->setChangeSetCondition(JoyButton::SetChangeDisabled); } PadderCommon::inputDaemonMutex.unlock(); } void AdvanceButtonDialog::checkTurboIntervalValue(int value) { if (value >= MINIMUMTURBO) { changeTurboText(value); updateTurboIntervalValue(value); } else { ui->turboSlider->setValue(MINIMUMTURBO); } } void AdvanceButtonDialog::fillTimeComboBoxes() { ui->actionMinutesComboBox->clear(); ui->actionSecondsComboBox->clear(); ui->actionHundredthsComboBox->clear(); ui->actionTenthsComboBox->clear(); for (double i=0; i <= 10; i++) { QString temp = QString::number(i, 'g', 2).append("m"); ui->actionMinutesComboBox->addItem(temp); } for (double i=0; i <= 59; i++) { QString temp = QString::number(i, 'g', 2); ui->actionSecondsComboBox->addItem(temp); } for (int i=0; i < 10; i++) { QString temp = QString(".%1").arg(i, 1, 10, QChar('0')); ui->actionTenthsComboBox->addItem(temp); } for (int i=0; i < 10; i++) { QString temp = QString("%1s").arg(i, 1, 10, QChar('0')); ui->actionHundredthsComboBox->addItem(temp); } } void AdvanceButtonDialog::insertMouseSpeedModSlot() { int index = ui->slotListWidget->currentRow(); SimpleKeyGrabberButton *tempbutton = ui->slotListWidget->currentItem() ->data(Qt::UserRole).value(); int tempMouseMod = ui->mouseSpeedModSpinBox->value(); if (tempMouseMod > 0) { tempbutton->setValue(tempMouseMod, JoyButtonSlot::JoyMouseSpeedMod); QMetaObject::invokeMethod(&helper, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, tempMouseMod), Q_ARG(unsigned int, 0), Q_ARG(int, index), Q_ARG(JoyButtonSlot::JoySlotInputAction, JoyButtonSlot::JoyMouseSpeedMod)); updateSlotsScrollArea(tempMouseMod); } } void AdvanceButtonDialog::insertKeyPressSlot() { int index = ui->slotListWidget->currentRow(); SimpleKeyGrabberButton *tempbutton = ui->slotListWidget->currentItem() ->data(Qt::UserRole).value(); int actionTime = actionTimeConvert(); if (actionTime > 0) { tempbutton->setValue(actionTime, JoyButtonSlot::JoyKeyPress); QMetaObject::invokeMethod(&helper, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, actionTime), Q_ARG(unsigned int, 0), Q_ARG(int, index), Q_ARG(JoyButtonSlot::JoySlotInputAction, JoyButtonSlot::JoyKeyPress)); updateSlotsScrollArea(actionTime); } } void AdvanceButtonDialog::insertDelaySlot() { //PadderCommon::lockInputDevices(); int index = ui->slotListWidget->currentRow(); SimpleKeyGrabberButton *tempbutton = ui->slotListWidget->currentItem() ->data(Qt::UserRole).value(); int actionTime = actionTimeConvert(); if (actionTime > 0) { tempbutton->setValue(actionTime, JoyButtonSlot::JoyDelay); QMetaObject::invokeMethod(&helper, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, actionTime), Q_ARG(unsigned int, 0), Q_ARG(int, index), Q_ARG(JoyButtonSlot::JoySlotInputAction, JoyButtonSlot::JoyDelay)); updateSlotsScrollArea(actionTime); } } void AdvanceButtonDialog::insertTextEntrySlot() { int index = ui->slotListWidget->currentRow(); SimpleKeyGrabberButton *tempbutton = ui->slotListWidget->currentItem() ->data(Qt::UserRole).value(); QString temp = ui->textEntryLineEdit->text(); if (!temp.isEmpty()) { tempbutton->setValue(temp, JoyButtonSlot::JoyTextEntry); QMetaObject::invokeMethod(&helper, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(JoyButtonSlot*, tempbutton->getValue()), Q_ARG(int, index)); tempbutton->setToolTip(temp); updateSlotsScrollArea(0); } } void AdvanceButtonDialog::insertExecuteSlot() { int index = ui->slotListWidget->currentRow(); SimpleKeyGrabberButton *tempbutton = ui->slotListWidget->currentItem() ->data(Qt::UserRole).value(); QString temp = ui->execLineEdit->text(); QString argumentsTemp = ui->execArgumentsLineEdit->text(); if (!temp.isEmpty()) { QFileInfo tempFileInfo(temp); if (tempFileInfo.exists() && tempFileInfo.isExecutable()) { tempbutton->setValue(temp, JoyButtonSlot::JoyExecute); if (!argumentsTemp.isEmpty()) { tempbutton->getValue()->setExtraData(QVariant(argumentsTemp)); } QMetaObject::invokeMethod(&helper, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(JoyButtonSlot*, tempbutton->getValue()), Q_ARG(int, index)); tempbutton->setToolTip(temp); updateSlotsScrollArea(0); } } } void AdvanceButtonDialog::performStatsWidgetRefresh(QListWidgetItem *item) { SimpleKeyGrabberButton *tempbutton = item->data(Qt::UserRole).value(); JoyButtonSlot *slot = tempbutton->getValue(); if (slot->getSlotMode() == JoyButtonSlot::JoyKeyboard && slot->getSlotCode() != 0) { ui->slotTypeComboBox->setCurrentIndex(KBMouseSlot); } else if (slot->getSlotMode() == JoyButtonSlot::JoyMouseButton || slot->getSlotMode() == JoyButtonSlot::JoyMouseMovement) { ui->slotTypeComboBox->setCurrentIndex(KBMouseSlot); } else if (slot->getSlotMode() == JoyButtonSlot::JoyCycle) { ui->slotTypeComboBox->setCurrentIndex(CycleSlot); } else if (slot->getSlotMode() == JoyButtonSlot::JoyDelay) { ui->slotTypeComboBox->setCurrentIndex(DelaySlot); //changeSlotTypeDisplay(DelaySlot); refreshTimeComboBoxes(slot); } else if (slot->getSlotMode() == JoyButtonSlot::JoyDistance) { ui->slotTypeComboBox->setCurrentIndex(DistanceSlot); disconnect(ui->distanceSpinBox, SIGNAL(valueChanged(int)), this, SLOT(checkSlotDistanceUpdate())); ui->distanceSpinBox->setValue(slot->getSlotCode()); connect(ui->distanceSpinBox, SIGNAL(valueChanged(int)), this, SLOT(checkSlotDistanceUpdate())); } else if (slot->getSlotMode() == JoyButtonSlot::JoyHold) { ui->slotTypeComboBox->setCurrentIndex(HoldSlot); refreshTimeComboBoxes(slot); } else if (slot->getSlotMode() == JoyButtonSlot::JoyLoadProfile) { ui->slotTypeComboBox->setCurrentIndex(LoadSlot); } else if (slot->getSlotMode() == JoyButtonSlot::JoyMouseSpeedMod) { ui->slotTypeComboBox->setCurrentIndex(MouseModSlot); disconnect(ui->mouseSpeedModSpinBox, SIGNAL(valueChanged(int)), this, SLOT(checkSlotMouseModUpdate())); ui->mouseSpeedModSpinBox->setValue(slot->getSlotCode()); connect(ui->mouseSpeedModSpinBox, SIGNAL(valueChanged(int)), this, SLOT(checkSlotMouseModUpdate())); } else if (slot->getSlotMode() == JoyButtonSlot::JoyPause) { ui->slotTypeComboBox->setCurrentIndex(PauseSlot); refreshTimeComboBoxes(slot); } else if (slot->getSlotMode() == JoyButtonSlot::JoyKeyPress) { ui->slotTypeComboBox->setCurrentIndex(PressTimeSlot); refreshTimeComboBoxes(slot); } else if (slot->getSlotMode() == JoyButtonSlot::JoyRelease) { ui->slotTypeComboBox->setCurrentIndex(ReleaseSlot); refreshTimeComboBoxes(slot); } else if (slot->getSlotMode() == JoyButtonSlot::JoySetChange) { disconnect(ui->slotSetChangeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkSlotSetChangeUpdate())); ui->slotTypeComboBox->setCurrentIndex(SetChangeSlot); unsigned int chooseIndex = slot->getSlotCode(); int foundIndex = ui->slotSetChangeComboBox->findData(QVariant(chooseIndex)); if (foundIndex >= 0) { ui->slotSetChangeComboBox->setCurrentIndex(foundIndex); } connect(ui->slotSetChangeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkSlotSetChangeUpdate())); } else if (slot->getSlotMode() == JoyButtonSlot::JoyTextEntry) { ui->slotTypeComboBox->setCurrentIndex(TextEntry); ui->textEntryLineEdit->setText(slot->getTextData()); } else if (slot->getSlotMode() == JoyButtonSlot::JoyExecute) { ui->slotTypeComboBox->setCurrentIndex(ExecuteSlot); ui->execLineEdit->setText(slot->getTextData()); ui->execArgumentsLineEdit->setText(slot->getExtraData().toString()); } /*else { ui->slotTypeComboBox->setCurrentIndex(KBMouseSlot); } */ } void AdvanceButtonDialog::checkSlotTimeUpdate() { int index = ui->slotListWidget->currentRow(); SimpleKeyGrabberButton *tempbutton = ui->slotListWidget->currentItem() ->data(Qt::UserRole).value(); JoyButtonSlot *tempbuttonslot = tempbutton->getValue(); if (tempbuttonslot->getSlotMode() == JoyButtonSlot::JoyPause || tempbuttonslot->getSlotMode() == JoyButtonSlot::JoyHold || tempbuttonslot->getSlotMode() == JoyButtonSlot::JoyRelease || tempbuttonslot->getSlotMode() == JoyButtonSlot::JoyKeyPress || tempbuttonslot->getSlotMode() == JoyButtonSlot::JoyDelay) { int actionTime = actionTimeConvert(); if (actionTime > 0) { tempbutton->setValue(actionTime, tempbuttonslot->getSlotMode()); QMetaObject::invokeMethod(&helper, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, actionTime), Q_ARG(unsigned int, 0), Q_ARG(int, index), Q_ARG(JoyButtonSlot::JoySlotInputAction, tempbuttonslot->getSlotMode())); updateSlotsScrollArea(actionTime); } } } void AdvanceButtonDialog::checkSlotMouseModUpdate() { int index = ui->slotListWidget->currentRow(); SimpleKeyGrabberButton *tempbutton = ui->slotListWidget->currentItem() ->data(Qt::UserRole).value(); JoyButtonSlot *tempbuttonslot = tempbutton->getValue(); int tempMouseMod = ui->mouseSpeedModSpinBox->value(); if (tempbuttonslot->getSlotMode() == JoyButtonSlot::JoyMouseSpeedMod && tempMouseMod > 0) { tempbutton->setValue(tempMouseMod, tempbuttonslot->getSlotMode()); QMetaObject::invokeMethod(&helper, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, tempMouseMod), Q_ARG(unsigned int, 0), Q_ARG(int, index), Q_ARG(JoyButtonSlot::JoySlotInputAction, tempbuttonslot->getSlotMode())); updateSlotsScrollArea(tempMouseMod); } } void AdvanceButtonDialog::checkSlotSetChangeUpdate() { int index = ui->slotListWidget->currentRow(); SimpleKeyGrabberButton *tempbutton = ui->slotListWidget->currentItem() ->data(Qt::UserRole).value(); JoyButtonSlot *buttonslot = tempbutton->getValue(); if (buttonslot->getSlotMode() == JoyButtonSlot::JoySetChange) { int comboIndex = ui->slotSetChangeComboBox->currentIndex(); int setIndex = ui->slotSetChangeComboBox->itemData(comboIndex).toInt(); if (setIndex >= 0) { tempbutton->setValue(setIndex, buttonslot->getSlotMode()); QMetaObject::invokeMethod(&helper, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, setIndex), Q_ARG(unsigned int, 0), Q_ARG(int, index), Q_ARG(JoyButtonSlot::JoySlotInputAction, buttonslot->getSlotMode())); updateSlotsScrollArea(setIndex); } } } void AdvanceButtonDialog::checkSlotDistanceUpdate() { int index = ui->slotListWidget->currentRow(); SimpleKeyGrabberButton *tempbutton = ui->slotListWidget->currentItem() ->data(Qt::UserRole).value(); JoyButtonSlot *buttonslot = tempbutton->getValue(); int tempDistance = 0; if (buttonslot->getSlotMode() == JoyButtonSlot::JoyDistance) { for (int i = 0; i < ui->slotListWidget->count(); i++) { SimpleKeyGrabberButton *button = ui->slotListWidget->item(i) ->data(Qt::UserRole).value(); JoyButtonSlot *tempbuttonslot = button->getValue(); if (tempbuttonslot->getSlotMode() == JoyButtonSlot::JoyDistance) { tempDistance += tempbuttonslot->getSlotCode(); } else if (tempbuttonslot->getSlotMode() == JoyButtonSlot::JoyCycle) { tempDistance = 0; } } int testDistance = ui->distanceSpinBox->value(); tempDistance += testDistance - buttonslot->getSlotCode(); if (tempDistance <= 100) { tempbutton->setValue(testDistance, buttonslot->getSlotMode()); QMetaObject::invokeMethod(&helper, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, testDistance), Q_ARG(unsigned int, 0), Q_ARG(int, index), Q_ARG(JoyButtonSlot::JoySlotInputAction, buttonslot->getSlotMode())); updateSlotsScrollArea(testDistance); } } } void AdvanceButtonDialog::updateWindowTitleButtonName() { QString temp; temp.append(tr("Advanced").append(": ")).append(button->getPartialName(false, true)); if (button->getParentSet()->getIndex() != 0) { unsigned int setIndex = button->getParentSet()->getRealIndex(); temp.append(" [").append(tr("Set %1").arg(setIndex)); QString setName = button->getParentSet()->getName(); if (!setName.isEmpty()) { temp.append(": ").append(setName); } temp.append("]"); } setWindowTitle(temp); } void AdvanceButtonDialog::checkCycleResetWidgetStatus(bool enabled) { if (enabled) { ui->resetCycleDoubleSpinBox->setEnabled(true); } else { ui->resetCycleDoubleSpinBox->setEnabled(false); } } void AdvanceButtonDialog::setButtonCycleResetInterval(double value) { unsigned int milliseconds = ((int)value * 1000) + (fmod(value, 1.0) * 1000); button->setCycleResetTime(milliseconds); } void AdvanceButtonDialog::populateAutoResetInterval() { double seconds = button->getCycleResetTime() / 1000.0; ui->resetCycleDoubleSpinBox->setValue(seconds); } void AdvanceButtonDialog::setButtonCycleReset(bool enabled) { if (enabled) { button->setCycleResetStatus(true); if (button->getCycleResetTime() == 0 && ui->resetCycleDoubleSpinBox->value() > 0.0) { double current = ui->resetCycleDoubleSpinBox->value(); setButtonCycleResetInterval(current); } } else { button->setCycleResetStatus(false); } } void AdvanceButtonDialog::resetTimeBoxes() { disconnectTimeBoxesEvents(); ui->actionMinutesComboBox->setCurrentIndex(0); ui->actionSecondsComboBox->setCurrentIndex(0); ui->actionTenthsComboBox->setCurrentIndex(1); ui->actionHundredthsComboBox->setCurrentIndex(0); updateActionTimeLabel(); connectTimeBoxesEvents(); } void AdvanceButtonDialog::disconnectTimeBoxesEvents() { disconnect(ui->actionSecondsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateActionTimeLabel())); disconnect(ui->actionHundredthsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateActionTimeLabel())); disconnect(ui->actionMinutesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateActionTimeLabel())); disconnect(ui->actionTenthsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateActionTimeLabel())); disconnect(ui->actionHundredthsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkSlotTimeUpdate())); disconnect(ui->actionSecondsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkSlotTimeUpdate())); disconnect(ui->actionMinutesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkSlotTimeUpdate())); disconnect(ui->actionTenthsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkSlotTimeUpdate())); } void AdvanceButtonDialog::connectTimeBoxesEvents() { connect(ui->actionSecondsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateActionTimeLabel())); connect(ui->actionHundredthsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateActionTimeLabel())); connect(ui->actionMinutesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateActionTimeLabel())); connect(ui->actionTenthsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateActionTimeLabel())); connect(ui->actionHundredthsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkSlotTimeUpdate())); connect(ui->actionSecondsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkSlotTimeUpdate())); connect(ui->actionMinutesComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkSlotTimeUpdate())); connect(ui->actionTenthsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkSlotTimeUpdate())); } void AdvanceButtonDialog::populateSetSelectionComboBox() { ui->setSelectionComboBox->clear(); ui->setSelectionComboBox->insertItem(0, tr("Disabled")); int currentIndex = 1; for (int i=0; i < InputDevice::NUMBER_JOYSETS; i++) { if (this->button->getOriginSet() != i) { QString temp; temp.append(tr("Select Set %1").arg(i+1)); InputDevice *tempdevice = button->getParentSet()->getInputDevice(); SetJoystick *tempset = tempdevice->getSetJoystick(i); if (tempset) { QString setName = tempset->getName(); if (!setName.isEmpty()) { temp.append(" ").append("["); temp.append(setName).append("]").append(" "); } } QString oneWayText; oneWayText.append(temp).append(" ").append(tr("One Way")); QString twoWayText; twoWayText.append(temp).append(" ").append(tr("Two Way")); QString whileHeldText; whileHeldText.append(temp).append(" ").append(tr("While Held")); QStringList setChoices; setChoices.append(oneWayText); setChoices.append(twoWayText); setChoices.append(whileHeldText); ui->setSelectionComboBox->insertItems(currentIndex, setChoices); currentIndex += 3; } } } void AdvanceButtonDialog::populateSlotSetSelectionComboBox() { ui->slotSetChangeComboBox->clear(); unsigned int currentIndex = 0; for (int i=0; i < InputDevice::NUMBER_JOYSETS; i++) { if (this->button->getOriginSet() != i) { QString temp; temp.append(tr("Select Set %1").arg(i+1)); InputDevice *tempdevice = button->getParentSet()->getInputDevice(); SetJoystick *tempset = tempdevice->getSetJoystick(i); if (tempset) { QString setName = tempset->getName(); if (!setName.isEmpty()) { temp.append(" ").append("["); temp.append(setName).append("]").append(" "); } } ui->slotSetChangeComboBox->insertItem(currentIndex, temp, QVariant(i)); currentIndex++; } } } void AdvanceButtonDialog::findTurboModeComboIndex() { JoyButton::TurboMode currentTurboMode = this->button->getTurboMode(); if (currentTurboMode == JoyButton::NormalTurbo) { ui->turboModeComboBox->setCurrentIndex(0); } else if (currentTurboMode == JoyButton::GradientTurbo) { ui->turboModeComboBox->setCurrentIndex(1); } else if (currentTurboMode == JoyButton::PulseTurbo) { ui->turboModeComboBox->setCurrentIndex(2); } } void AdvanceButtonDialog::setButtonTurboMode(int value) { if (value == 0) { this->button->setTurboMode(JoyButton::NormalTurbo); } else if (value == 1) { this->button->setTurboMode(JoyButton::GradientTurbo); } else if (value == 2) { this->button->setTurboMode(JoyButton::PulseTurbo); } } void AdvanceButtonDialog::showSelectProfileWindow() { AntiMicroSettings *settings = this->button->getParentSet()->getInputDevice()->getSettings(); QString lookupDir = PadderCommon::preferredProfileDir(settings); QString filename = QFileDialog::getOpenFileName(this, tr("Choose Profile"), lookupDir, tr("Config Files (*.amgp *.xml)")); if (!filename.isEmpty()) { int index = ui->slotListWidget->currentRow(); SimpleKeyGrabberButton *tempbutton = ui->slotListWidget->currentItem() ->data(Qt::UserRole).value(); tempbutton->setValue(filename, JoyButtonSlot::JoyLoadProfile); QMetaObject::invokeMethod(&helper, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(JoyButtonSlot*, tempbutton->getValue()), Q_ARG(int, index)); tempbutton->setToolTip(filename); updateSlotsScrollArea(0); } } void AdvanceButtonDialog::showFindExecutableWindow(bool) { QString temp = ui->execLineEdit->text(); QString lookupDir = QDir::homePath(); if (!temp.isEmpty()) { QFileInfo tempFileInfo(temp); if (tempFileInfo.absoluteDir().exists()) { lookupDir = tempFileInfo.absoluteDir().absolutePath(); } } QString filepath = QFileDialog::getOpenFileName(this, tr("Choose Executable"), lookupDir); if (!filepath.isEmpty()) { QFileInfo tempFileInfo(filepath); if (tempFileInfo.exists() && tempFileInfo.isExecutable()) { ui->execLineEdit->setText(filepath); } } } void AdvanceButtonDialog::changeSlotTypeDisplay(int index) { if (index == KBMouseSlot) { ui->slotControlsStackedWidget->setCurrentIndex(0); } else if (index == CycleSlot) { ui->slotControlsStackedWidget->setCurrentIndex(3); } else if (index == DelaySlot) { ui->slotControlsStackedWidget->setCurrentIndex(0); } else if (index == DistanceSlot) { ui->slotControlsStackedWidget->setCurrentIndex(2); } else if (index == HoldSlot) { ui->slotControlsStackedWidget->setCurrentIndex(0); } else if (index == LoadSlot) { ui->slotControlsStackedWidget->setCurrentIndex(4); } else if (index == MouseModSlot) { ui->slotControlsStackedWidget->setCurrentIndex(1); } else if (index == PauseSlot) { ui->slotControlsStackedWidget->setCurrentIndex(0); } else if (index == PressTimeSlot) { ui->slotControlsStackedWidget->setCurrentIndex(0); } else if (index == ReleaseSlot) { ui->slotControlsStackedWidget->setCurrentIndex(0); } else if (index == SetChangeSlot) { ui->slotControlsStackedWidget->setCurrentIndex(5); } else if (index == TextEntry) { ui->slotControlsStackedWidget->setCurrentIndex(6); } else if (index == ExecuteSlot) { ui->slotControlsStackedWidget->setCurrentIndex(7); } } void AdvanceButtonDialog::changeSlotHelpText(int index) { if (index == KBMouseSlot) { ui->slotTypeHelpLabel->setText(tr("Insert a new blank slot.")); } else if (index == CycleSlot) { ui->slotTypeHelpLabel->setText(tr("Slots past a Cycle action will be executed " "on the next button press. Multiple cycles can be added " "in order to create partitions in a sequence.")); } else if (index == DelaySlot) { ui->slotTypeHelpLabel->setText(tr("Delays the time that the next slot is activated " "by the time specified. Slots activated before the " "delay will remain active after the delay time " "has passed.")); } else if (index == DistanceSlot) { ui->slotTypeHelpLabel->setText(tr("Distance action specifies that the slots afterwards " "will only be executed when an axis is moved " "a certain range past the designated dead zone.")); } else if (index == HoldSlot) { ui->slotTypeHelpLabel->setText(tr("Insert a hold action. Slots after the action will only be " "executed if the button is held past the interval specified.")); } else if (index == LoadSlot) { ui->slotTypeHelpLabel->setText(tr("Chose a profile to load when this slot is activated.")); } else if (index == MouseModSlot) { ui->slotTypeHelpLabel->setText(tr("Mouse mod action will modify all mouse speed settings " "by a specified percentage while the action is being processed. " "This can be useful for slowing down the mouse while " "sniping.")); } else if (index == PauseSlot) { ui->slotTypeHelpLabel->setText(tr("Insert a pause that occurs in between key presses.")); } else if (index == PressTimeSlot) { ui->slotTypeHelpLabel->setText(tr("Specify the time that keys past this slot should be " "held down.")); } else if (index == ReleaseSlot) { ui->slotTypeHelpLabel->setText(tr("Insert a release action. Slots after the action will only be " "executed after a button release if the button was held " "past the interval specified.")); } else if (index == SetChangeSlot) { ui->slotTypeHelpLabel->setText(tr("Change to selected set once slot is activated.")); } else if (index == TextEntry) { ui->slotTypeHelpLabel->setText(tr("Full string will be typed when a " "slot is activated.")); } else if (index == ExecuteSlot) { ui->slotTypeHelpLabel->setText(tr("Execute program when slot is activated.")); } } antimicro-2.23/src/advancebuttondialog.h000066400000000000000000000071631300750276700204200ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef ADVANCEBUTTONDIALOG_H #define ADVANCEBUTTONDIALOG_H #include #include #include "joybutton.h" #include "simplekeygrabberbutton.h" #include "uihelpers/advancebuttondialoghelper.h" namespace Ui { class AdvanceButtonDialog; } class AdvanceButtonDialog : public QDialog { Q_OBJECT public: explicit AdvanceButtonDialog(JoyButton *button, QWidget *parent=0); ~AdvanceButtonDialog(); private: Ui::AdvanceButtonDialog *ui; enum SlotTypeComboIndex { KBMouseSlot = 0, CycleSlot, DelaySlot, DistanceSlot, ExecuteSlot, HoldSlot, LoadSlot, MouseModSlot, PauseSlot, PressTimeSlot, ReleaseSlot, SetChangeSlot, TextEntry, }; protected: void connectButtonEvents(SimpleKeyGrabberButton *button); void appendBlankKeyGrabber(); int actionTimeConvert(); void changeTurboForSequences(); void fillTimeComboBoxes(); void refreshTimeComboBoxes(JoyButtonSlot *slot); void updateWindowTitleButtonName(); void populateAutoResetInterval(); void disconnectTimeBoxesEvents(); void connectTimeBoxesEvents(); void resetTimeBoxes(); void populateSetSelectionComboBox(); void populateSlotSetSelectionComboBox(); void findTurboModeComboIndex(); int oldRow; JoyButton *button; AdvanceButtonDialogHelper helper; static const int MINIMUMTURBO; signals: void toggleChanged(bool state); void turboChanged(bool state); void slotsChanged(); void turboButtonEnabledChange(bool state); public slots: void placeNewSlot(JoyButtonSlot *slot); void clearAllSlots(); private slots: void changeTurboText(int value); void updateTurboIntervalValue(int value); void checkTurboSetting(bool state); void updateSlotsScrollArea(int value); void deleteSlot(); void changeSelectedSlot(); void insertSlot(); void updateSelectedSlot(int value); void insertPauseSlot(); void insertHoldSlot(); void insertCycleSlot(); void insertDistanceSlot(); void insertReleaseSlot(); void insertMouseSpeedModSlot(); void insertKeyPressSlot(); void insertDelaySlot(); void insertSetChangeSlot(); void insertTextEntrySlot(); void insertExecuteSlot(); void updateActionTimeLabel(); void updateSetSelection(); void checkTurboIntervalValue(int value); void performStatsWidgetRefresh(QListWidgetItem *item); void checkSlotTimeUpdate(); void checkSlotMouseModUpdate(); void checkSlotDistanceUpdate(); void checkSlotSetChangeUpdate(); void checkCycleResetWidgetStatus(bool enabled); void setButtonCycleResetInterval(double value); void setButtonCycleReset(bool enabled); void setButtonTurboMode(int value); void showSelectProfileWindow(); void showFindExecutableWindow(bool); void changeSlotTypeDisplay(int index); void changeSlotHelpText(int index); }; #endif // ADVANCEBUTTONDIALOG_H antimicro-2.23/src/advancebuttondialog.ui000066400000000000000000001217301300750276700206030ustar00rootroot00000000000000 AdvanceButtonDialog Qt::NonModal 0 0 750 439 0 0 750 430 Advanced false 6 4 0 true 0 0 200 16777215 0 Assignments Toggle Turbo Set Selector 0 0 0 0 0 0 100 16777215 100 false QFrame::StyledPanel QFrame::Sunken 1 0 Qt::ScrollBarAlwaysOff QListView::LeftToRight 0 QListView::ListMode false Qt::Vertical QSizePolicy::Fixed 20 10 Qt::Horizontal QSizePolicy::Fixed 50 20 Blank or KB/M Cycle Delay Distance Execute Hold Load Mouse Mod Pause Press Time Release Set Change Text Entry Qt::Horizontal QSizePolicy::Fixed 50 20 Insert a new blank slot. Insert Delete a slot. Delete Clear all currently assigned slots. Clear All Qt::Vertical QSizePolicy::Fixed 20 20 Placeholder true 0 Qt::Vertical QSizePolicy::Fixed 20 20 40 0 0 75 true Specify the duration of an inserted Pause or Hold slot. Time: 50 false 0.01s 10 0m 0 0 0 0 11 0 0 0 0 0 0 0 0s 75 true &Mouse Speed Mod: mouseSpeedModSpinBox 81 0 Set the percentage that mouse speeds will be modified by. % 1 400 1 100 20 75 true Specify the range past an axis dead zone in which a sequence of actions will execute. Distance: distanceSpinBox 81 0 Specify the range past an axis dead zone in which a sequence of actions will execute. % 1 100 1 10 true 75 true Auto Reset Cycle After false 60.000000000000000 0.500000000000000 1.000000000000000 true 75 true seconds Choose Profile Executable: ... Arguments: Qt::Vertical QSizePolicy::Expanding 20 10 verticalSpacer_5 slotListWidget verticalSpacer_6 slotControlsStackedWidget slotTypeHelpLabel verticalSpacer_2 20 Enabled Qt::Vertical 20 302 0 0 Enabled 0 0 Mode: false <html><head/><body><p>Normal: Repeatedly press and release a button by the chosen rate.</p><p>Gradient: Modify the button press and button release delay based on how far an axis has been moved. The rate will remain the same.</p><p>Pulse: Modify how many times a button is pressed and released per second. The button delay will remain the same.</p></body></html> Normal Gradient Pulse Qt::Vertical QSizePolicy::Fixed 20 20 6 0 0 0 0 0 16777215 20 Delay: 0 0 0 0 16777215 20 0.10s false 0 0 0 400 10 10 true Qt::Horizontal false false QSlider::TicksBelow 10 Qt::Vertical QSizePolicy::Fixed 20 20 Rate: 10.0/s turboSlider verticalSpacer verticalSpacer_4 30 Enabled 0 30 Disabled Select Set 1 One Way Select Set 1 Two Way Select Set 1 While Held Select Set 2 One Way Select Set 2 Two Way Select Set 2 While Held Select Set 3 One Way Select Set 3 Two Way Select Set 3 While Held Select Set 4 One Way Select Set 4 Two Way Select Set 4 While Held Select Set 5 One Way Select Set 5 Two Way Select Set 5 While Held Select Set 6 One Way Select Set 6 Two Way Select Set 6 While Held Select Set 7 One Way Select Set 7 Two Way Select Set 7 While Held Select Set 8 One Way Select Set 8 Two Way Select Set 8 While Held Qt::Vertical 20 289 Qt::Horizontal Qt::Horizontal QDialogButtonBox::Close buttonBox line SlotItemListWidget QListWidget
slotitemlistwidget.h
buttonBox accepted() AdvanceButtonDialog accept() 222 406 157 274 buttonBox rejected() AdvanceButtonDialog reject() 290 412 286 274 listWidget currentRowChanged(int) stackedWidget setCurrentIndex(int) 119 90 573 14
antimicro-2.23/src/advancestickassignmentdialog.cpp000066400000000000000000001404431300750276700226450ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include "advancestickassignmentdialog.h" #include "ui_advancestickassignmentdialog.h" #include "joycontrolstick.h" AdvanceStickAssignmentDialog::AdvanceStickAssignmentDialog(Joystick *joystick, QWidget *parent) : QDialog(parent, Qt::Window), ui(new Ui::AdvanceStickAssignmentDialog) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); this->joystick = joystick; joystick->getActiveSetJoystick()->setIgnoreEventState(true); joystick->getActiveSetJoystick()->release(); joystick->resetButtonDownCount(); QString tempHeaderLabel = ui->joystickNumberLabel->text(); tempHeaderLabel = tempHeaderLabel.arg(joystick->getSDLName()).arg(joystick->getRealJoyNumber()); ui->joystickNumberLabel->setText(tempHeaderLabel); ui->joystickNumberLabel2->setText(tempHeaderLabel); tempHeaderLabel = ui->hatNumberLabel->text(); tempHeaderLabel = tempHeaderLabel.arg(joystick->getNumberHats()); ui->hatNumberLabel->setText(tempHeaderLabel); ui->xAxisOneComboBox->addItem("", QVariant(0)); ui->yAxisOneComboBox->addItem("", QVariant(0)); ui->xAxisTwoComboBox->addItem("", QVariant(0)); ui->yAxisTwoComboBox->addItem("", QVariant(0)); for (int i=0; i < joystick->getNumberAxes(); i++) { ui->xAxisOneComboBox->addItem(tr("Axis %1").arg(i+1), QVariant(i)); ui->yAxisOneComboBox->addItem(tr("Axis %1").arg(i+1), QVariant(i)); ui->xAxisTwoComboBox->addItem(tr("Axis %1").arg(i+1), QVariant(i)); ui->yAxisTwoComboBox->addItem(tr("Axis %1").arg(i+1), QVariant(i)); } refreshStickConfiguration(); populateDPadComboBoxes(); refreshVDPadConfiguration(); #ifndef USE_SDL_2 ui->versionTwoMessageLabel->setVisible(false); #endif connect(ui->enableOneCheckBox, SIGNAL(clicked(bool)), this, SLOT(changeStateStickOneWidgets(bool))); connect(ui->enableTwoCheckBox, SIGNAL(clicked(bool)), this, SLOT(changeStateStickTwoWidgets(bool))); connect(ui->vdpadEnableCheckBox, SIGNAL(clicked(bool)), this, SLOT(changeStateVDPadWidgets(bool))); connect(ui->xAxisOneComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkForAxisAssignmentStickOne())); connect(ui->yAxisOneComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkForAxisAssignmentStickOne())); connect(ui->xAxisTwoComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkForAxisAssignmentStickTwo())); connect(ui->yAxisTwoComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkForAxisAssignmentStickTwo())); connect(ui->quickAssignStick1PushButton, SIGNAL(clicked()), this, SLOT(openQuickAssignDialogStick1())); connect(ui->quickAssignStick2PushButton, SIGNAL(clicked()), this, SLOT(openQuickAssignDialogStick2())); enableVDPadComboBoxes(); connect(this, SIGNAL(stickConfigurationChanged()), this, SLOT(disableVDPadComboBoxes())); connect(this, SIGNAL(stickConfigurationChanged()), this, SLOT(populateDPadComboBoxes())); connect(this, SIGNAL(stickConfigurationChanged()), this, SLOT(refreshVDPadConfiguration())); connect(this, SIGNAL(stickConfigurationChanged()), this, SLOT(enableVDPadComboBoxes())); connect(ui->vdpadUpPushButton, SIGNAL(clicked()), this, SLOT(openAssignVDPadUp())); connect(ui->vdpadDownPushButton, SIGNAL(clicked()), this, SLOT(openAssignVDPadDown())); connect(ui->vdpadLeftPushButton, SIGNAL(clicked()), this, SLOT(openAssignVDPadLeft())); connect(ui->vdpadRightPushButton, SIGNAL(clicked()), this, SLOT(openAssignVDPadRight())); connect(this, SIGNAL(finished(int)), this, SLOT(reenableButtonEvents())); } AdvanceStickAssignmentDialog::~AdvanceStickAssignmentDialog() { delete ui; } void AdvanceStickAssignmentDialog::checkForAxisAssignmentStickOne() { if (ui->xAxisOneComboBox->currentIndex() > 0 && ui->yAxisOneComboBox->currentIndex() > 0) { if (ui->xAxisOneComboBox->currentIndex() != ui->yAxisOneComboBox->currentIndex()) { for (int i=0; i < joystick->NUMBER_JOYSETS; i++) { SetJoystick *currentset = joystick->getSetJoystick(i); JoyAxis *axis1 = currentset->getJoyAxis(ui->xAxisOneComboBox->currentIndex()-1); JoyAxis *axis2 = currentset->getJoyAxis(ui->yAxisOneComboBox->currentIndex()-1); if (axis1 && axis2) { JoyControlStick *controlstick = currentset->getJoyStick(0); if (controlstick) { controlstick->replaceAxes(axis1, axis2); } else { JoyControlStick *controlstick = new JoyControlStick(axis1, axis2, 0, i, currentset); currentset->addControlStick(0, controlstick); } } } refreshStickConfiguration(); emit stickConfigurationChanged(); } else { if (sender() == ui->xAxisOneComboBox) { ui->yAxisOneComboBox->setCurrentIndex(0); } else if (sender() == ui->yAxisOneComboBox) { ui->xAxisOneComboBox->setCurrentIndex(0); } } } } void AdvanceStickAssignmentDialog::checkForAxisAssignmentStickTwo() { if (ui->xAxisTwoComboBox->currentIndex() > 0 && ui->yAxisTwoComboBox->currentIndex() > 0) { if (ui->xAxisTwoComboBox->currentIndex() != ui->yAxisTwoComboBox->currentIndex()) { for (int i=0; i < joystick->NUMBER_JOYSETS; i++) { SetJoystick *currentset = joystick->getSetJoystick(i); JoyAxis *axis1 = currentset->getJoyAxis(ui->xAxisTwoComboBox->currentIndex()-1); JoyAxis *axis2 = currentset->getJoyAxis(ui->yAxisTwoComboBox->currentIndex()-1); if (axis1 && axis2) { JoyControlStick *controlstick = currentset->getJoyStick(1); if (controlstick) { controlstick->replaceXAxis(axis1); controlstick->replaceYAxis(axis2); } else { JoyControlStick *controlstick = new JoyControlStick(axis1, axis2, 1, i, currentset); currentset->addControlStick(1, controlstick); } } } refreshStickConfiguration(); emit stickConfigurationChanged(); } else { if (sender() == ui->xAxisTwoComboBox) { ui->yAxisTwoComboBox->setCurrentIndex(0); } else if (sender() == ui->yAxisTwoComboBox) { ui->xAxisTwoComboBox->setCurrentIndex(0); } } } } void AdvanceStickAssignmentDialog::changeStateVDPadWidgets(bool enabled) { if (enabled) { ui->vdpadUpComboBox->setEnabled(true); ui->vdpadDownComboBox->setEnabled(true); ui->vdpadLeftComboBox->setEnabled(true); ui->vdpadRightComboBox->setEnabled(true); ui->vdpadUpPushButton->setEnabled(true); ui->vdpadDownPushButton->setEnabled(true); ui->vdpadLeftPushButton->setEnabled(true); ui->vdpadRightPushButton->setEnabled(true); for (int i=0; i < joystick->NUMBER_JOYSETS; i++) { SetJoystick *currentset = joystick->getSetJoystick(i); if (!currentset->getVDPad(0)) { VDPad *vdpad = new VDPad(0, i, currentset, currentset); currentset->addVDPad(0, vdpad); } } } else { ui->vdpadUpComboBox->setEnabled(false); ui->vdpadDownComboBox->setEnabled(false); ui->vdpadLeftComboBox->setEnabled(false); ui->vdpadRightComboBox->setEnabled(false); ui->vdpadUpPushButton->setEnabled(false); ui->vdpadDownPushButton->setEnabled(false); ui->vdpadLeftPushButton->setEnabled(false); ui->vdpadRightPushButton->setEnabled(false); for (int i=0; i < joystick->NUMBER_JOYSETS; i++) { SetJoystick *currentset = joystick->getSetJoystick(i); if (currentset->getVDPad(0)) { currentset->removeVDPad(0); } } } } void AdvanceStickAssignmentDialog::changeStateStickOneWidgets(bool enabled) { if (enabled) { ui->xAxisOneComboBox->setEnabled(true); ui->yAxisOneComboBox->setEnabled(true); ui->enableTwoCheckBox->setEnabled(true); ui->quickAssignStick1PushButton->setEnabled(true); } else { ui->xAxisOneComboBox->setEnabled(false); ui->xAxisOneComboBox->setCurrentIndex(0); ui->yAxisOneComboBox->setEnabled(false); ui->yAxisOneComboBox->setCurrentIndex(0); ui->xAxisTwoComboBox->setEnabled(false); ui->yAxisTwoComboBox->setEnabled(false); ui->xAxisTwoComboBox->setCurrentIndex(0); ui->yAxisTwoComboBox->setCurrentIndex(0); ui->enableTwoCheckBox->setEnabled(false); ui->enableTwoCheckBox->setChecked(false); ui->quickAssignStick1PushButton->setEnabled(false); JoyControlStick *controlstick = joystick->getActiveSetJoystick()->getJoyStick(0); JoyControlStick *controlstick2 = joystick->getActiveSetJoystick()->getJoyStick(1); if (controlstick2) { joystick->removeControlStick(1); } if (controlstick) { joystick->removeControlStick(0); } } } void AdvanceStickAssignmentDialog::changeStateStickTwoWidgets(bool enabled) { if (enabled) { ui->xAxisTwoComboBox->setEnabled(true); ui->yAxisTwoComboBox->setEnabled(true); ui->quickAssignStick2PushButton->setEnabled(true); } else { ui->xAxisTwoComboBox->setEnabled(false); ui->xAxisTwoComboBox->setCurrentIndex(0); ui->yAxisTwoComboBox->setEnabled(false); ui->yAxisTwoComboBox->setCurrentIndex(0); ui->quickAssignStick2PushButton->setEnabled(false); JoyControlStick *controlstick = joystick->getActiveSetJoystick()->getJoyStick(1); if (controlstick) { for (int i=0; i < joystick->NUMBER_JOYSETS; i++) { SetJoystick *currentset = joystick->getSetJoystick(i); currentset->removeControlStick(1); } } } } void AdvanceStickAssignmentDialog::refreshStickConfiguration() { JoyControlStick *stick1 = joystick->getActiveSetJoystick()->getJoyStick(0); JoyControlStick *stick2 = joystick->getActiveSetJoystick()->getJoyStick(1); if (stick1) { JoyAxis *axisX = stick1->getAxisX(); JoyAxis *axisY = stick1->getAxisY(); if (axisX && axisY) { ui->xAxisOneComboBox->setCurrentIndex(axisX->getRealJoyIndex()); ui->yAxisOneComboBox->setCurrentIndex(axisY->getRealJoyIndex()); ui->xAxisOneComboBox->setEnabled(true); ui->yAxisOneComboBox->setEnabled(true); ui->enableOneCheckBox->setEnabled(true); ui->enableOneCheckBox->setChecked(true); ui->enableTwoCheckBox->setEnabled(true); ui->quickAssignStick1PushButton->setEnabled(true); } } else { ui->xAxisOneComboBox->setCurrentIndex(0); ui->xAxisOneComboBox->setEnabled(false); ui->yAxisOneComboBox->setCurrentIndex(0); ui->yAxisOneComboBox->setEnabled(false); ui->enableOneCheckBox->setChecked(false); ui->enableTwoCheckBox->setEnabled(false); ui->quickAssignStick1PushButton->setEnabled(false); } if (stick2) { JoyAxis *axisX = stick2->getAxisX(); JoyAxis *axisY = stick2->getAxisY(); if (axisX && axisY) { ui->xAxisTwoComboBox->setCurrentIndex(axisX->getRealJoyIndex()); ui->yAxisTwoComboBox->setCurrentIndex(axisY->getRealJoyIndex()); ui->xAxisTwoComboBox->setEnabled(true); ui->yAxisTwoComboBox->setEnabled(true); ui->enableTwoCheckBox->setEnabled(true); ui->enableTwoCheckBox->setChecked(true); ui->quickAssignStick2PushButton->setEnabled(true); } } else { ui->xAxisTwoComboBox->setCurrentIndex(0); ui->xAxisTwoComboBox->setEnabled(false); ui->yAxisTwoComboBox->setCurrentIndex(0); ui->yAxisTwoComboBox->setEnabled(false); ui->enableTwoCheckBox->setChecked(false); ui->quickAssignStick2PushButton->setEnabled(false); } } void AdvanceStickAssignmentDialog::refreshVDPadConfiguration() { VDPad *vdpad = joystick->getActiveSetJoystick()->getVDPad(0); if (vdpad) { ui->vdpadEnableCheckBox->setChecked(true); ui->vdpadUpComboBox->setEnabled(true); ui->vdpadDownComboBox->setEnabled(true); ui->vdpadLeftComboBox->setEnabled(true); ui->vdpadRightComboBox->setEnabled(true); ui->vdpadUpPushButton->setEnabled(true); ui->vdpadDownPushButton->setEnabled(true); ui->vdpadLeftPushButton->setEnabled(true); ui->vdpadRightPushButton->setEnabled(true); JoyButton *upButton = vdpad->getVButton(JoyDPadButton::DpadUp); if (upButton) { int buttonindex = 0; if (typeid(*upButton) == typeid(JoyAxisButton)) { JoyAxisButton *axisbutton = static_cast(upButton); JoyAxis *axis = axisbutton->getAxis(); QList templist; templist.append(QVariant(axis->getRealJoyIndex())); templist.append(QVariant(axisbutton->getJoyNumber())); buttonindex = ui->vdpadUpComboBox->findData(templist); } else { QList templist; templist.append(QVariant(0)); templist.append(QVariant(upButton->getRealJoyNumber())); buttonindex = ui->vdpadUpComboBox->findData(templist); } if (buttonindex == -1) { vdpad->removeVButton(upButton); } else { ui->vdpadUpComboBox->setCurrentIndex(buttonindex); } } JoyButton *downButton = vdpad->getVButton(JoyDPadButton::DpadDown); if (downButton) { int buttonindex = 0; if (typeid(*downButton) == typeid(JoyAxisButton)) { JoyAxisButton *axisbutton = static_cast(downButton); JoyAxis *axis = axisbutton->getAxis(); QList templist; templist.append(QVariant(axis->getRealJoyIndex())); templist.append(QVariant(axisbutton->getJoyNumber())); buttonindex = ui->vdpadDownComboBox->findData(templist); } else { QList templist; templist.append(QVariant(0)); templist.append(QVariant(downButton->getRealJoyNumber())); buttonindex = ui->vdpadDownComboBox->findData(templist); } if (buttonindex == -1) { vdpad->removeVButton(downButton); } else { ui->vdpadDownComboBox->setCurrentIndex(buttonindex); } } JoyButton *leftButton = vdpad->getVButton(JoyDPadButton::DpadLeft); if (leftButton) { int buttonindex = 0; if (typeid(*leftButton) == typeid(JoyAxisButton)) { JoyAxisButton *axisbutton = static_cast(leftButton); JoyAxis *axis = axisbutton->getAxis(); QList templist; templist.append(QVariant(axis->getRealJoyIndex())); templist.append(QVariant(axisbutton->getJoyNumber())); buttonindex = ui->vdpadLeftComboBox->findData(templist); } else { QList templist; templist.append(QVariant(0)); templist.append(QVariant(leftButton->getRealJoyNumber())); buttonindex = ui->vdpadLeftComboBox->findData(templist); } if (buttonindex == -1) { vdpad->removeVButton(leftButton); } else { ui->vdpadLeftComboBox->setCurrentIndex(buttonindex); } } JoyButton *rightButton = vdpad->getVButton(JoyDPadButton::DpadRight); if (rightButton) { int buttonindex = 0; if (typeid(*rightButton) == typeid(JoyAxisButton)) { JoyAxisButton *axisbutton = static_cast(rightButton); JoyAxis *axis = axisbutton->getAxis(); QList templist; templist.append(QVariant(axis->getRealJoyIndex())); templist.append(QVariant(axisbutton->getJoyNumber())); buttonindex = ui->vdpadRightComboBox->findData(templist); } else { QList templist; templist.append(QVariant(0)); templist.append(QVariant(rightButton->getRealJoyNumber())); buttonindex = ui->vdpadRightComboBox->findData(templist); } if (buttonindex == -1) { vdpad->removeVButton(rightButton); } else { ui->vdpadRightComboBox->setCurrentIndex(buttonindex); } } } else { ui->vdpadEnableCheckBox->setChecked(false); ui->vdpadUpComboBox->setCurrentIndex(0); ui->vdpadUpComboBox->setEnabled(false); ui->vdpadDownComboBox->setCurrentIndex(0); ui->vdpadDownComboBox->setEnabled(false); ui->vdpadLeftComboBox->setCurrentIndex(0); ui->vdpadLeftComboBox->setEnabled(false); ui->vdpadRightComboBox->setCurrentIndex(0); ui->vdpadRightComboBox->setEnabled(false); ui->vdpadUpPushButton->setEnabled(false); ui->vdpadDownPushButton->setEnabled(false); ui->vdpadLeftPushButton->setEnabled(false); ui->vdpadRightPushButton->setEnabled(false); } } void AdvanceStickAssignmentDialog::populateDPadComboBoxes() { ui->vdpadUpComboBox->clear(); ui->vdpadDownComboBox->clear(); ui->vdpadLeftComboBox->clear(); ui->vdpadRightComboBox->clear(); ui->vdpadUpComboBox->addItem("", QVariant(0)); ui->vdpadDownComboBox->addItem("", QVariant(0)); ui->vdpadLeftComboBox->addItem("", QVariant(0)); ui->vdpadRightComboBox->addItem("", QVariant(0)); for (int i = 0; i < joystick->getNumberAxes(); i++) { JoyAxis *axis = joystick->getActiveSetJoystick()->getJoyAxis(i); if (!axis->isPartControlStick()) { QList templist; templist.append(QVariant(i+1)); templist.append(QVariant(0)); ui->vdpadUpComboBox->addItem(tr("Axis %1 -").arg(QString::number(i+1)), templist); ui->vdpadDownComboBox->addItem(tr("Axis %1 -").arg(QString::number(i+1)), templist); ui->vdpadLeftComboBox->addItem(tr("Axis %1 -").arg(QString::number(i+1)), templist); ui->vdpadRightComboBox->addItem(tr("Axis %1 -").arg(QString::number(i+1)), templist); templist.clear(); templist.append(QVariant(i+1)); templist.append(QVariant(1)); ui->vdpadUpComboBox->addItem(tr("Axis %1 +").arg(QString::number(i+1)), templist); ui->vdpadDownComboBox->addItem(tr("Axis %1 +").arg(QString::number(i+1)), templist); ui->vdpadLeftComboBox->addItem(tr("Axis %1 +").arg(QString::number(i+1)), templist); ui->vdpadRightComboBox->addItem(tr("Axis %1 +").arg(QString::number(i+1)), templist); } } for (int i = 0; i < joystick->getNumberButtons(); i++) { QList templist; templist.append(QVariant(0)); templist.append(QVariant(i+1)); ui->vdpadUpComboBox->addItem(tr("Button %1").arg(QString::number(i+1)), templist); ui->vdpadDownComboBox->addItem(tr("Button %1").arg(QString::number(i+1)), templist); ui->vdpadLeftComboBox->addItem(tr("Button %1").arg(QString::number(i+1)), templist); ui->vdpadRightComboBox->addItem(tr("Button %1").arg(QString::number(i+1)), templist); } } void AdvanceStickAssignmentDialog::changeVDPadUpButton(int index) { if (index > 0) { if (ui->vdpadDownComboBox->currentIndex() == index) { ui->vdpadDownComboBox->setCurrentIndex(0); } else if (ui->vdpadLeftComboBox->currentIndex() == index) { ui->vdpadLeftComboBox->setCurrentIndex(0); } else if (ui->vdpadRightComboBox->currentIndex() == index) { ui->vdpadRightComboBox->setCurrentIndex(0); } QVariant temp = ui->vdpadUpComboBox->itemData(index); QList templist = temp.toList(); if (templist.size() == 2) { int axis = templist.at(0).toInt(); int button = templist.at(1).toInt(); if (axis > 0 && button >= 0) { for (int i=0; i < joystick->NUMBER_JOYSETS; i++) { SetJoystick *currentset = joystick->getSetJoystick(i); VDPad *vdpad = currentset->getVDPad(0); JoyAxis *currentaxis = currentset->getJoyAxis(axis-1); JoyButton *currentbutton = 0; if (button == 0) { currentbutton = currentaxis->getNAxisButton(); } else if (button == 1) { currentbutton = currentaxis->getPAxisButton(); } vdpad->addVButton(JoyDPadButton::DpadUp, currentbutton); } } else if (button > 0) { for (int i=0; i < joystick->NUMBER_JOYSETS; i++) { SetJoystick *currentset = joystick->getSetJoystick(i); VDPad *vdpad = currentset->getVDPad(0); JoyButton *currentbutton = currentset->getJoyButton(button-1); if (currentbutton) { vdpad->addVButton(JoyDPadButton::DpadUp, currentbutton); } } } } } else { for (int i=0; i < joystick->NUMBER_JOYSETS; i++) { SetJoystick *currentset = joystick->getSetJoystick(i); VDPad *vdpad = currentset->getVDPad(0); if (vdpad && vdpad->getVButton(JoyDPadButton::DpadUp)) { vdpad->removeVButton(JoyDPadButton::DpadUp); } } } } void AdvanceStickAssignmentDialog::changeVDPadDownButton(int index) { if (index > 0) { if (ui->vdpadUpComboBox->currentIndex() == index) { ui->vdpadUpComboBox->setCurrentIndex(0); } else if (ui->vdpadLeftComboBox->currentIndex() == index) { ui->vdpadLeftComboBox->setCurrentIndex(0); } else if (ui->vdpadRightComboBox->currentIndex() == index) { ui->vdpadRightComboBox->setCurrentIndex(0); } QVariant temp = ui->vdpadDownComboBox->itemData(index); QList templist = temp.toList(); if (templist.size() == 2) { int axis = templist.at(0).toInt(); int button = templist.at(1).toInt(); if (axis > 0 && button >= 0) { for (int i=0; i < joystick->NUMBER_JOYSETS; i++) { SetJoystick *currentset = joystick->getSetJoystick(i); VDPad *vdpad = currentset->getVDPad(0); JoyAxis *currentaxis = currentset->getJoyAxis(axis-1); JoyButton *currentbutton = 0; if (button == 0) { currentbutton = currentaxis->getNAxisButton(); } else if (button == 1) { currentbutton = currentaxis->getPAxisButton(); } vdpad->addVButton(JoyDPadButton::DpadDown, currentbutton); } } else if (button > 0) { for (int i=0; i < joystick->NUMBER_JOYSETS; i++) { SetJoystick *currentset = joystick->getSetJoystick(i); VDPad *vdpad = currentset->getVDPad(0); JoyButton *currentbutton = currentset->getJoyButton(button-1); if (currentbutton) { vdpad->addVButton(JoyDPadButton::DpadDown, currentbutton); } } } } } else { for (int i=0; i < joystick->NUMBER_JOYSETS; i++) { SetJoystick *currentset = joystick->getSetJoystick(i); VDPad *vdpad = currentset->getVDPad(0); if (vdpad && vdpad->getVButton(JoyDPadButton::DpadDown)) { vdpad->removeVButton(JoyDPadButton::DpadDown); } } } } void AdvanceStickAssignmentDialog::changeVDPadLeftButton(int index) { if (index > 0) { if (ui->vdpadUpComboBox->currentIndex() == index) { ui->vdpadUpComboBox->setCurrentIndex(0); } else if (ui->vdpadDownComboBox->currentIndex() == index) { ui->vdpadDownComboBox->setCurrentIndex(0); } else if (ui->vdpadRightComboBox->currentIndex() == index) { ui->vdpadRightComboBox->setCurrentIndex(0); } QVariant temp = ui->vdpadLeftComboBox->itemData(index); QList templist = temp.toList(); if (templist.size() == 2) { int axis = templist.at(0).toInt(); int button = templist.at(1).toInt(); if (axis > 0 && button >= 0) { for (int i=0; i < joystick->NUMBER_JOYSETS; i++) { SetJoystick *currentset = joystick->getSetJoystick(i); VDPad *vdpad = currentset->getVDPad(0); JoyAxis *currentaxis = currentset->getJoyAxis(axis-1); JoyButton *currentbutton = 0; if (button == 0) { currentbutton = currentaxis->getNAxisButton(); } else if (button == 1) { currentbutton = currentaxis->getPAxisButton(); } vdpad->addVButton(JoyDPadButton::DpadLeft, currentbutton); } } else if (button > 0) { for (int i=0; i < joystick->NUMBER_JOYSETS; i++) { SetJoystick *currentset = joystick->getSetJoystick(i); VDPad *vdpad = currentset->getVDPad(0); JoyButton *currentbutton = currentset->getJoyButton(button-1); if (currentbutton) { vdpad->addVButton(JoyDPadButton::DpadLeft, currentbutton); } } } } } else { for (int i=0; i < joystick->NUMBER_JOYSETS; i++) { SetJoystick *currentset = joystick->getSetJoystick(i); VDPad *vdpad = currentset->getVDPad(0); if (vdpad && vdpad->getVButton(JoyDPadButton::DpadLeft)) { vdpad->removeVButton(JoyDPadButton::DpadLeft); } } } } void AdvanceStickAssignmentDialog::changeVDPadRightButton(int index) { if (index > 0) { if (ui->vdpadUpComboBox->currentIndex() == index) { ui->vdpadUpComboBox->setCurrentIndex(0); } else if (ui->vdpadDownComboBox->currentIndex() == index) { ui->vdpadDownComboBox->setCurrentIndex(0); } else if (ui->vdpadLeftComboBox->currentIndex() == index) { ui->vdpadLeftComboBox->setCurrentIndex(0); } QVariant temp = ui->vdpadRightComboBox->itemData(index); QList templist = temp.toList(); if (templist.size() == 2) { int axis = templist.at(0).toInt(); int button = templist.at(1).toInt(); if (axis > 0 && button >= 0) { for (int i=0; i < joystick->NUMBER_JOYSETS; i++) { SetJoystick *currentset = joystick->getSetJoystick(i); VDPad *vdpad = currentset->getVDPad(0); JoyAxis *currentaxis = currentset->getJoyAxis(axis-1); JoyButton *currentbutton = 0; if (button == 0) { currentbutton = currentaxis->getNAxisButton(); } else if (button == 1) { currentbutton = currentaxis->getPAxisButton(); } vdpad->addVButton(JoyDPadButton::DpadRight, currentbutton); } } else if (button > 0) { for (int i=0; i < joystick->NUMBER_JOYSETS; i++) { SetJoystick *currentset = joystick->getSetJoystick(i); VDPad *vdpad = currentset->getVDPad(0); JoyButton *currentbutton = currentset->getJoyButton(button-1); if (currentbutton) { vdpad->addVButton(JoyDPadButton::DpadRight, currentbutton); } } } } } else { for (int i=0; i < joystick->NUMBER_JOYSETS; i++) { SetJoystick *currentset = joystick->getSetJoystick(i); VDPad *vdpad = currentset->getVDPad(0); if (vdpad && vdpad->getVButton(JoyDPadButton::DpadRight)) { vdpad->removeVButton(JoyDPadButton::DpadRight); } } } } void AdvanceStickAssignmentDialog::enableVDPadComboBoxes() { connect(ui->vdpadUpComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeVDPadUpButton(int))); connect(ui->vdpadDownComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeVDPadDownButton(int))); connect(ui->vdpadLeftComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeVDPadLeftButton(int))); connect(ui->vdpadRightComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeVDPadRightButton(int))); } void AdvanceStickAssignmentDialog::disableVDPadComboBoxes() { disconnect(ui->vdpadUpComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeVDPadUpButton(int))); disconnect(ui->vdpadDownComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeVDPadDownButton(int))); disconnect(ui->vdpadLeftComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeVDPadLeftButton(int))); disconnect(ui->vdpadRightComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeVDPadRightButton(int))); } void AdvanceStickAssignmentDialog::openQuickAssignDialogStick1() { QMessageBox msgBox; msgBox.setText(tr("Move stick 1 along the X axis")); msgBox.setStandardButtons(QMessageBox::Close); for (int i=0; i < joystick->getNumberAxes(); i++) { JoyAxis *axis = joystick->getActiveSetJoystick()->getJoyAxis(i); if (axis) { connect(axis, SIGNAL(active(int)), &msgBox, SLOT(close())); connect(axis, SIGNAL(active(int)), this, SLOT(quickAssignStick1Axis1())); } } msgBox.exec(); msgBox.setText(tr("Move stick 1 along the Y axis")); for (int i=0; i < joystick->getNumberAxes(); i++) { JoyAxis *axis = joystick->getActiveSetJoystick()->getJoyAxis(i); if (axis) { disconnect(axis, SIGNAL(active(int)), &msgBox, SLOT(close())); disconnect(axis, SIGNAL(active(int)), this, SLOT(quickAssignStick1Axis1())); connect(axis, SIGNAL(active(int)), &msgBox, SLOT(close())); connect(axis, SIGNAL(active(int)), this, SLOT(quickAssignStick1Axis2())); } } msgBox.exec(); for (int i=0; i < joystick->getNumberAxes(); i++) { JoyAxis *axis = joystick->getActiveSetJoystick()->getJoyAxis(i); if (axis) { disconnect(axis, SIGNAL(active(int)), &msgBox, SLOT(close())); disconnect(axis, SIGNAL(active(int)), this, SLOT(quickAssignStick1Axis2())); } } } void AdvanceStickAssignmentDialog::openQuickAssignDialogStick2() { QMessageBox msgBox; msgBox.setText(tr("Move stick 2 along the X axis")); msgBox.setStandardButtons(QMessageBox::Close); for (int i=0; i < joystick->getNumberAxes(); i++) { JoyAxis *axis = joystick->getActiveSetJoystick()->getJoyAxis(i); if (axis) { connect(axis, SIGNAL(active(int)), &msgBox, SLOT(close())); connect(axis, SIGNAL(active(int)), this, SLOT(quickAssignStick2Axis1())); } } msgBox.exec(); msgBox.setText(tr("Move stick 2 along the Y axis")); for (int i=0; i < joystick->getNumberAxes(); i++) { JoyAxis *axis = joystick->getActiveSetJoystick()->getJoyAxis(i); if (axis) { disconnect(axis, SIGNAL(active(int)), &msgBox, SLOT(close())); disconnect(axis, SIGNAL(active(int)), this, SLOT(quickAssignStick2Axis1())); connect(axis, SIGNAL(active(int)), &msgBox, SLOT(close())); connect(axis, SIGNAL(active(int)), this, SLOT(quickAssignStick2Axis2())); } } msgBox.exec(); for (int i=0; i < joystick->getNumberAxes(); i++) { JoyAxis *axis = joystick->getActiveSetJoystick()->getJoyAxis(i); if (axis) { disconnect(axis, SIGNAL(active(int)), &msgBox, SLOT(close())); disconnect(axis, SIGNAL(active(int)), this, SLOT(quickAssignStick2Axis2())); } } } void AdvanceStickAssignmentDialog::quickAssignStick1Axis1() { JoyAxis *axis = static_cast(sender()); ui->xAxisOneComboBox->setCurrentIndex(axis->getRealJoyIndex()); } void AdvanceStickAssignmentDialog::quickAssignStick1Axis2() { JoyAxis *axis = static_cast(sender()); ui->yAxisOneComboBox->setCurrentIndex(axis->getRealJoyIndex()); } void AdvanceStickAssignmentDialog::quickAssignStick2Axis1() { JoyAxis *axis = static_cast(sender()); ui->xAxisTwoComboBox->setCurrentIndex(axis->getRealJoyIndex()); } void AdvanceStickAssignmentDialog::quickAssignStick2Axis2() { JoyAxis *axis = static_cast(sender()); ui->yAxisTwoComboBox->setCurrentIndex(axis->getRealJoyIndex()); } void AdvanceStickAssignmentDialog::reenableButtonEvents() { joystick->getActiveSetJoystick()->setIgnoreEventState(false); joystick->getActiveSetJoystick()->release(); } void AdvanceStickAssignmentDialog::openAssignVDPadUp() { QMessageBox msgBox; msgBox.setText(tr("Press a button or move an axis")); msgBox.setStandardButtons(QMessageBox::Close); for (int i=0; i < joystick->getNumberAxes(); i++) { JoyAxis *axis = joystick->getActiveSetJoystick()->getJoyAxis(i); if (axis && !axis->isPartControlStick()) { connect(axis->getNAxisButton(), SIGNAL(clicked(int)), &msgBox, SLOT(close())); connect(axis->getNAxisButton(), SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadUp())); connect(axis->getPAxisButton(), SIGNAL(clicked(int)), &msgBox, SLOT(close())); connect(axis->getPAxisButton(), SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadUp())); } } for (int i=0; i < joystick->getNumberButtons(); i++) { JoyButton *button = joystick->getActiveSetJoystick()->getJoyButton(i); if (button) { connect(button, SIGNAL(clicked(int)), &msgBox, SLOT(close())); connect(button, SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadUp())); } } msgBox.exec(); for (int i=0; i < joystick->getNumberAxes(); i++) { JoyAxis *axis = joystick->getActiveSetJoystick()->getJoyAxis(i); if (axis && !axis->isPartControlStick()) { disconnect(axis->getNAxisButton(), SIGNAL(clicked(int)), &msgBox, SLOT(close())); disconnect(axis->getNAxisButton(), SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadUp())); disconnect(axis->getPAxisButton(), SIGNAL(clicked(int)), &msgBox, SLOT(close())); disconnect(axis->getPAxisButton(), SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadUp())); } } for (int i=0; i < joystick->getNumberButtons(); i++) { JoyButton *button = joystick->getActiveSetJoystick()->getJoyButton(i); if (button) { disconnect(button, SIGNAL(clicked(int)), &msgBox, SLOT(close())); disconnect(button, SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadUp())); } } } void AdvanceStickAssignmentDialog::openAssignVDPadDown() { QMessageBox msgBox; msgBox.setText(tr("Press a button or move an axis")); msgBox.setStandardButtons(QMessageBox::Close); for (int i=0; i < joystick->getNumberAxes(); i++) { JoyAxis *axis = joystick->getActiveSetJoystick()->getJoyAxis(i); if (axis && !axis->isPartControlStick()) { connect(axis->getNAxisButton(), SIGNAL(clicked(int)), &msgBox, SLOT(close())); connect(axis->getNAxisButton(), SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadDown())); connect(axis->getPAxisButton(), SIGNAL(clicked(int)), &msgBox, SLOT(close())); connect(axis->getPAxisButton(), SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadDown())); } } for (int i=0; i < joystick->getNumberButtons(); i++) { JoyButton *button = joystick->getActiveSetJoystick()->getJoyButton(i); if (button) { connect(button, SIGNAL(clicked(int)), &msgBox, SLOT(close())); connect(button, SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadDown())); } } msgBox.exec(); for (int i=0; i < joystick->getNumberAxes(); i++) { JoyAxis *axis = joystick->getActiveSetJoystick()->getJoyAxis(i); if (axis && !axis->isPartControlStick()) { disconnect(axis->getNAxisButton(), SIGNAL(clicked(int)), &msgBox, SLOT(close())); disconnect(axis->getNAxisButton(), SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadDown())); disconnect(axis->getPAxisButton(), SIGNAL(clicked(int)), &msgBox, SLOT(close())); disconnect(axis->getPAxisButton(), SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadDown())); } } for (int i=0; i < joystick->getNumberButtons(); i++) { JoyButton *button = joystick->getActiveSetJoystick()->getJoyButton(i); if (button) { disconnect(button, SIGNAL(clicked(int)), &msgBox, SLOT(close())); disconnect(button, SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadDown())); } } } void AdvanceStickAssignmentDialog::openAssignVDPadLeft() { QMessageBox msgBox; msgBox.setText(tr("Press a button or move an axis")); msgBox.setStandardButtons(QMessageBox::Close); for (int i=0; i < joystick->getNumberAxes(); i++) { JoyAxis *axis = joystick->getActiveSetJoystick()->getJoyAxis(i); if (axis && !axis->isPartControlStick()) { connect(axis->getNAxisButton(), SIGNAL(clicked(int)), &msgBox, SLOT(close())); connect(axis->getNAxisButton(), SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadLeft())); connect(axis->getPAxisButton(), SIGNAL(clicked(int)), &msgBox, SLOT(close())); connect(axis->getPAxisButton(), SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadLeft())); } } for (int i=0; i < joystick->getNumberButtons(); i++) { JoyButton *button = joystick->getActiveSetJoystick()->getJoyButton(i); if (button) { connect(button, SIGNAL(clicked(int)), &msgBox, SLOT(close())); connect(button, SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadLeft())); } } msgBox.exec(); for (int i=0; i < joystick->getNumberAxes(); i++) { JoyAxis *axis = joystick->getActiveSetJoystick()->getJoyAxis(i); if (axis && !axis->isPartControlStick()) { disconnect(axis->getNAxisButton(), SIGNAL(clicked(int)), &msgBox, SLOT(close())); disconnect(axis->getNAxisButton(), SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadLeft())); disconnect(axis->getPAxisButton(), SIGNAL(clicked(int)), &msgBox, SLOT(close())); disconnect(axis->getPAxisButton(), SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadLeft())); } } for (int i=0; i < joystick->getNumberButtons(); i++) { JoyButton *button = joystick->getActiveSetJoystick()->getJoyButton(i); if (button) { disconnect(button, SIGNAL(clicked(int)), &msgBox, SLOT(close())); disconnect(button, SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadLeft())); } } } void AdvanceStickAssignmentDialog::openAssignVDPadRight() { QMessageBox msgBox; msgBox.setText(tr("Press a button or move an axis")); msgBox.setStandardButtons(QMessageBox::Close); for (int i=0; i < joystick->getNumberAxes(); i++) { JoyAxis *axis = joystick->getActiveSetJoystick()->getJoyAxis(i); if (axis && !axis->isPartControlStick()) { connect(axis->getNAxisButton(), SIGNAL(clicked(int)), &msgBox, SLOT(close())); connect(axis->getNAxisButton(), SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadRight())); connect(axis->getPAxisButton(), SIGNAL(clicked(int)), &msgBox, SLOT(close())); connect(axis->getPAxisButton(), SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadRight())); } } for (int i=0; i < joystick->getNumberButtons(); i++) { JoyButton *button = joystick->getActiveSetJoystick()->getJoyButton(i); if (button) { connect(button, SIGNAL(clicked(int)), &msgBox, SLOT(close())); connect(button, SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadRight())); } } msgBox.exec(); for (int i=0; i < joystick->getNumberAxes(); i++) { JoyAxis *axis = joystick->getActiveSetJoystick()->getJoyAxis(i); if (axis && !axis->isPartControlStick()) { disconnect(axis->getNAxisButton(), SIGNAL(clicked(int)), &msgBox, SLOT(close())); disconnect(axis->getNAxisButton(), SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadRight())); disconnect(axis->getPAxisButton(), SIGNAL(clicked(int)), &msgBox, SLOT(close())); disconnect(axis->getPAxisButton(), SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadRight())); } } for (int i=0; i < joystick->getNumberButtons(); i++) { JoyButton *button = joystick->getActiveSetJoystick()->getJoyButton(i); if (button) { disconnect(button, SIGNAL(clicked(int)), &msgBox, SLOT(close())); disconnect(button, SIGNAL(clicked(int)), this, SLOT(quickAssignVDPadRight())); } } } void AdvanceStickAssignmentDialog::quickAssignVDPadUp() { if (qobject_cast(sender()) != 0) { JoyAxisButton *axisButton = static_cast(sender()); QList templist; templist.append(QVariant(axisButton->getAxis()->getRealJoyIndex())); if (axisButton->getAxis()->getNAxisButton() == axisButton) { templist.append(QVariant(0)); } else { templist.append(QVariant(1)); } int index = ui->vdpadUpComboBox->findData(templist); if (index > 0) { ui->vdpadUpComboBox->setCurrentIndex(index); } } else { JoyButton *button = static_cast(sender()); QList templist; templist.append(QVariant(0)); templist.append(QVariant(button->getJoyNumber()+1)); int index = ui->vdpadUpComboBox->findData(templist); if (index > 0) { ui->vdpadUpComboBox->setCurrentIndex(index); } } } void AdvanceStickAssignmentDialog::quickAssignVDPadDown() { if (qobject_cast(sender()) != 0) { JoyAxisButton *axisButton = static_cast(sender()); QList templist; templist.append(QVariant(axisButton->getAxis()->getRealJoyIndex())); if (axisButton->getAxis()->getNAxisButton() == axisButton) { templist.append(QVariant(0)); } else { templist.append(QVariant(1)); } int index = ui->vdpadDownComboBox->findData(templist); if (index > 0) { ui->vdpadDownComboBox->setCurrentIndex(index); } } else { JoyButton *button = static_cast(sender()); QList templist; templist.append(QVariant(0)); templist.append(QVariant(button->getJoyNumber()+1)); int index = ui->vdpadDownComboBox->findData(templist); if (index > 0) { ui->vdpadDownComboBox->setCurrentIndex(index); } } } void AdvanceStickAssignmentDialog::quickAssignVDPadLeft() { if (qobject_cast(sender()) != 0) { JoyAxisButton *axisButton = static_cast(sender()); QList templist; templist.append(QVariant(axisButton->getAxis()->getRealJoyIndex())); if (axisButton->getAxis()->getNAxisButton() == axisButton) { templist.append(QVariant(0)); } else { templist.append(QVariant(1)); } int index = ui->vdpadLeftComboBox->findData(templist); if (index > 0) { ui->vdpadLeftComboBox->setCurrentIndex(index); } } else { JoyButton *button = static_cast(sender()); QList templist; templist.append(QVariant(0)); templist.append(QVariant(button->getJoyNumber()+1)); int index = ui->vdpadLeftComboBox->findData(templist); if (index > 0) { ui->vdpadLeftComboBox->setCurrentIndex(index); } } } void AdvanceStickAssignmentDialog::quickAssignVDPadRight() { if (qobject_cast(sender()) != 0) { JoyAxisButton *axisButton = static_cast(sender()); QList templist; templist.append(QVariant(axisButton->getAxis()->getRealJoyIndex())); if (axisButton->getAxis()->getNAxisButton() == axisButton) { templist.append(QVariant(0)); } else { templist.append(QVariant(1)); } int index = ui->vdpadRightComboBox->findData(templist); if (index > 0) { ui->vdpadRightComboBox->setCurrentIndex(index); } } else { JoyButton *button = static_cast(sender()); QList templist; templist.append(QVariant(0)); templist.append(QVariant(button->getJoyNumber()+1)); int index = ui->vdpadRightComboBox->findData(templist); if (index > 0) { ui->vdpadRightComboBox->setCurrentIndex(index); } } } antimicro-2.23/src/advancestickassignmentdialog.h000066400000000000000000000046611300750276700223130ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef ADVANCESTICKASSIGNMENTDIALOG_H #define ADVANCESTICKASSIGNMENTDIALOG_H #include #include "joystick.h" namespace Ui { class AdvanceStickAssignmentDialog; } class AdvanceStickAssignmentDialog : public QDialog { Q_OBJECT public: explicit AdvanceStickAssignmentDialog(Joystick *joystick, QWidget *parent = 0); ~AdvanceStickAssignmentDialog(); protected: Joystick *joystick; signals: void stickConfigurationChanged(); void vdpadConfigurationChanged(); private: Ui::AdvanceStickAssignmentDialog *ui; private slots: void refreshStickConfiguration(); void refreshVDPadConfiguration(); void checkForAxisAssignmentStickOne(); void checkForAxisAssignmentStickTwo(); void changeStateStickOneWidgets(bool enabled); void changeStateStickTwoWidgets(bool enabled); void changeStateVDPadWidgets(bool enabled); void populateDPadComboBoxes(); void changeVDPadUpButton(int index); void changeVDPadDownButton(int index); void changeVDPadLeftButton(int index); void changeVDPadRightButton(int index); void disableVDPadComboBoxes(); void enableVDPadComboBoxes(); void openQuickAssignDialogStick1(); void openQuickAssignDialogStick2(); void quickAssignStick1Axis1(); void quickAssignStick1Axis2(); void quickAssignStick2Axis1(); void quickAssignStick2Axis2(); void openAssignVDPadUp(); void openAssignVDPadDown(); void openAssignVDPadLeft(); void openAssignVDPadRight(); void quickAssignVDPadUp(); void quickAssignVDPadDown(); void quickAssignVDPadLeft(); void quickAssignVDPadRight(); void reenableButtonEvents(); }; #endif // ADVANCESTICKASSIGNMENTDIALOG_H antimicro-2.23/src/advancestickassignmentdialog.ui000066400000000000000000000505131300750276700224760ustar00rootroot00000000000000 AdvanceStickAssignmentDialog 0 0 770 440 0 0 Stick/Pad Assignment true 0 0 0 Sticks DPads Qt::Horizontal QSizePolicy::Fixed 20 20 0 50 false Note: This window is meant for backwards compatibility with profiles made before antimicro 2.0. Since version 2.0, use of the Game Controller Mapping window is preferred. true 75 true %1 (Joystick %2) -1 -1 75 true Stick 1 true Enabled Qt::Vertical QSizePolicy::Fixed 20 20 Qt::Horizontal 40 20 false Assign X Axis: false Y Axis: false Qt::Horizontal QSizePolicy::Fixed 40 10 75 true Stick 2 false Enabled Qt::Vertical QSizePolicy::Fixed 20 20 Qt::Horizontal 40 20 false Assign X Axis: false Y Axis: false 75 true %1 (Joystick %2) 75 true Number of Physical DPads: %1 Qt::Vertical 20 40 -1 75 true Virtual DPad 1 Qt::Vertical QSizePolicy::Fixed 20 11 Enabled Qt::Vertical QSizePolicy::Fixed 20 20 41 20 false Down: false Left: false Right: Up: false false Assign false Assign false Assign false Assign Qt::Vertical QSizePolicy::Fixed 20 20 Qt::Horizontal Qt::Horizontal QDialogButtonBox::Close buttonBox accepted() AdvanceStickAssignmentDialog accept() 252 369 157 274 buttonBox rejected() AdvanceStickAssignmentDialog reject() 320 369 286 274 listWidget currentRowChanged(int) stackedWidget setCurrentIndex(int) 91 116 291 105 antimicro-2.23/src/antimicro.exe.manifest000066400000000000000000000012321300750276700205160ustar00rootroot00000000000000 antimicro antimicro-2.23/src/antimicro.exe.uiaccess.manifest000066400000000000000000000012471300750276700223220ustar00rootroot00000000000000 antimicro antimicro-2.23/src/antimicro.rc000066400000000000000000000004461300750276700165420ustar00rootroot00000000000000#include "winuser.h" IDI_ICON1 ICON DISCARDABLE "images/antimicro.ico" #ifndef PERFORM_SIGNING CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "antimicro.exe.manifest" #else CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "antimicro.exe.uiaccess.manifest" #endif antimicro-2.23/src/antimicrosettings.cpp000066400000000000000000000047671300750276700205130ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "antimicrosettings.h" const bool AntiMicroSettings::defaultDisabledWinEnhanced = false; const bool AntiMicroSettings::defaultAssociateProfiles = true; const int AntiMicroSettings::defaultSpringScreen = -1; const unsigned int AntiMicroSettings::defaultSDLGamepadPollRate = 10; AntiMicroSettings::AntiMicroSettings(const QString &fileName, Format format, QObject *parent) : QSettings(fileName, format, parent) { } /** * @brief Get the currently used value such as an setting overridden * with a command line argument. * @param Setting key * @param Default value to use if key does not exist * @return Stored value or the default value passed */ QVariant AntiMicroSettings::runtimeValue(const QString &key, const QVariant &defaultValue) const { QVariant settingValue; QString inGroup = group(); QString fullKey = QString(inGroup).append("/").append(key); if (cmdSettings.contains(fullKey)) { settingValue = cmdSettings.value(fullKey, defaultValue); } else { settingValue = value(key, defaultValue); } return settingValue; } /** * @brief Import relevant options given on the command line into a QSettings * instance. Used to override any options that might be present in the * main settings file. Keys will have to be changed to the appropriate * config key. * @param Interpreted options set on the command line. */ void AntiMicroSettings::importFromCommandLine(CommandLineUtility &cmdutility) { cmdSettings.clear(); if (cmdutility.isLaunchInTrayEnabled()) { cmdSettings.setValue("LaunchInTray", 1); } if (cmdutility.shouldMapController()) { cmdSettings.setValue("DisplaySDLMapping", 1); } } QMutex* AntiMicroSettings::getLock() { return &lock; } antimicro-2.23/src/antimicrosettings.h000066400000000000000000000030071300750276700201420ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef ANTIMICROSETTINGS_H #define ANTIMICROSETTINGS_H #include #include #include "commandlineutility.h" class AntiMicroSettings : public QSettings { Q_OBJECT public: explicit AntiMicroSettings(const QString &fileName, Format format, QObject *parent = 0); QVariant runtimeValue(const QString &key, const QVariant &defaultValue = QVariant()) const; void importFromCommandLine(CommandLineUtility &cmdutility); QMutex* getLock(); static const bool defaultDisabledWinEnhanced; static const bool defaultAssociateProfiles; static const int defaultSpringScreen; static const unsigned int defaultSDLGamepadPollRate; protected: QSettings cmdSettings; QMutex lock; signals: public slots: }; #endif // ANTIMICROSETTINGS_H antimicro-2.23/src/antkeymapper.cpp000066400000000000000000000057641300750276700174430ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include "antkeymapper.h" #include "eventhandlerfactory.h" AntKeyMapper* AntKeyMapper::_instance = 0; static QStringList buildEventGeneratorList() { QStringList temp; #ifdef Q_OS_WIN temp.append("sendinput"); #ifdef WITH_VMULTI temp.append("vmulti"); #endif #else #ifdef WITH_XTEST temp.append("xtest"); #endif #ifdef WITH_UINPUT temp.append("uinput"); #endif #endif return temp; } AntKeyMapper::AntKeyMapper(QString handler, QObject *parent) : QObject(parent) { internalMapper = 0; #ifdef Q_OS_WIN #ifdef WITH_VMULTI if (handler == "vmulti") { internalMapper = &vmultiMapper; nativeKeyMapper = &winMapper; } #endif BACKEND_ELSE_IF (handler == "sendinput") { internalMapper = &winMapper; nativeKeyMapper = 0; } #else #ifdef WITH_XTEST if (handler == "xtest") { internalMapper = &x11Mapper; nativeKeyMapper = 0; } #endif #ifdef WITH_UINPUT if (handler == "uinput") { internalMapper = &uinputMapper; #ifdef WITH_XTEST nativeKeyMapper = &x11Mapper; #else nativeKeyMapper = 0; #endif } #endif #endif } AntKeyMapper* AntKeyMapper::getInstance(QString handler) { if (!_instance) { Q_ASSERT(!handler.isEmpty()); QStringList temp = buildEventGeneratorList(); Q_ASSERT(temp.contains(handler)); _instance = new AntKeyMapper(handler); } return _instance; } void AntKeyMapper::deleteInstance() { if (_instance) { delete _instance; _instance = 0; } } unsigned int AntKeyMapper::returnQtKey(unsigned int key, unsigned int scancode) { return internalMapper->returnQtKey(key, scancode); } unsigned int AntKeyMapper::returnVirtualKey(unsigned int qkey) { return internalMapper->returnVirtualKey(qkey); } bool AntKeyMapper::isModifierKey(unsigned int qkey) { return internalMapper->isModifier(qkey); } QtKeyMapperBase* AntKeyMapper::getNativeKeyMapper() { return nativeKeyMapper; } QtKeyMapperBase* AntKeyMapper::getKeyMapper() { return internalMapper; } bool AntKeyMapper::hasNativeKeyMapper() { bool result = nativeKeyMapper != 0; return result; } antimicro-2.23/src/antkeymapper.h000066400000000000000000000037611300750276700171030ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef ANTKEYMAPPER_H #define ANTKEYMAPPER_H #include #ifdef Q_OS_WIN #include "qtwinkeymapper.h" #ifdef WITH_VMULTI #include "qtvmultikeymapper.h" #endif #else #if defined(WITH_XTEST) #include "qtx11keymapper.h" #endif #if defined(WITH_UINPUT) #include "qtuinputkeymapper.h" #endif #endif class AntKeyMapper : public QObject { Q_OBJECT public: static AntKeyMapper* getInstance(QString handler = ""); void deleteInstance(); unsigned int returnVirtualKey(unsigned int qkey); unsigned int returnQtKey(unsigned int key, unsigned int scancode=0); bool isModifierKey(unsigned int qkey); QtKeyMapperBase* getNativeKeyMapper(); QtKeyMapperBase* getKeyMapper(); bool hasNativeKeyMapper(); protected: explicit AntKeyMapper(QString handler = "", QObject *parent = 0); static AntKeyMapper *_instance; QtKeyMapperBase *internalMapper; QtKeyMapperBase *nativeKeyMapper; #ifdef Q_OS_WIN QtWinKeyMapper winMapper; #ifdef WITH_VMULTI QtVMultiKeyMapper vmultiMapper; #endif #else #if defined(WITH_XTEST) QtX11KeyMapper x11Mapper; #endif #if defined(WITH_UINPUT) QtUInputKeyMapper uinputMapper; #endif #endif signals: public slots: }; #endif // ANTKEYMAPPER_H antimicro-2.23/src/applaunchhelper.cpp000066400000000000000000000132531300750276700201060ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "applaunchhelper.h" #ifdef Q_OS_WIN #include #endif AppLaunchHelper::AppLaunchHelper(AntiMicroSettings *settings, bool graphical, QObject *parent) : QObject(parent) { this->settings = settings; this->graphical = graphical; } void AppLaunchHelper::initRunMethods() { if (graphical) { establishMouseTimerConnections(); enablePossibleMouseSmoothing(); changeMouseRefreshRate(); changeSpringModeScreen(); changeGamepadPollRate(); #ifdef Q_OS_WIN checkPointerPrecision(); #endif } } void AppLaunchHelper::enablePossibleMouseSmoothing() { bool smoothingEnabled = settings->value("Mouse/Smoothing", false).toBool(); if (smoothingEnabled) { int historySize = settings->value("Mouse/HistorySize", 0).toInt(); if (historySize > 0) { JoyButton::setMouseHistorySize(historySize); } double weightModifier = settings->value("Mouse/WeightModifier", 0.0).toDouble(); if (weightModifier > 0.0) { JoyButton::setWeightModifier(weightModifier); } } } void AppLaunchHelper::changeMouseRefreshRate() { int refreshRate = settings->value("Mouse/RefreshRate", 0).toInt(); if (refreshRate > 0) { JoyButton::setMouseRefreshRate(refreshRate); } } void AppLaunchHelper::changeGamepadPollRate() { unsigned int pollRate = settings->value("GamepadPollRate", AntiMicroSettings::defaultSDLGamepadPollRate).toUInt(); if (pollRate > 0) { JoyButton::setGamepadRefreshRate(pollRate); } } void AppLaunchHelper::printControllerList(QMap *joysticks) { QTextStream outstream(stdout); outstream << QObject::tr("# of joysticks found: %1").arg(joysticks->size()) << endl; outstream << endl; outstream << QObject::tr("List Joysticks:") << endl; outstream << QObject::tr("---------------") << endl; QMapIterator iter(*joysticks); unsigned int indexNumber = 1; while (iter.hasNext()) { InputDevice *tempdevice = iter.next().value(); outstream << QObject::tr("Joystick %1:").arg(indexNumber) << endl; outstream << " " << QObject::tr("Index: %1").arg(tempdevice->getRealJoyNumber()) << endl; #ifdef USE_SDL_2 outstream << " " << QObject::tr("GUID: %1").arg(tempdevice->getGUIDString()) << endl; #endif outstream << " " << QObject::tr("Name: %1").arg(tempdevice->getSDLName()) << endl; #ifdef USE_SDL_2 QString gameControllerStatus = tempdevice->isGameController() ? QObject::tr("Yes") : QObject::tr("No"); outstream << " " << QObject::tr("Game Controller: %1").arg(gameControllerStatus) << endl; #endif outstream << " " << QObject::tr("# of Axes: %1").arg(tempdevice->getNumberRawAxes()) << endl; outstream << " " << QObject::tr("# of Buttons: %1").arg(tempdevice->getNumberRawButtons()) << endl; outstream << " " << QObject::tr("# of Hats: %1").arg(tempdevice->getNumberHats()) << endl; if (iter.hasNext()) { outstream << endl; indexNumber++; } } } void AppLaunchHelper::changeSpringModeScreen() { QDesktopWidget deskWid; int springScreen = settings->value("Mouse/SpringScreen", AntiMicroSettings::defaultSpringScreen).toInt(); if (springScreen >= deskWid.screenCount()) { springScreen = -1; settings->setValue("Mouse/SpringScreen", AntiMicroSettings::defaultSpringScreen); settings->sync(); } JoyButton::setSpringModeScreen(springScreen); } #ifdef Q_OS_WIN void AppLaunchHelper::checkPointerPrecision() { WinExtras::grabCurrentPointerPrecision(); bool disableEnhandedPoint = settings->value("Mouse/DisableWinEnhancedPointer", AntiMicroSettings::defaultDisabledWinEnhanced).toBool(); if (disableEnhandedPoint) { WinExtras::disablePointerPrecision(); } } void AppLaunchHelper::appQuitPointerPrecision() { bool disableEnhancedPoint = settings->value("Mouse/DisableWinEnhancedPointer", AntiMicroSettings::defaultDisabledWinEnhanced).toBool(); if (disableEnhancedPoint && !WinExtras::isUsingEnhancedPointerPrecision()) { WinExtras::enablePointerPrecision(); } } #endif void AppLaunchHelper::revertMouseThread() { JoyButton::indirectStaticMouseThread(QThread::currentThread()); } void AppLaunchHelper::changeMouseThread(QThread *thread) { JoyButton::setStaticMouseThread(thread); } void AppLaunchHelper::establishMouseTimerConnections() { JoyButton::establishMouseTimerConnections(); } antimicro-2.23/src/applaunchhelper.h000066400000000000000000000033201300750276700175450ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef APPLAUNCHHELPER_H #define APPLAUNCHHELPER_H #include #include #include #include "inputdevice.h" #include "joybutton.h" #include "antimicrosettings.h" class AppLaunchHelper : public QObject { Q_OBJECT public: explicit AppLaunchHelper(AntiMicroSettings *settings, bool graphical=false, QObject *parent=0); void printControllerList(QMap *joysticks); protected: void enablePossibleMouseSmoothing(); void establishMouseTimerConnections(); void changeMouseRefreshRate(); void changeSpringModeScreen(); void changeGamepadPollRate(); #ifdef Q_OS_WIN void checkPointerPrecision(); #endif AntiMicroSettings *settings; bool graphical; signals: public slots: #ifdef Q_OS_WIN void appQuitPointerPrecision(); #endif void initRunMethods(); void revertMouseThread(); void changeMouseThread(QThread *thread); }; #endif // APPLAUNCHHELPER_H antimicro-2.23/src/autoprofileinfo.cpp000066400000000000000000000064271300750276700201450ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "autoprofileinfo.h" AutoProfileInfo::AutoProfileInfo(QString guid, QString profileLocation, QString exe, bool active, QObject *parent) : QObject(parent) { setGUID(guid); setProfileLocation(profileLocation); setExe(exe); setActive(active); setDefaultState(false); } AutoProfileInfo::AutoProfileInfo(QString guid, QString profileLocation, bool active, QObject *parent) : QObject(parent) { setGUID(guid); setProfileLocation(profileLocation); setActive(active); setDefaultState(false); } AutoProfileInfo::AutoProfileInfo(QObject *parent) : QObject(parent) { setActive(true); setDefaultState(false); } AutoProfileInfo::~AutoProfileInfo() { } void AutoProfileInfo::setGUID(QString guid) { this->guid = guid; } QString AutoProfileInfo::getGUID() { return guid; } void AutoProfileInfo::setProfileLocation(QString profileLocation) { QFileInfo info(profileLocation); if (profileLocation != this->profileLocation && info.exists() && info.isReadable()) { this->profileLocation = profileLocation; } else if (profileLocation.isEmpty()) { this->profileLocation = ""; } } QString AutoProfileInfo::getProfileLocation() { return profileLocation; } void AutoProfileInfo::setExe(QString exe) { if (!exe.isEmpty()) { QFileInfo info(exe); if (exe != this->exe && info.exists() && info.isExecutable()) { this->exe = exe; } #ifdef Q_OS_WIN else if (exe != this->exe && info.suffix() == "exe") { this->exe = exe; } #endif } else { this->exe = exe; } } QString AutoProfileInfo::getExe() { return exe; } void AutoProfileInfo::setWindowClass(QString windowClass) { this->windowClass = windowClass; } QString AutoProfileInfo::getWindowClass() { return windowClass; } void AutoProfileInfo::setWindowName(QString winName) { this->windowName = winName; } QString AutoProfileInfo::getWindowName() { return windowName; } void AutoProfileInfo::setActive(bool active) { this->active = active; } bool AutoProfileInfo::isActive() { return active; } void AutoProfileInfo::setDefaultState(bool value) { this->defaultState = value; } bool AutoProfileInfo::isCurrentDefault() { return defaultState; } void AutoProfileInfo::setDeviceName(QString name) { this->deviceName = name; } QString AutoProfileInfo::getDeviceName() { return deviceName; } antimicro-2.23/src/autoprofileinfo.h000066400000000000000000000040441300750276700176030ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef AUTOPROFILEINFO_H #define AUTOPROFILEINFO_H #include #include class AutoProfileInfo : public QObject { Q_OBJECT public: explicit AutoProfileInfo(QString guid, QString profileLocation, bool active, QObject *parent = 0); explicit AutoProfileInfo(QString guid, QString profileLocation, QString exe, bool active, QObject *parent = 0); explicit AutoProfileInfo(QObject *parent=0); ~AutoProfileInfo(); void setGUID(QString guid); QString getGUID(); void setProfileLocation(QString profileLocation); QString getProfileLocation(); void setExe(QString exe); QString getExe(); void setWindowClass(QString windowClass); QString getWindowClass(); void setWindowName(QString winName); QString getWindowName(); void setActive(bool active); bool isActive(); void setDeviceName(QString name); QString getDeviceName(); void setDefaultState(bool value); bool isCurrentDefault(); protected: QString guid; QString profileLocation; QString exe; QString deviceName; QString windowClass; QString windowName; bool active; bool defaultState; signals: public slots: }; Q_DECLARE_METATYPE(AutoProfileInfo*) #endif // AUTOPROFILEINFO_H antimicro-2.23/src/autoprofilewatcher.cpp000066400000000000000000000374021300750276700206440ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include #include #include #include #include #include "autoprofilewatcher.h" #if defined(Q_OS_UNIX) && defined(WITH_X11) #include "x11extras.h" #elif defined(Q_OS_WIN) #include "winextras.h" #endif AutoProfileWatcher::AutoProfileWatcher(AntiMicroSettings *settings, QObject *parent) : QObject(parent) { this->settings = settings; allDefaultInfo = 0; currentApplication = ""; syncProfileAssignment(); connect(&appTimer, SIGNAL(timeout()), this, SLOT(runAppCheck())); } void AutoProfileWatcher::startTimer() { appTimer.start(CHECKTIME); } void AutoProfileWatcher::stopTimer() { appTimer.stop(); } void AutoProfileWatcher::runAppCheck() { //qDebug() << qApp->applicationFilePath(); QString appLocation; QString baseAppFileName; guidSet.clear(); // Check whether program path needs to be parsed. Removes processing time // and need to run Linux specific code searching /proc. #ifdef Q_OS_LINUX if (!appProfileAssignments.isEmpty()) { appLocation = findAppLocation(); } #else // In Windows, get program location no matter what. appLocation = findAppLocation(); if (!appLocation.isEmpty()) { baseAppFileName = QFileInfo(appLocation).fileName(); } #endif // More portable check for whether antimicro is the current application // with focus. QWidget *focusedWidget = qApp->activeWindow(); QString nowWindow; QString nowWindowClass; QString nowWindowName; #ifdef Q_OS_WIN nowWindowName = WinExtras::getCurrentWindowText(); #else unsigned long currentWindow = X11Extras::getInstance()->getWindowInFocus(); if (currentWindow > 0) { unsigned long tempWindow = X11Extras::getInstance()->findParentClient(currentWindow); if (tempWindow > 0) { currentWindow = tempWindow; } nowWindow = QString::number(currentWindow); nowWindowClass = X11Extras::getInstance()->getWindowClass(currentWindow); nowWindowName = X11Extras::getInstance()->getWindowTitle(currentWindow); //qDebug() << nowWindowClass; //qDebug() << nowWindowName; } #endif bool checkForTitleChange = windowNameProfileAssignments.size() > 0; #ifdef Q_OS_WIN if (!focusedWidget && ((!appLocation.isEmpty() && appLocation != currentApplication) || (checkForTitleChange && nowWindowName != currentAppWindowTitle))) #else if (!focusedWidget && ((!nowWindow.isEmpty() && nowWindow != currentApplication) || (checkForTitleChange && nowWindowName != currentAppWindowTitle))) #endif { #ifdef Q_OS_WIN currentApplication = appLocation; #else currentApplication = nowWindow; #endif currentAppWindowTitle = nowWindowName; //currentApplication = appLocation; Logger::LogDebug(QObject::tr("Active window changed to: Title = \"%1\", " "Class = \"%2\", Program = \"%3\" or \"%4\"."). arg(nowWindowName, nowWindowClass, appLocation, baseAppFileName)); QSet fullSet; if (!appLocation.isEmpty() && appProfileAssignments.contains(appLocation)) { QSet tempSet; tempSet = appProfileAssignments.value(appLocation).toSet(); fullSet.unite(tempSet); } else if (!baseAppFileName.isEmpty() && appProfileAssignments.contains(baseAppFileName)) { QSet tempSet; tempSet = appProfileAssignments.value(baseAppFileName).toSet(); fullSet.unite(tempSet); } if (!nowWindowClass.isEmpty() && windowClassProfileAssignments.contains(nowWindowClass)) { QSet tempSet; tempSet = windowClassProfileAssignments.value(nowWindowClass).toSet(); fullSet.unite(tempSet); } if (!nowWindowName.isEmpty() && windowNameProfileAssignments.contains(nowWindowName)) { QSet tempSet; tempSet = windowNameProfileAssignments.value(nowWindowName).toSet(); fullSet = fullSet.unite(tempSet); } QHash highestMatchCount; QHash highestMatches; QSetIterator fullSetIter(fullSet); while (fullSetIter.hasNext()) { AutoProfileInfo *info = fullSetIter.next(); if (info->isActive()) { int numProps = 0; numProps += !info->getExe().isEmpty() ? 1 : 0; numProps += !info->getWindowClass().isEmpty() ? 1 : 0; numProps += !info->getWindowName().isEmpty() ? 1 : 0; int numMatched = 0; numMatched += (!info->getExe().isEmpty() && (info->getExe() == appLocation || info->getExe() == baseAppFileName)) ? 1 : 0; numMatched += (!info->getWindowClass().isEmpty() && info->getWindowClass() == nowWindowClass) ? 1 : 0; numMatched += (!info->getWindowName().isEmpty() && info->getWindowName() == nowWindowName) ? 1 : 0; if (numProps == numMatched) { if (highestMatchCount.contains(info->getGUID())) { int currentHigh = highestMatchCount.value(info->getGUID()); if (numMatched > currentHigh) { highestMatchCount.insert(info->getGUID(), numMatched); highestMatches.insert(info->getGUID(), info); } } else { highestMatchCount.insert(info->getGUID(), numMatched); highestMatches.insert(info->getGUID(), info); } } } } QHashIterator highIter(highestMatches); while (highIter.hasNext()) { AutoProfileInfo *info = highIter.next().value(); guidSet.insert(info->getGUID()); emit foundApplicableProfile(info); } if ((!defaultProfileAssignments.isEmpty() || allDefaultInfo) && !focusedWidget) //antiProgramLocation != appLocation) { if (allDefaultInfo) { if (allDefaultInfo->isActive() && !guidSet.contains("all")) { emit foundApplicableProfile(allDefaultInfo); } } QHashIterator iter(defaultProfileAssignments); while (iter.hasNext()) { iter.next(); AutoProfileInfo *info = iter.value(); if (info->isActive() && !guidSet.contains(info->getGUID())) { emit foundApplicableProfile(info); } } } } } void AutoProfileWatcher::syncProfileAssignment() { clearProfileAssignments(); currentApplication = ""; //QStringList assignments = settings->allKeys(); //QStringListIterator iter(assignments); settings->getLock()->lock(); settings->beginGroup("DefaultAutoProfiles"); QString exe; QString guid; QString profile; QString active; QString windowClass; QString windowName; QStringList registeredGUIDs = settings->value("GUIDs", QStringList()).toStringList(); //QStringList defaultkeys = settings->allKeys(); settings->endGroup(); QString allProfile = settings->value(QString("DefaultAutoProfileAll/Profile"), "").toString(); QString allActive = settings->value(QString("DefaultAutoProfileAll/Active"), "0").toString(); // Handle overall Default profile assignment bool defaultActive = allActive == "1" ? true : false; if (defaultActive) { allDefaultInfo = new AutoProfileInfo("all", allProfile, defaultActive, this); allDefaultInfo->setDefaultState(true); } // Handle device specific Default profile assignments QStringListIterator iter(registeredGUIDs); while (iter.hasNext()) { QString tempkey = iter.next(); QString guid = QString(tempkey).replace("GUID", ""); QString profile = settings->value(QString("DefaultAutoProfile-%1/Profile").arg(guid), "").toString(); QString active = settings->value(QString("DefaultAutoProfile-%1/Active").arg(guid), "").toString(); if (!guid.isEmpty() && !profile.isEmpty()) { bool profileActive = active == "1" ? true : false; if (profileActive && guid != "all") { AutoProfileInfo *info = new AutoProfileInfo(guid, profile, profileActive, this); info->setDefaultState(true); defaultProfileAssignments.insert(guid, info); } } } settings->beginGroup("AutoProfiles"); bool quitSearch = false; //QHash > tempAssociation; for (int i = 1; !quitSearch; i++) { exe = settings->value(QString("AutoProfile%1Exe").arg(i), "").toString(); exe = QDir::toNativeSeparators(exe); guid = settings->value(QString("AutoProfile%1GUID").arg(i), "").toString(); profile = settings->value(QString("AutoProfile%1Profile").arg(i), "").toString(); active = settings->value(QString("AutoProfile%1Active").arg(i), 0).toString(); windowName = settings->value(QString("AutoProfile%1WindowName").arg(i), "").toString(); #ifdef Q_OS_UNIX windowClass = settings->value(QString("AutoProfile%1WindowClass").arg(i), "").toString(); #else windowClass.clear(); #endif // Check if all required elements exist. If not, assume that the end of the // list has been reached. if ((!exe.isEmpty() || !windowClass.isEmpty() || !windowName.isEmpty()) && !guid.isEmpty()) { bool profileActive = active == "1" ? true : false; if (profileActive) { AutoProfileInfo *info = new AutoProfileInfo(guid, profile, profileActive, this); if (!windowClass.isEmpty()) { info->setWindowClass(windowClass); QList templist; if (windowClassProfileAssignments.contains(windowClass)) { templist = windowClassProfileAssignments.value(windowClass); } templist.append(info); windowClassProfileAssignments.insert(windowClass, templist); } if (!windowName.isEmpty()) { info->setWindowName(windowName); QList templist; if (windowNameProfileAssignments.contains(windowName)) { templist = windowNameProfileAssignments.value(windowName); } templist.append(info); windowNameProfileAssignments.insert(windowName, templist); } if (!exe.isEmpty()) { info->setExe(exe); QList templist; if (appProfileAssignments.contains(exe)) { templist = appProfileAssignments.value(exe); } templist.append(info); appProfileAssignments.insert(exe, templist); QString baseExe = QFileInfo(exe).fileName(); if (!baseExe.isEmpty() && baseExe != exe) { QList templist; if (appProfileAssignments.contains(baseExe)) { templist = appProfileAssignments.value(baseExe); } templist.append(info); appProfileAssignments.insert(baseExe, templist); } } } } else { quitSearch = true; } } settings->endGroup(); settings->getLock()->unlock(); } void AutoProfileWatcher::clearProfileAssignments() { QSet terminateProfiles; QListIterator > iterDelete(appProfileAssignments.values()); while (iterDelete.hasNext()) { QList templist = iterDelete.next(); terminateProfiles.unite(templist.toSet()); } appProfileAssignments.clear(); QListIterator > iterClassDelete(windowClassProfileAssignments.values()); while (iterClassDelete.hasNext()) { QList templist = iterClassDelete.next(); terminateProfiles.unite(templist.toSet()); } windowClassProfileAssignments.clear(); QListIterator > iterNameDelete(windowNameProfileAssignments.values()); while (iterNameDelete.hasNext()) { QList templist = iterNameDelete.next(); terminateProfiles.unite(templist.toSet()); } windowNameProfileAssignments.clear(); QSetIterator iterTerminate(terminateProfiles); while (iterTerminate.hasNext()) { AutoProfileInfo *info = iterTerminate.next(); if (info) { delete info; info = 0; } } QListIterator iterDefaultsDelete(defaultProfileAssignments.values()); while (iterDefaultsDelete.hasNext()) { AutoProfileInfo *info = iterDefaultsDelete.next(); if (info) { delete info; info = 0; } } defaultProfileAssignments.clear(); allDefaultInfo = 0; guidSet.clear(); } QString AutoProfileWatcher::findAppLocation() { QString exepath; #if defined(Q_OS_LINUX) #ifdef WITH_X11 Window currentWindow = 0; int pid = 0; currentWindow = X11Extras::getInstance()->getWindowInFocus(); if (currentWindow) { pid = X11Extras::getInstance()->getApplicationPid(currentWindow); } if (pid > 0) { exepath = X11Extras::getInstance()->getApplicationLocation(pid); } #endif #elif defined(Q_OS_WIN) exepath = WinExtras::getForegroundWindowExePath(); //qDebug() << exepath; #endif return exepath; } QList* AutoProfileWatcher::getCustomDefaults() { QList *temp = new QList(); QHashIterator iter(defaultProfileAssignments); while (iter.hasNext()) { iter.next(); temp->append(iter.value()); } return temp; } AutoProfileInfo* AutoProfileWatcher::getDefaultAllProfile() { return allDefaultInfo; } bool AutoProfileWatcher::isGUIDLocked(QString guid) { return guidSet.contains(guid); } antimicro-2.23/src/autoprofilewatcher.h000066400000000000000000000043451300750276700203110ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef AUTOPROFILEWATCHER_H #define AUTOPROFILEWATCHER_H #include #include #include #include #include #include "autoprofileinfo.h" #include "antimicrosettings.h" class AutoProfileWatcher : public QObject { Q_OBJECT public: explicit AutoProfileWatcher(AntiMicroSettings *settings, QObject *parent = 0); void startTimer(); void stopTimer(); QList* getCustomDefaults(); AutoProfileInfo* getDefaultAllProfile(); bool isGUIDLocked(QString guid); static const int CHECKTIME = 1000; // time in ms protected: QString findAppLocation(); void clearProfileAssignments(); QTimer appTimer; AntiMicroSettings *settings; // Path, QList QHash > appProfileAssignments; // WM_CLASS, QList QHash > windowClassProfileAssignments; // WM_NAME, QList QHash > windowNameProfileAssignments; // GUID, AutoProfileInfo* QHash defaultProfileAssignments; //QList *customDefaults; AutoProfileInfo *allDefaultInfo; QString currentApplication; QString currentAppWindowTitle; QSet guidSet; signals: void foundApplicableProfile(AutoProfileInfo *info); public slots: void syncProfileAssignment(); private slots: void runAppCheck(); }; #endif // AUTOPROFILEWATCHER_H antimicro-2.23/src/axiseditdialog.cpp000066400000000000000000000602621300750276700177270ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include "axiseditdialog.h" #include "ui_axiseditdialog.h" #include "buttoneditdialog.h" #include "mousedialog/mouseaxissettingsdialog.h" #include "event.h" #include "antkeymapper.h" #include "setjoystick.h" #include "inputdevice.h" #include "common.h" AxisEditDialog::AxisEditDialog(JoyAxis *axis, QWidget *parent) : QDialog(parent, Qt::Window), ui(new Ui::AxisEditDialog) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); setAxisThrottleConfirm = new SetAxisThrottleDialog(axis, this); this->axis = axis; updateWindowTitleAxisName(); initialThrottleState = axis->getThrottle(); bool actAsTrigger = false; if (initialThrottleState == JoyAxis::PositiveThrottle || initialThrottleState == JoyAxis::PositiveHalfThrottle) { actAsTrigger = true; } if (actAsTrigger) { buildTriggerPresetsMenu(); } ui->horizontalSlider->setValue(axis->getDeadZone()); ui->lineEdit->setText(QString::number(axis->getDeadZone())); ui->horizontalSlider_2->setValue(axis->getMaxZoneValue()); ui->lineEdit_2->setText(QString::number(axis->getMaxZoneValue())); JoyAxisButton *nButton = axis->getNAxisButton(); if (!nButton->getActionName().isEmpty()) { ui->nPushButton->setText(nButton->getActionName()); } else { ui->nPushButton->setText(nButton->getSlotsSummary()); } JoyAxisButton *pButton = axis->getPAxisButton(); if (!pButton->getActionName().isEmpty()) { ui->pPushButton->setText(pButton->getActionName()); } else { ui->pPushButton->setText(pButton->getSlotsSummary()); } int currentThrottle = axis->getThrottle(); //ui->comboBox_2->setCurrentIndex(currentThrottle+1); if (currentThrottle == JoyAxis::NegativeThrottle || currentThrottle == JoyAxis::NegativeHalfThrottle) { int tempindex = currentThrottle == JoyAxis::NegativeHalfThrottle ? 0 : 1; ui->comboBox_2->setCurrentIndex(tempindex); ui->nPushButton->setEnabled(true); ui->pPushButton->setEnabled(false); } else if (currentThrottle == JoyAxis::PositiveThrottle || currentThrottle == JoyAxis::PositiveHalfThrottle) { int tempindex = currentThrottle == JoyAxis::PositiveThrottle ? 3 : 4; ui->comboBox_2->setCurrentIndex(tempindex); ui->pPushButton->setEnabled(true); ui->nPushButton->setEnabled(false); } ui->axisstatusBox->setDeadZone(axis->getDeadZone()); ui->axisstatusBox->setMaxZone(axis->getMaxZoneValue()); ui->axisstatusBox->setThrottle(axis->getThrottle()); ui->joyValueLabel->setText(QString::number(axis->getCurrentRawValue())); ui->axisstatusBox->setValue(axis->getCurrentRawValue()); if (!actAsTrigger) { selectAxisCurrentPreset(); } else { selectTriggerPreset(); } ui->axisNameLineEdit->setText(axis->getAxisName()); connect(ui->presetsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(implementPresets(int))); connect(ui->horizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(updateDeadZoneBox(int))); connect(ui->horizontalSlider, SIGNAL(valueChanged(int)), ui->axisstatusBox, SLOT(setDeadZone(int))); connect(ui->horizontalSlider, SIGNAL(valueChanged(int)), axis, SLOT(setDeadZone(int))); connect(ui->horizontalSlider_2, SIGNAL(valueChanged(int)), this, SLOT(updateMaxZoneBox(int))); connect(ui->horizontalSlider_2, SIGNAL(valueChanged(int)), ui->axisstatusBox, SLOT(setMaxZone(int))); connect(ui->horizontalSlider_2, SIGNAL(valueChanged(int)), axis, SLOT(setMaxZoneValue(int))); connect(ui->comboBox_2, SIGNAL(currentIndexChanged(int)), this, SLOT(updateThrottleUi(int))); connect(ui->comboBox_2, SIGNAL(currentIndexChanged(int)), this, SLOT(presetForThrottleChange(int))); connect(axis, SIGNAL(moved(int)), ui->axisstatusBox, SLOT(setValue(int))); connect(axis, SIGNAL(moved(int)), this, SLOT(updateJoyValue(int))); connect(ui->lineEdit, SIGNAL(textEdited(QString)), this, SLOT(updateDeadZoneSlider(QString))); connect(ui->lineEdit_2, SIGNAL(textEdited(QString)), this, SLOT(updateMaxZoneSlider(QString))); connect(ui->nPushButton, SIGNAL(clicked()), this, SLOT(openAdvancedNDialog())); connect(ui->pPushButton, SIGNAL(clicked()), this, SLOT(openAdvancedPDialog())); connect(ui->mouseSettingsPushButton, SIGNAL(clicked()), this, SLOT(openMouseSettingsDialog())); connect(ui->axisNameLineEdit, SIGNAL(textEdited(QString)), axis, SLOT(setAxisName(QString))); connect(axis, SIGNAL(axisNameChanged()), this, SLOT(updateWindowTitleAxisName())); connect(this, SIGNAL(finished(int)), this, SLOT(checkFinalSettings())); } AxisEditDialog::~AxisEditDialog() { delete ui; } void AxisEditDialog::implementPresets(int index) { bool actAsTrigger = false; int currentThrottle = axis->getThrottle(); if (currentThrottle == JoyAxis::PositiveThrottle || currentThrottle == JoyAxis::PositiveHalfThrottle) { actAsTrigger = true; } if (actAsTrigger) { implementTriggerPresets(index); } else { implementAxisPresets(index); } } void AxisEditDialog::implementAxisPresets(int index) { JoyButtonSlot *nbuttonslot = 0; JoyButtonSlot *pbuttonslot = 0; PadderCommon::lockInputDevices(); InputDevice *tempDevice = axis->getParentSet()->getInputDevice(); QMetaObject::invokeMethod(tempDevice, "haltServices", Qt::BlockingQueuedConnection); if (index == 1) { nbuttonslot = new JoyButtonSlot(JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); pbuttonslot = new JoyButtonSlot(JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); } else if (index == 2) { nbuttonslot = new JoyButtonSlot(JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); pbuttonslot = new JoyButtonSlot(JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); } else if (index == 3) { nbuttonslot = new JoyButtonSlot(JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); pbuttonslot = new JoyButtonSlot(JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); } else if (index == 4) { nbuttonslot = new JoyButtonSlot(JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); pbuttonslot = new JoyButtonSlot(JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); } else if (index == 5) { nbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Up), Qt::Key_Up, JoyButtonSlot::JoyKeyboard, this); pbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Down), Qt::Key_Down, JoyButtonSlot::JoyKeyboard, this); } else if (index == 6) { nbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Left), Qt::Key_Left, JoyButtonSlot::JoyKeyboard, this); pbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Right), Qt::Key_Right, JoyButtonSlot::JoyKeyboard, this); } else if (index == 7) { nbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_W), Qt::Key_W, JoyButtonSlot::JoyKeyboard, this); pbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_S), Qt::Key_S, JoyButtonSlot::JoyKeyboard, this); } else if (index == 8) { nbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_A), Qt::Key_A, JoyButtonSlot::JoyKeyboard, this); pbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_D), Qt::Key_D, JoyButtonSlot::JoyKeyboard, this); } else if (index == 9) { nbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_8), QtKeyMapperBase::AntKey_KP_8, JoyButtonSlot::JoyKeyboard, this); pbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_2), QtKeyMapperBase::AntKey_KP_2, JoyButtonSlot::JoyKeyboard, this); } else if (index == 10) { nbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_4), QtKeyMapperBase::AntKey_KP_4, JoyButtonSlot::JoyKeyboard, this); pbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_6), QtKeyMapperBase::AntKey_KP_6, JoyButtonSlot::JoyKeyboard, this); } else if (index == 11) { JoyAxisButton *nbutton = axis->getNAxisButton(); JoyAxisButton *pbutton = axis->getPAxisButton(); QMetaObject::invokeMethod(nbutton, "clearSlotsEventReset"); QMetaObject::invokeMethod(pbutton, "clearSlotsEventReset", Qt::BlockingQueuedConnection); refreshNButtonLabel(); refreshPButtonLabel(); } if (nbuttonslot) { JoyAxisButton *button = axis->getNAxisButton(); QMetaObject::invokeMethod(button, "clearSlotsEventReset", Q_ARG(bool, false)); QMetaObject::invokeMethod(button, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, nbuttonslot->getSlotCode()), Q_ARG(unsigned int, nbuttonslot->getSlotCodeAlias()), Q_ARG(JoyButtonSlot::JoySlotInputAction, nbuttonslot->getSlotMode())); refreshNButtonLabel(); nbuttonslot->deleteLater(); } if (pbuttonslot) { JoyAxisButton *button = axis->getPAxisButton(); QMetaObject::invokeMethod(button, "clearSlotsEventReset", Q_ARG(bool, false)); QMetaObject::invokeMethod(button, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, pbuttonslot->getSlotCode()), Q_ARG(unsigned int, pbuttonslot->getSlotCodeAlias()), Q_ARG(JoyButtonSlot::JoySlotInputAction, pbuttonslot->getSlotMode())); refreshPButtonLabel(); pbuttonslot->deleteLater(); } PadderCommon::unlockInputDevices(); } void AxisEditDialog::updateDeadZoneBox(int value) { ui->lineEdit->setText(QString::number(value)); } void AxisEditDialog::updateMaxZoneBox(int value) { ui->lineEdit_2->setText(QString::number(value)); } void AxisEditDialog::updateThrottleUi(int index) { int tempthrottle = 0; if (index == 0 || index == 1) { ui->nPushButton->setEnabled(true); ui->pPushButton->setEnabled(false); tempthrottle = index == 0 ? JoyAxis::NegativeHalfThrottle : JoyAxis::NegativeThrottle; } else if (index == 2) { ui->nPushButton->setEnabled(true); ui->pPushButton->setEnabled(true); tempthrottle = JoyAxis::NormalThrottle; } else if (index == 3 || index == 4) { ui->pPushButton->setEnabled(true); ui->nPushButton->setEnabled(false); tempthrottle = index == 3 ? JoyAxis::PositiveThrottle : JoyAxis::PositiveHalfThrottle; } axis->setThrottle(tempthrottle); ui->axisstatusBox->setThrottle(tempthrottle); } void AxisEditDialog::updateJoyValue(int value) { ui->joyValueLabel->setText(QString::number(value)); } void AxisEditDialog::updateDeadZoneSlider(QString value) { int temp = value.toInt(); if (temp >= JoyAxis::AXISMIN && temp <= JoyAxis::AXISMAX) { ui->horizontalSlider->setValue(temp); } } void AxisEditDialog::updateMaxZoneSlider(QString value) { int temp = value.toInt(); if (temp >= JoyAxis::AXISMIN && temp <= JoyAxis::AXISMAX) { ui->horizontalSlider_2->setValue(temp); } } void AxisEditDialog::openAdvancedPDialog() { ButtonEditDialog *dialog = new ButtonEditDialog(axis->getPAxisButton(), this); dialog->show(); connect(dialog, SIGNAL(finished(int)), this, SLOT(refreshPButtonLabel())); connect(dialog, SIGNAL(finished(int)), this, SLOT(refreshPreset())); } void AxisEditDialog::openAdvancedNDialog() { ButtonEditDialog *dialog = new ButtonEditDialog(axis->getNAxisButton(), this); dialog->show(); connect(dialog, SIGNAL(finished(int)), this, SLOT(refreshNButtonLabel())); connect(dialog, SIGNAL(finished(int)), this, SLOT(refreshPreset())); } void AxisEditDialog::refreshNButtonLabel() { /*if (!axis->getNAxisButton()->getActionName().isEmpty()) { ui->nPushButton->setText(axis->getNAxisButton()->getActionName()); } else { ui->nPushButton->setText(axis->getNAxisButton()->getSlotsSummary()); }*/ ui->nPushButton->setText(axis->getNAxisButton()->getSlotsSummary()); } void AxisEditDialog::refreshPButtonLabel() { /*if (!axis->getPAxisButton()->getActionName().isEmpty()) { ui->pPushButton->setText(axis->getPAxisButton()->getActionName()); } else { ui->pPushButton->setText(axis->getPAxisButton()->getSlotsSummary()); }*/ ui->pPushButton->setText(axis->getPAxisButton()->getSlotsSummary()); } void AxisEditDialog::checkFinalSettings() { if (axis->getThrottle() != initialThrottleState) { setAxisThrottleConfirm->exec(); } } void AxisEditDialog::selectAxisCurrentPreset() { JoyAxisButton *naxisbutton = axis->getNAxisButton(); QList *naxisslots = naxisbutton->getAssignedSlots(); JoyAxisButton *paxisbutton = axis->getPAxisButton(); QList *paxisslots = paxisbutton->getAssignedSlots(); if (naxisslots->length() == 1 && paxisslots->length() == 1) { JoyButtonSlot *nslot = naxisslots->at(0); JoyButtonSlot *pslot = paxisslots->at(0); if (nslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && nslot->getSlotCode() == JoyButtonSlot::MouseLeft && pslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && pslot->getSlotCode() == JoyButtonSlot::MouseRight) { ui->presetsComboBox->setCurrentIndex(1); } else if (nslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && nslot->getSlotCode() == JoyButtonSlot::MouseRight && pslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && pslot->getSlotCode() == JoyButtonSlot::MouseLeft) { ui->presetsComboBox->setCurrentIndex(2); } else if (nslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && nslot->getSlotCode() == JoyButtonSlot::MouseUp && pslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && pslot->getSlotCode() == JoyButtonSlot::MouseDown) { ui->presetsComboBox->setCurrentIndex(3); } else if (nslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && nslot->getSlotCode() == JoyButtonSlot::MouseDown && pslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && pslot->getSlotCode() == JoyButtonSlot::MouseUp) { ui->presetsComboBox->setCurrentIndex(4); } else if (nslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)nslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Up) && pslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)pslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Down)) { ui->presetsComboBox->setCurrentIndex(5); } else if (nslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)nslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Left) && pslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)pslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Right)) { ui->presetsComboBox->setCurrentIndex(6); } else if (nslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)nslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_W) && pslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)pslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_S)) { ui->presetsComboBox->setCurrentIndex(7); } else if (nslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)nslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_A) && pslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)pslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_D)) { ui->presetsComboBox->setCurrentIndex(8); } else if (nslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)nslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_8) && pslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)pslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_2)) { ui->presetsComboBox->setCurrentIndex(9); } else if (nslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)nslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_4) && pslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)pslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_6)) { ui->presetsComboBox->setCurrentIndex(10); } else { ui->presetsComboBox->setCurrentIndex(0); } } else if (naxisslots->length() == 0 && paxisslots->length() == 0) { ui->presetsComboBox->setCurrentIndex(11); } else { ui->presetsComboBox->setCurrentIndex(0); } } void AxisEditDialog::selectTriggerPreset() { JoyAxisButton *paxisbutton = axis->getPAxisButton(); QList *paxisslots = paxisbutton->getAssignedSlots(); if (paxisslots->length() == 1) { JoyButtonSlot *pslot = paxisslots->at(0); if (pslot->getSlotMode() == JoyButtonSlot::JoyMouseButton && pslot->getSlotCode() == JoyButtonSlot::MouseLB) { ui->presetsComboBox->setCurrentIndex(1); } else if (pslot->getSlotMode() == JoyButtonSlot::JoyMouseButton && pslot->getSlotCode() == JoyButtonSlot::MouseRB) { ui->presetsComboBox->setCurrentIndex(2); } else { ui->presetsComboBox->setCurrentIndex(0); } } else if (paxisslots->length() == 0) { ui->presetsComboBox->setCurrentIndex(3); } else { ui->presetsComboBox->setCurrentIndex(0); } } void AxisEditDialog::implementTriggerPresets(int index) { JoyButtonSlot *pbuttonslot = 0; if (index == 1) { pbuttonslot = new JoyButtonSlot(JoyButtonSlot::MouseLB, JoyButtonSlot::JoyMouseButton, this); } else if (index == 2) { pbuttonslot = new JoyButtonSlot(JoyButtonSlot::MouseRB, JoyButtonSlot::JoyMouseButton, this); } else if (index == 3) { JoyAxisButton *nbutton = axis->getNAxisButton(); JoyAxisButton *pbutton = axis->getPAxisButton(); QMetaObject::invokeMethod(nbutton, "clearSlotsEventReset"); QMetaObject::invokeMethod(pbutton, "clearSlotsEventReset", Qt::BlockingQueuedConnection); refreshNButtonLabel(); refreshPButtonLabel(); } if (pbuttonslot) { JoyAxisButton *nbutton = axis->getNAxisButton(); JoyAxisButton *pbutton = axis->getPAxisButton(); if (nbutton->getAssignedSlots()->length() > 0) { QMetaObject::invokeMethod(nbutton, "clearSlotsEventReset", Qt::BlockingQueuedConnection, Q_ARG(bool, false)); refreshNButtonLabel(); } QMetaObject::invokeMethod(pbutton, "clearSlotsEventReset", Q_ARG(bool, false)); QMetaObject::invokeMethod(pbutton, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, pbuttonslot->getSlotCode()), Q_ARG(unsigned int, pbuttonslot->getSlotCodeAlias()), Q_ARG(JoyButtonSlot::JoySlotInputAction, pbuttonslot->getSlotMode())); refreshPButtonLabel(); pbuttonslot->deleteLater(); } } void AxisEditDialog::refreshPreset() { // Disconnect event associated with presetsComboBox so a change in the index does not // alter the axis buttons disconnect(ui->presetsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(implementPresets(int))); selectAxisCurrentPreset(); // Reconnect the event connect(ui->presetsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(implementPresets(int))); } void AxisEditDialog::openMouseSettingsDialog() { ui->mouseSettingsPushButton->setEnabled(false); MouseAxisSettingsDialog *dialog = new MouseAxisSettingsDialog(this->axis, this); dialog->show(); connect(this, SIGNAL(finished(int)), dialog, SLOT(close())); connect(dialog, SIGNAL(finished(int)), this, SLOT(enableMouseSettingButton())); } void AxisEditDialog::enableMouseSettingButton() { ui->mouseSettingsPushButton->setEnabled(true); } void AxisEditDialog::updateWindowTitleAxisName() { QString temp = QString(tr("Set")).append(" "); if (!axis->getAxisName().isEmpty()) { temp.append(axis->getPartialName(false, true)); } else { temp.append(axis->getPartialName()); } if (axis->getParentSet()->getIndex() != 0) { unsigned int setIndex = axis->getParentSet()->getRealIndex(); temp.append(" [").append(tr("Set %1").arg(setIndex)); QString setName = axis->getParentSet()->getName(); if (!setName.isEmpty()) { temp.append(": ").append(setName); } temp.append("]"); } setWindowTitle(temp); } void AxisEditDialog::buildAxisPresetsMenu() { ui->presetsComboBox->clear(); ui->presetsComboBox->addItem(tr("")); ui->presetsComboBox->addItem(tr("Mouse (Horizontal)")); ui->presetsComboBox->addItem(tr("Mouse (Inverted Horizontal)")); ui->presetsComboBox->addItem(tr("Mouse (Vertical)")); ui->presetsComboBox->addItem(tr("Mouse (Inverted Vertical)")); ui->presetsComboBox->addItem(tr("Arrows: Up | Down")); ui->presetsComboBox->addItem(tr("Arrows: Left | Right")); ui->presetsComboBox->addItem(tr("Keys: W | S")); ui->presetsComboBox->addItem(tr("Keys: A | D")); ui->presetsComboBox->addItem(tr("NumPad: KP_8 | KP_2")); ui->presetsComboBox->addItem(tr("NumPad: KP_4 | KP_6")); ui->presetsComboBox->addItem(tr("None")); } void AxisEditDialog::buildTriggerPresetsMenu() { ui->presetsComboBox->clear(); ui->presetsComboBox->addItem(tr("")); ui->presetsComboBox->addItem(tr("Left Mouse Button")); ui->presetsComboBox->addItem(tr("Right Mouse Button")); ui->presetsComboBox->addItem(tr("None")); } void AxisEditDialog::presetForThrottleChange(int index) { Q_UNUSED(index); bool actAsTrigger = false; int currentThrottle = axis->getThrottle(); if (currentThrottle == JoyAxis::PositiveThrottle || currentThrottle == JoyAxis::PositiveHalfThrottle) { actAsTrigger = true; } disconnect(ui->presetsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(implementPresets(int))); if (actAsTrigger) { buildTriggerPresetsMenu(); selectTriggerPreset(); } else { buildAxisPresetsMenu(); selectAxisCurrentPreset(); } connect(ui->presetsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(implementPresets(int))); } antimicro-2.23/src/axiseditdialog.h000066400000000000000000000041451300750276700173720ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef AXISEDITDIALOG_H #define AXISEDITDIALOG_H #include #include "joyaxis.h" #include "axisvaluebox.h" #include "setaxisthrottledialog.h" namespace Ui { class AxisEditDialog; } class AxisEditDialog : public QDialog { Q_OBJECT public: explicit AxisEditDialog(JoyAxis *axis, QWidget *parent=0); ~AxisEditDialog(); protected: void selectAxisCurrentPreset(); void selectTriggerPreset(); void buildTriggerPresetsMenu(); void buildAxisPresetsMenu(); JoyAxis *axis; SetAxisThrottleDialog *setAxisThrottleConfirm; int initialThrottleState; private: Ui::AxisEditDialog *ui; private slots: void implementAxisPresets(int index); void implementTriggerPresets(int index); void implementPresets(int index); void presetForThrottleChange(int index); void updateDeadZoneBox(int value); void updateMaxZoneBox(int value); void updateThrottleUi(int index); void updateJoyValue(int value); void updateDeadZoneSlider(QString value); void updateMaxZoneSlider(QString value); void openAdvancedPDialog(); void openAdvancedNDialog(); void refreshPButtonLabel(); void refreshNButtonLabel(); void refreshPreset(); void checkFinalSettings(); void openMouseSettingsDialog(); void enableMouseSettingButton(); void updateWindowTitleAxisName(); }; #endif // AXISEDITDIALOG_H antimicro-2.23/src/axiseditdialog.ui000066400000000000000000000353251300750276700175640ustar00rootroot00000000000000 AxisEditDialog 0 0 511 369 0 0 0 0 16777215 16777215 Axis false true 10 1 Presets: false false 12 12 Mouse (Horizontal) Mouse (Inverted Horizontal) Mouse (Vertical) Mouse (Inverted Vertical) Arrows: Up | Down Arrows: Left | Right Keys: W | S Keys: A | D NumPad: KP_8 | KP_2 NumPad: KP_4 | KP_6 None Qt::Vertical QSizePolicy::Fixed 20 20 10 10 10 0 0 100 16777215 false false Set the value to use as the limit for an axis. Useful for a worn out analog stick. 5 false Dead Zone: Set the value of the dead zone for an axis. 0 32737 100 1000 5000 5000 true Qt::Horizontal false false QSlider::NoTicks 1000 true 0 0 100 16777215 false false Set the value of the dead zone for an axis. 5 true false Set the value to use as the limit for an axis. Useful for a worn out analog stick. 0 32737 100 1000 32000 Qt::Horizontal QSlider::NoTicks 1000 Max Zone: [NO KEY] Throttle setting that determines the behavior of how to interpret an axis hold or release. 2 5 5 Negative Half Throttle Negative Throttle Normal Positive Throttle Positive Half Throttle [NO KEY] 0 0 0 25 16777215 25 10 0 0 Current Value: 0 4 0 0 Qt::Vertical QSizePolicy::Fixed 20 20 Name: axisNameLineEdit Specify the name of an axis. Mouse Settings Qt::Horizontal Qt::Horizontal QDialogButtonBox::Close false buttonBox line axisstatusBox verticalSpacer mouseSettingsPushButton verticalSpacer_2 AxisValueBox QWidget
axisvaluebox.h
1
buttonBox accepted() AxisEditDialog accept() 248 254 157 274 buttonBox rejected() AxisEditDialog reject() 316 260 286 274
antimicro-2.23/src/axisvaluebox.cpp000066400000000000000000000131331300750276700174420ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "axisvaluebox.h" #include "joyaxis.h" AxisValueBox::AxisValueBox(QWidget *parent) : QWidget(parent) { deadZone = 0; maxZone = 0; joyValue = 0; throttle = 0; lboxstart = 0; lboxend = 0; rboxstart = 0; rboxend = 0; } void AxisValueBox::setThrottle(int throttle) { if (throttle <= JoyAxis::PositiveHalfThrottle && throttle >= JoyAxis::NegativeHalfThrottle) { this->throttle = throttle; setValue(joyValue); } update(); } void AxisValueBox::setValue(int value) { if (value >= JoyAxis::AXISMIN && value <= JoyAxis::AXISMAX) { if (throttle == JoyAxis::NormalThrottle) { this->joyValue = value; } else if (throttle == JoyAxis::NegativeThrottle) { this->joyValue = (value + JoyAxis::AXISMIN) / 2; } else if (throttle == JoyAxis::PositiveThrottle) { this->joyValue = (value + JoyAxis::AXISMAX) / 2; } else if (throttle == JoyAxis::NegativeHalfThrottle) { this->joyValue = value <= 0 ? value : -value; } else if (throttle == JoyAxis::PositiveHalfThrottle) { this->joyValue = value >= 0 ? value : -value; } } update(); } void AxisValueBox::setDeadZone(int deadZone) { if (deadZone >= JoyAxis::AXISMIN && deadZone <= JoyAxis::AXISMAX) { this->deadZone = deadZone; } update(); } int AxisValueBox::getDeadZone() { return deadZone; } void AxisValueBox::setMaxZone(int maxZone) { if (maxZone >= JoyAxis::AXISMIN && maxZone <= JoyAxis::AXISMAX) { this->maxZone = maxZone; } update(); } int AxisValueBox::getMaxZone() { return maxZone; } int AxisValueBox::getJoyValue() { return joyValue; } int AxisValueBox::getThrottle() { return throttle; } void AxisValueBox::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); boxwidth = (this->width() / 2) - 5; boxheight = this->height() - 4; lboxstart = 0; lboxend = lboxstart + boxwidth; rboxstart = lboxend + 10; rboxend = rboxstart + boxwidth; singlewidth = this->width(); singleend = lboxstart + singlewidth; } void AxisValueBox::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter paint (this); paint.setPen(palette().base().color()); paint.setBrush(palette().base().color()); QBrush brush(palette().light().color()); if (throttle == 0) { qDrawShadeRect(&paint, lboxstart, 0, lboxend, height(), palette(), true, 2, 0, &brush); qDrawShadeRect(&paint, rboxstart, 0, rboxend, height(), palette(), true, 2, 0, &brush); } else { qDrawShadeRect(&paint, lboxstart, 0, singlewidth, height(), palette(), true, 2, 0, &brush); } QColor innerColor; if (abs(joyValue) <= deadZone) { innerColor = Qt::gray; } else if (abs(joyValue) >= maxZone) { innerColor = Qt::red; } else { innerColor = Qt::blue; } paint.setPen(innerColor); paint.setBrush(innerColor); int barwidth = (throttle == 0) ? boxwidth : singlewidth; int barlength = abs((barwidth - 2) * joyValue) / JoyAxis::AXISMAX; if (joyValue > 0) { paint.drawRect(((throttle == 0) ? rboxstart : lboxstart) + 2, 2, barlength, boxheight); } else if (joyValue < 0) { paint.drawRect(lboxstart + barwidth - 2 - barlength, 2, barlength, boxheight); } // Draw marker for deadZone int deadLine = abs((barwidth - 2) * deadZone) / JoyAxis::AXISMAX; int maxLine = abs((barwidth - 2) * maxZone) / JoyAxis::AXISMAX; paint.setPen(Qt::blue); brush.setColor(Qt::blue); QBrush maxBrush(Qt::red); if (throttle == JoyAxis::NormalThrottle) { qDrawPlainRect(&paint, rboxstart + 2 + deadLine, 2, 4, boxheight + 2, Qt::black, 1, &brush); qDrawPlainRect(&paint, lboxend - deadLine - 2, 2, 4, boxheight + 2, Qt::black, 1, &brush); paint.setPen(Qt::red); qDrawPlainRect(&paint, rboxstart + 2 + maxLine, 2, 4, boxheight + 2, Qt::black, 1, &maxBrush); qDrawPlainRect(&paint, lboxend - maxLine - 2, 2, 4, boxheight + 2, Qt::black, 1, &maxBrush); } else if (throttle == JoyAxis::PositiveThrottle || JoyAxis::PositiveHalfThrottle) { qDrawPlainRect(&paint, lboxstart + deadLine - 2, 2, 4, boxheight + 2, Qt::black, 1, &brush); paint.setPen(Qt::red); qDrawPlainRect(&paint, lboxstart + maxLine, 2, 4, boxheight + 2, Qt::black, 1, &maxBrush); } else if (throttle == JoyAxis::NegativeThrottle || throttle == JoyAxis::NegativeHalfThrottle) { qDrawPlainRect(&paint, singleend - deadLine - 2, 2, 4, boxheight + 2, Qt::black, 1, &brush); paint.setPen(Qt::red); qDrawPlainRect(&paint, singleend - maxLine, 2, 4, boxheight + 2, Qt::black, 1, &maxBrush); } } antimicro-2.23/src/axisvaluebox.h000066400000000000000000000030161300750276700171060ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef AXISVALUEBOX_H #define AXISVALUEBOX_H #include class AxisValueBox : public QWidget { Q_OBJECT public: explicit AxisValueBox(QWidget *parent = 0); int getDeadZone(); int getMaxZone(); int getJoyValue(); int getThrottle(); protected: virtual void resizeEvent(QResizeEvent *event); virtual void paintEvent(QPaintEvent *event); int deadZone; int maxZone; int joyValue; int throttle; int boxwidth; int boxheight; int lboxstart; int lboxend; int rboxstart; int rboxend; int singlewidth; int singleend; signals: public slots: void setThrottle(int throttle); void setValue(int value); void setDeadZone(int deadZone); void setMaxZone(int maxZone); }; #endif // AXISVALUEBOX_H antimicro-2.23/src/buttoneditdialog.cpp000066400000000000000000000352671300750276700203050ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #ifdef Q_OS_WIN #include #include "winextras.h" #else #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include #endif #endif #include "buttoneditdialog.h" #include "ui_buttoneditdialog.h" #include "event.h" #include "antkeymapper.h" #include "eventhandlerfactory.h" #include "setjoystick.h" #include "inputdevice.h" #include "common.h" ButtonEditDialog::ButtonEditDialog(JoyButton *button, QWidget *parent) : QDialog(parent, Qt::Window), ui(new Ui::ButtonEditDialog), helper(button) { ui->setupUi(this); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) setMinimumHeight(460); #endif setAttribute(Qt::WA_DeleteOnClose); setWindowModality(Qt::WindowModal); ignoreRelease = false; helper.moveToThread(button->thread()); PadderCommon::inputDaemonMutex.lock(); this->button = button; ui->virtualKeyMouseTabWidget->hide(); ui->virtualKeyMouseTabWidget->deleteLater(); ui->virtualKeyMouseTabWidget = new VirtualKeyboardMouseWidget(button, this); ui->verticalLayout->insertWidget(1, ui->virtualKeyMouseTabWidget); //ui->virtualKeyMouseTabWidget->setFocus(); ui->slotSummaryLabel->setText(button->getSlotsString()); updateWindowTitleButtonName(); ui->toggleCheckBox->setChecked(button->getToggleState()); ui->turboCheckBox->setChecked(button->isUsingTurbo()); if (!button->getActionName().isEmpty()) { ui->actionNameLineEdit->setText(button->getActionName()); } if (!button->getButtonName().isEmpty()) { ui->buttonNameLineEdit->setText(button->getButtonName()); } PadderCommon::inputDaemonMutex.unlock(); connect(qApp, SIGNAL(focusChanged(QWidget*,QWidget*)), this, SLOT(checkForKeyboardWidgetFocus(QWidget*,QWidget*))); connect(ui->virtualKeyMouseTabWidget, SIGNAL(selectionCleared()), this, SLOT(refreshSlotSummaryLabel())); connect(ui->virtualKeyMouseTabWidget, SIGNAL(selectionFinished()), this, SLOT(close())); connect(this, SIGNAL(keyGrabbed(JoyButtonSlot*)), this, SLOT(processSlotAssignment(JoyButtonSlot*))); connect(this, SIGNAL(selectionCleared()), this, SLOT(clearButtonSlots())); connect(this, SIGNAL(selectionCleared()), this, SLOT(sendSelectionFinished())); connect(this, SIGNAL(selectionFinished()), this, SLOT(close())); connect(ui->toggleCheckBox, SIGNAL(clicked()), this, SLOT(changeToggleSetting())); connect(ui->turboCheckBox, SIGNAL(clicked()), this, SLOT(changeTurboSetting())); connect(ui->advancedPushButton, SIGNAL(clicked()), this, SLOT(openAdvancedDialog())); connect(this, SIGNAL(advancedDialogOpened()), ui->virtualKeyMouseTabWidget, SLOT(establishVirtualKeyboardAdvancedSignalConnections())); connect(this, SIGNAL(advancedDialogOpened()), ui->virtualKeyMouseTabWidget, SLOT(establishVirtualMouseAdvancedSignalConnections())); //connect(ui->virtualKeyMouseTabWidget, SIGNAL(selectionMade(int)), this, SLOT(createTempSlot(int))); connect(ui->actionNameLineEdit, SIGNAL(textEdited(QString)), button, SLOT(setActionName(QString))); connect(ui->buttonNameLineEdit, SIGNAL(textEdited(QString)), button, SLOT(setButtonName(QString))); connect(button, SIGNAL(toggleChanged(bool)), ui->toggleCheckBox, SLOT(setChecked(bool))); connect(button, SIGNAL(turboChanged(bool)), this, SLOT(checkTurboSetting(bool))); connect(button, SIGNAL(slotsChanged()), this, SLOT(refreshSlotSummaryLabel())); connect(button, SIGNAL(buttonNameChanged()), this, SLOT(updateWindowTitleButtonName())); } void ButtonEditDialog::checkForKeyboardWidgetFocus(QWidget *old, QWidget *now) { Q_UNUSED(old); Q_UNUSED(now); if (ui->virtualKeyMouseTabWidget->hasFocus() && ui->virtualKeyMouseTabWidget->isKeyboardTabVisible()) { grabKeyboard(); } else { releaseKeyboard(); } } ButtonEditDialog::~ButtonEditDialog() { delete ui; } void ButtonEditDialog::keyPressEvent(QKeyEvent *event) { bool ignore = false; // Ignore the following keys that might // trigger an event in QDialog::keyPressEvent switch(event->key()) { case Qt::Key_Escape: case Qt::Key_Right: case Qt::Key_Enter: case Qt::Key_Return: { ignore = true; break; } } if (!ignore) { QDialog::keyPressEvent(event); } } void ButtonEditDialog::keyReleaseEvent(QKeyEvent *event) { if (ui->actionNameLineEdit->hasFocus() || ui->buttonNameLineEdit->hasFocus()) { QDialog::keyReleaseEvent(event); } else if (ui->virtualKeyMouseTabWidget->isKeyboardTabVisible()) { int controlcode = event->nativeScanCode(); int virtualactual = event->nativeVirtualKey(); BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); #ifdef Q_OS_WIN int finalvirtual = 0; int checkalias = 0; #ifdef WITH_VMULTI if (handler->getIdentifier() == "vmulti") { finalvirtual = WinExtras::correctVirtualKey(controlcode, virtualactual); checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual); //unsigned int tempQtKey = nativeWinKeyMapper.returnQtKey(finalvirtual); QtKeyMapperBase *nativeWinKeyMapper = AntKeyMapper::getInstance()->getNativeKeyMapper(); unsigned int tempQtKey = 0; if (nativeWinKeyMapper) { tempQtKey = nativeWinKeyMapper->returnQtKey(finalvirtual); } if (tempQtKey > 0) { finalvirtual = AntKeyMapper::getInstance()->returnVirtualKey(tempQtKey); checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual); } else { finalvirtual = AntKeyMapper::getInstance()->returnVirtualKey(event->key()); } } #endif BACKEND_ELSE_IF (handler->getIdentifier() == "sendinput") { // Find more specific virtual key (VK_SHIFT -> VK_LSHIFT) // by checking for extended bit in scan code. finalvirtual = WinExtras::correctVirtualKey(controlcode, virtualactual); checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual, controlcode); } #else #if defined(WITH_X11) int finalvirtual = 0; int checkalias = 0; #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif // Obtain group 1 X11 keysym. Removes effects from modifiers. finalvirtual = X11KeyCodeToX11KeySym(controlcode); #ifdef WITH_UINPUT if (handler->getIdentifier() == "uinput") { // Find Qt Key corresponding to X11 KeySym. //checkalias = x11KeyMapper.returnQtKey(finalvirtual); Q_ASSERT(AntKeyMapper::getInstance()->hasNativeKeyMapper()); QtKeyMapperBase *x11KeyMapper = AntKeyMapper::getInstance()->getNativeKeyMapper(); Q_ASSERT(x11KeyMapper != NULL); checkalias = x11KeyMapper->returnQtKey(finalvirtual); // Find corresponding Linux input key for the Qt key. finalvirtual = AntKeyMapper::getInstance()->returnVirtualKey(checkalias); } #endif #ifdef WITH_XTEST BACKEND_ELSE_IF (handler->getIdentifier() == "xtest") { // Check for alias against group 1 keysym. checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual); } #endif #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } else { // Not running on xcb platform. finalvirtual = controlcode; checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual); } #endif #else int finalvirtual = 0; int checkalias = 0; #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif finalvirtual = AntKeyMapper::getInstance()->returnVirtualKey(event->key()); checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } else { // Not running on xcb platform. finalvirtual = controlcode; checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual); } #endif #endif #endif if (!ignoreRelease) { if ((event->modifiers() & Qt::ControlModifier) && event->key() == Qt::Key_X) { controlcode = 0; ignoreRelease = true; emit selectionCleared(); } else if (controlcode <= 0) { controlcode = 0; } } else { controlcode = 0; ignoreRelease = false; } if (controlcode > 0) { if (checkalias > 0 && finalvirtual > 0) { JoyButtonSlot *tempslot = new JoyButtonSlot(finalvirtual, checkalias, JoyButtonSlot::JoyKeyboard, this); emit keyGrabbed(tempslot); } else if (virtualactual > 0) { JoyButtonSlot *tempslot = new JoyButtonSlot(virtualactual, JoyButtonSlot::JoyKeyboard, this); emit keyGrabbed(tempslot); } else { QDialog::keyReleaseEvent(event); } } else { QDialog::keyReleaseEvent(event); } } else { QDialog::keyReleaseEvent(event); } } void ButtonEditDialog::refreshSlotSummaryLabel() { ui->slotSummaryLabel->setText(button->getSlotsString().replace("&", "&&")); } void ButtonEditDialog::changeToggleSetting() { button->setToggle(ui->toggleCheckBox->isChecked()); } void ButtonEditDialog::changeTurboSetting() { button->setUseTurbo(ui->turboCheckBox->isChecked()); } void ButtonEditDialog::openAdvancedDialog() { ui->advancedPushButton->setEnabled(false); AdvanceButtonDialog *dialog = new AdvanceButtonDialog(button, this); dialog->show(); // Disconnect event to allow for placing slot to AdvanceButtonDialog disconnect(this, SIGNAL(keyGrabbed(JoyButtonSlot*)), 0, 0); disconnect(this, SIGNAL(selectionCleared()), 0, 0); disconnect(this, SIGNAL(selectionFinished()), 0, 0); connect(dialog, SIGNAL(finished(int)), ui->virtualKeyMouseTabWidget, SLOT(establishVirtualKeyboardSingleSignalConnections())); connect(dialog, SIGNAL(finished(int)), ui->virtualKeyMouseTabWidget, SLOT(establishVirtualMouseSignalConnections())); connect(dialog, SIGNAL(finished(int)), this, SLOT(closedAdvancedDialog())); connect(dialog, SIGNAL(turboButtonEnabledChange(bool)), this, SLOT(setTurboButtonEnabled(bool))); connect(this, SIGNAL(sendTempSlotToAdvanced(JoyButtonSlot*)), dialog, SLOT(placeNewSlot(JoyButtonSlot*))); connect(this, SIGNAL(keyGrabbed(JoyButtonSlot*)), dialog, SLOT(placeNewSlot(JoyButtonSlot*))); connect(this, SIGNAL(selectionCleared()), dialog, SLOT(clearAllSlots())); connect(ui->virtualKeyMouseTabWidget, SIGNAL(selectionMade(JoyButtonSlot*)), dialog, SLOT(placeNewSlot(JoyButtonSlot*))); connect(ui->virtualKeyMouseTabWidget, SIGNAL(selectionMade(int, unsigned int)), this, SLOT(createTempSlot(int, unsigned int))); connect(ui->virtualKeyMouseTabWidget, SIGNAL(selectionCleared()), dialog, SLOT(clearAllSlots())); connect(this, SIGNAL(finished(int)), dialog, SLOT(close())); emit advancedDialogOpened(); } void ButtonEditDialog::createTempSlot(int keycode, unsigned int alias) { JoyButtonSlot *slot = new JoyButtonSlot(keycode, alias, JoyButtonSlot::JoyKeyboard, this); emit sendTempSlotToAdvanced(slot); } void ButtonEditDialog::checkTurboSetting(bool state) { if (button->containsSequence()) { ui->turboCheckBox->setChecked(false); ui->turboCheckBox->setEnabled(false); } else { ui->turboCheckBox->setChecked(state); ui->turboCheckBox->setEnabled(true); } helper.setUseTurbo(state); } void ButtonEditDialog::setTurboButtonEnabled(bool state) { ui->turboCheckBox->setEnabled(state); } void ButtonEditDialog::closedAdvancedDialog() { ui->advancedPushButton->setEnabled(true); disconnect(ui->virtualKeyMouseTabWidget, SIGNAL(selectionMade(int, unsigned int)), this, 0); // Re-connect previously disconnected event connect(this, SIGNAL(keyGrabbed(JoyButtonSlot*)), this, SLOT(processSlotAssignment(JoyButtonSlot*))); connect(this, SIGNAL(selectionCleared()), this, SLOT(clearButtonSlots())); connect(this, SIGNAL(selectionCleared()), this, SLOT(sendSelectionFinished())); connect(this, SIGNAL(selectionFinished()), this, SLOT(close())); } void ButtonEditDialog::processSlotAssignment(JoyButtonSlot *tempslot) { QMetaObject::invokeMethod(&helper, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, tempslot->getSlotCode()), Q_ARG(unsigned int, tempslot->getSlotCodeAlias()), Q_ARG(JoyButtonSlot::JoySlotInputAction, tempslot->getSlotMode())); this->close(); tempslot->deleteLater(); } void ButtonEditDialog::clearButtonSlots() { QMetaObject::invokeMethod(button, "clearSlotsEventReset", Q_ARG(bool, false)); } void ButtonEditDialog::sendSelectionFinished() { emit selectionFinished(); } void ButtonEditDialog::updateWindowTitleButtonName() { QString temp = QString(tr("Set")).append(" ").append(button->getPartialName(false, true)); if (button->getParentSet()->getIndex() != 0) { unsigned int setIndex = button->getParentSet()->getRealIndex(); temp.append(" [").append(tr("Set %1").arg(setIndex)); QString setName = button->getParentSet()->getName(); if (!setName.isEmpty()) { temp.append(": ").append(setName); } temp.append("]"); } setWindowTitle(temp); } antimicro-2.23/src/buttoneditdialog.h000066400000000000000000000042631300750276700177420ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BUTTONEDITDIALOGTWO_H #define BUTTONEDITDIALOGTWO_H #include #include "joybutton.h" #include "keyboard/virtualkeyboardmousewidget.h" #include "advancebuttondialog.h" #include "uihelpers/buttoneditdialoghelper.h" namespace Ui { class ButtonEditDialog; } class ButtonEditDialog : public QDialog { Q_OBJECT public: explicit ButtonEditDialog(JoyButton *button, QWidget *parent = 0); ~ButtonEditDialog(); protected: JoyButton *button; bool ignoreRelease; ButtonEditDialogHelper helper; virtual void keyReleaseEvent(QKeyEvent *event); virtual void keyPressEvent(QKeyEvent *event); private: Ui::ButtonEditDialog *ui; signals: void advancedDialogOpened(); void sendTempSlotToAdvanced(JoyButtonSlot *tempslot); void keyGrabbed(JoyButtonSlot *tempslot); void selectionCleared(); void selectionFinished(); private slots: void refreshSlotSummaryLabel(); void changeToggleSetting(); void changeTurboSetting(); void openAdvancedDialog(); void closedAdvancedDialog(); void createTempSlot(int keycode, unsigned int alias); void checkTurboSetting(bool state); void setTurboButtonEnabled(bool state); void processSlotAssignment(JoyButtonSlot *tempslot); void clearButtonSlots(); void sendSelectionFinished(); void updateWindowTitleButtonName(); void checkForKeyboardWidgetFocus(QWidget *old, QWidget *now); }; #endif // BUTTONEDITDIALOGTWO_H antimicro-2.23/src/buttoneditdialog.ui000066400000000000000000000207601300750276700201300ustar00rootroot00000000000000 ButtonEditDialog Qt::WindowModal 0 0 800 430 800 430 Dialog false false 0 0 1 To make a new assignment, press any keyboard key or click a button in the Keyboard or Mouse tab false Qt::AlignCenter true QTabWidget::South 0 false Placeholder Qt::Vertical QSizePolicy::Fixed 20 4 Enables a key press or release to only occur when a controller button is pressed. Toggle Qt::Horizontal QSizePolicy::Fixed 20 20 Enables rapid key presses and releases. Turbo controller. Turbo Qt::Horizontal QSizePolicy::Expanding 20 20 75 true Current: Slots false 30 6 6 4 Na&me: buttonNameLineEdit Specify the name of a button. 20 4 Action: actionNameLineEdit Specify the action that will be performed in game while this button is being used. 50 Qt::Horizontal 4 Advanced Qt::Horizontal QDialogButtonBox::Close VirtualKeyboardMouseWidget QTabWidget
keyboard/virtualkeyboardmousewidget.h
1
buttonBox accepted() ButtonEditDialog accept() 248 254 157 274 buttonBox rejected() ButtonEditDialog reject() 316 260 286 274
antimicro-2.23/src/capturedwindowinfodialog.cpp000066400000000000000000000120141300750276700220200ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "capturedwindowinfodialog.h" #include "ui_capturedwindowinfodialog.h" #ifdef Q_OS_WIN #include "winextras.h" #else #include "x11extras.h" #endif #ifdef Q_OS_WIN CapturedWindowInfoDialog::CapturedWindowInfoDialog(QWidget *parent) : #else CapturedWindowInfoDialog::CapturedWindowInfoDialog(unsigned long window, QWidget *parent) : #endif QDialog(parent), ui(new Ui::CapturedWindowInfoDialog) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); selectedMatch = WindowNone; #ifdef Q_OS_UNIX X11Extras *info = X11Extras::getInstance(); ui->winPathChoiceComboBox->setVisible(false); #endif bool setRadioDefault = false; fullWinPath = false; #ifdef Q_OS_WIN ui->winClassCheckBox->setVisible(false); ui->winClassLabel->setVisible(false); ui->winClassHeadLabel->setVisible(false); #else winClass = info->getWindowClass(window); ui->winClassLabel->setText(winClass); if (winClass.isEmpty()) { ui->winClassCheckBox->setEnabled(false); ui->winClassCheckBox->setChecked(false); } else { ui->winClassCheckBox->setChecked(true); setRadioDefault = true; } ui->winPathChoiceComboBox->setVisible(false); #endif #ifdef Q_OS_WIN winName = WinExtras::getCurrentWindowText(); #else winName = info->getWindowTitle(window); #endif ui->winTitleLabel->setText(winName); if (winName.isEmpty()) { ui->winTitleCheckBox->setEnabled(false); ui->winTitleCheckBox->setChecked(false); } else if (!setRadioDefault) { ui->winTitleCheckBox->setChecked(true); setRadioDefault = true; } ui->winPathLabel->clear(); #ifdef Q_OS_WIN winPath = WinExtras::getForegroundWindowExePath(); ui->winPathLabel->setText(winPath); if (winPath.isEmpty()) { ui->winPathCheckBox->setEnabled(false); ui->winPathCheckBox->setChecked(false); } else { ui->winPathCheckBox->setChecked(true); ui->winTitleCheckBox->setChecked(false); setRadioDefault = true; } #elif defined(Q_OS_LINUX) int pid = info->getApplicationPid(window); if (pid > 0) { QString exepath = X11Extras::getInstance()->getApplicationLocation(pid); if (!exepath.isEmpty()) { ui->winPathLabel->setText(exepath); winPath = exepath; if (!setRadioDefault) { ui->winTitleCheckBox->setChecked(true); setRadioDefault = true; } } else { ui->winPathCheckBox->setEnabled(false); ui->winPathCheckBox->setChecked(false); } } else { ui->winPathCheckBox->setEnabled(false); ui->winPathCheckBox->setChecked(false); } #endif if (winClass.isEmpty() && winName.isEmpty() && winPath.isEmpty()) { QPushButton *button = ui->buttonBox->button(QDialogButtonBox::Ok); button->setEnabled(false); } connect(this, SIGNAL(accepted()), this, SLOT(populateOption())); } CapturedWindowInfoDialog::~CapturedWindowInfoDialog() { delete ui; } void CapturedWindowInfoDialog::populateOption() { if (ui->winClassCheckBox->isChecked()) { selectedMatch = selectedMatch | WindowClass; } if (ui->winTitleCheckBox->isChecked()) { selectedMatch = selectedMatch | WindowName; } if (ui->winPathCheckBox->isChecked()) { selectedMatch = selectedMatch | WindowPath; if (ui->winPathChoiceComboBox->currentIndex() == 0) { fullWinPath = true; } else { fullWinPath = false; } } } CapturedWindowInfoDialog::CapturedWindowOption CapturedWindowInfoDialog::getSelectedOptions() { return selectedMatch; } QString CapturedWindowInfoDialog::getWindowClass() { return winClass; } QString CapturedWindowInfoDialog::getWindowName() { return winName; } QString CapturedWindowInfoDialog::getWindowPath() { return winPath; } bool CapturedWindowInfoDialog::useFullWindowPath() { return fullWinPath; } antimicro-2.23/src/capturedwindowinfodialog.h000066400000000000000000000035221300750276700214710ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UNIXWINDOWINFODIALOG_H #define UNIXWINDOWINFODIALOG_H #include #include namespace Ui { class CapturedWindowInfoDialog; } class CapturedWindowInfoDialog : public QDialog { Q_OBJECT public: #ifdef Q_OS_WIN explicit CapturedWindowInfoDialog(QWidget *parent = 0); #else explicit CapturedWindowInfoDialog(unsigned long window, QWidget *parent = 0); #endif ~CapturedWindowInfoDialog(); enum { WindowNone = 0, WindowClass = (1 << 0), WindowName = (1 << 1), WindowPath = (1 << 2), }; typedef unsigned int CapturedWindowOption; QString getWindowClass(); QString getWindowName(); QString getWindowPath(); bool useFullWindowPath(); CapturedWindowOption getSelectedOptions(); private: Ui::CapturedWindowInfoDialog *ui; protected: CapturedWindowOption selectedMatch; QString winClass; QString winName; QString winPath; bool fullWinPath; private slots: void populateOption(); }; #endif // UNIXWINDOWINFODIALOG_H antimicro-2.23/src/capturedwindowinfodialog.ui000066400000000000000000000140221300750276700216540ustar00rootroot00000000000000 CapturedWindowInfoDialog 0 0 533 363 Captured Window Properties 20 50 false Information About Window true 20 Class: true TextLabel Title: true TextLabel Path: true TextLabel Match By Properties true false false Class Title Path true Full Path File Name Qt::Vertical 20 40 Qt::Horizontal Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() CapturedWindowInfoDialog accept() 248 254 157 274 buttonBox rejected() CapturedWindowInfoDialog reject() 316 260 286 274 antimicro-2.23/src/commandlineutility.cpp000066400000000000000000000645131300750276700206520ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include #ifdef Q_OS_UNIX #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include #endif #endif #include "commandlineutility.h" #include "common.h" #include "eventhandlerfactory.h" QRegExp CommandLineUtility::trayRegexp = QRegExp("--tray"); QRegExp CommandLineUtility::helpRegexp = QRegExp("(-h|--help)"); QRegExp CommandLineUtility::versionRegexp = QRegExp("(-v|--version)"); QRegExp CommandLineUtility::noTrayRegexp = QRegExp("--no-tray"); QRegExp CommandLineUtility::loadProfileRegexp = QRegExp("--profile"); QRegExp CommandLineUtility::loadProfileForControllerRegexp = QRegExp("--profile-controller"); QRegExp CommandLineUtility::hiddenRegexp = QRegExp("--hidden"); QRegExp CommandLineUtility::unloadRegexp = QRegExp("--unload"); QRegExp CommandLineUtility::startSetRegexp = QRegExp("--startSet"); QRegExp CommandLineUtility::gamepadListRegexp = QRegExp("(-l|--list)"); QRegExp CommandLineUtility::mappingRegexp = QRegExp("--map"); QRegExp CommandLineUtility::qtStyleRegexp = QRegExp("-style"); QRegExp CommandLineUtility::logLevelRegexp = QRegExp("--log-level"); QRegExp CommandLineUtility::logFileRegexp = QRegExp("--log-file"); QRegExp CommandLineUtility::eventgenRegexp = QRegExp("--eventgen"); QRegExp CommandLineUtility::nextRegexp = QRegExp("--next"); #ifdef Q_OS_UNIX QRegExp CommandLineUtility::daemonRegexp = QRegExp("--daemon|-d"); #ifdef WITH_X11 QRegExp CommandLineUtility::displayRegexp = QRegExp("--display"); #endif #endif QStringList CommandLineUtility::eventGeneratorsList = EventHandlerFactory::buildEventGeneratorList(); CommandLineUtility::CommandLineUtility(QObject *parent) : QObject(parent) { launchInTray = false; helpRequest = false; versionRequest = false; hideTrayIcon = false; profileLocation = ""; controllerNumber = 0; encounteredError = false; hiddenRequest = false; unloadProfile = false; startSetNumber = 0; daemonMode = false; displayString = ""; listControllers = false; mappingController = false; currentLogLevel = Logger::LOG_NONE; currentListsIndex = 0; ControllerOptionsInfo tempInfo; controllerOptionsList.append(tempInfo); eventGenerator = EventHandlerFactory::fallBackIdentifier(); } void CommandLineUtility::parseArguments(QStringList &arguments) { QStringListIterator iter(arguments); while (iter.hasNext() && !encounteredError) { QString temp = iter.next(); if (helpRegexp.exactMatch(temp)) { helpRequest = true; } else if (versionRegexp.exactMatch(temp)) { versionRequest = true; } else if (trayRegexp.exactMatch(temp)) { launchInTray = true; hideTrayIcon = false; } else if (noTrayRegexp.exactMatch(temp)) { hideTrayIcon = true; launchInTray = false; } else if (loadProfileRegexp.exactMatch(temp)) { if (iter.hasNext()) { temp = iter.next(); QFileInfo fileInfo(temp); if (fileInfo.exists()) { if (fileInfo.suffix() != "amgp" && fileInfo.suffix() != "xml") { setErrorMessage(tr("Profile location %1 is not an XML file.").arg(temp)); } else { QString tempProfileLocation = fileInfo.absoluteFilePath(); ControllerOptionsInfo tempInfo = controllerOptionsList.at(currentListsIndex); tempInfo.setProfileLocation(tempProfileLocation); controllerOptionsList.replace(currentListsIndex, tempInfo); } } else { setErrorMessage(tr("Profile location %1 does not exist.").arg(temp)); } } } else if (loadProfileForControllerRegexp.exactMatch(temp)) { if (iter.hasNext()) { temp = iter.next(); bool validNumber = false; int tempNumber = temp.toInt(&validNumber); if (validNumber) { if (controllerNumber == 0) { controllerNumber = tempNumber; } ControllerOptionsInfo tempInfo = controllerOptionsList.at(currentListsIndex); tempInfo.setControllerNumber(tempNumber); controllerOptionsList.replace(currentListsIndex, tempInfo); } else if (!temp.isEmpty()) { if (controllerIDString.isEmpty()) { controllerIDString = temp; } ControllerOptionsInfo tempInfo = controllerOptionsList.at(currentListsIndex); tempInfo.setControllerID(temp); controllerOptionsList.replace(currentListsIndex, tempInfo); } else { setErrorMessage(tr("Controller identifier is not a valid value.")); } } } else if (hiddenRegexp.exactMatch(temp)) { hiddenRequest = true; } else if (unloadRegexp.exactMatch(temp)) { ControllerOptionsInfo tempInfo = controllerOptionsList.at(currentListsIndex); tempInfo.setProfileLocation(""); tempInfo.setUnloadRequest(true); controllerOptionsList.replace(currentListsIndex, tempInfo); if (iter.hasNext()) { temp = iter.next(); if (!isPossibleCommand(temp)) { // A value has been passed. Attempt // to validate the value. bool validNumber = false; int tempNumber = temp.toInt(&validNumber); if (validNumber) { controllerNumber = tempNumber; tempInfo = controllerOptionsList.at(currentListsIndex); tempInfo.setControllerNumber(controllerNumber); controllerOptionsList.replace(currentListsIndex, tempInfo); } else if (!temp.isEmpty()) { controllerIDString = temp; tempInfo = controllerOptionsList.at(currentListsIndex); tempInfo.setControllerID(controllerIDString); controllerOptionsList.replace(currentListsIndex, tempInfo); } else { setErrorMessage(tr("Controller identifier is not a valid value.")); } } else { // Grabbed a possible command-line option. // Move iterator back to previous item. iter.previous(); } } else { unloadProfile = true; profileLocation = ""; } } else if (startSetRegexp.exactMatch(temp)) { if (iter.hasNext()) { temp = iter.next(); bool validNumber = false; int tempNumber = temp.toInt(&validNumber); if (validNumber && tempNumber >= 1 && tempNumber <= 8) { startSetNumber = tempNumber; ControllerOptionsInfo tempInfo = controllerOptionsList.at(currentListsIndex); tempInfo.setStartSetNumber(startSetNumber); controllerOptionsList.replace(currentListsIndex, tempInfo); } else if (validNumber) { setErrorMessage(tr("An invalid set number '%1' was specified.").arg(tempNumber)); } if (iter.hasNext()) { temp = iter.next(); if (!isPossibleCommand(temp)) { if (validNumber) { controllerNumber = tempNumber; ControllerOptionsInfo tempInfo = controllerOptionsList.at(currentListsIndex); tempInfo.setControllerNumber(controllerNumber); controllerOptionsList.replace(currentListsIndex, tempInfo); } else if (!temp.isEmpty()) { controllerIDString = temp; ControllerOptionsInfo tempInfo = controllerOptionsList.at(currentListsIndex); tempInfo.setControllerID(controllerIDString); controllerOptionsList.replace(currentListsIndex, tempInfo); } else { setErrorMessage(tr("Controller identifier '%s'' is not a valid value.").arg(temp)); } } else { // Grabbed a possible command-line option. // Move iterator back to previous item. iter.previous(); } } } else { setErrorMessage(tr("No set number was specified.")); } } else if (nextRegexp.exactMatch(temp)) { currentListsIndex++; ControllerOptionsInfo tempInfo; controllerOptionsList.append(tempInfo); } #ifdef USE_SDL_2 else if (gamepadListRegexp.exactMatch(temp)) { listControllers = true; } else if (mappingRegexp.exactMatch(temp)) { if (iter.hasNext()) { temp = iter.next(); bool validNumber = false; int tempNumber = temp.toInt(&validNumber); if (validNumber) { controllerNumber = tempNumber; mappingController = true; } else if (!temp.isEmpty()) { controllerIDString = temp; mappingController = true; } else { setErrorMessage(tr("Controller identifier is not a valid value.")); } } else { setErrorMessage(tr("No controller was specified.")); } } #endif #ifdef Q_OS_UNIX else if (daemonRegexp.exactMatch(temp)) { daemonMode = true; } #ifdef WITH_X11 else if (displayRegexp.exactMatch(temp)) { if (iter.hasNext()) { displayString = iter.next(); } else { setErrorMessage(tr("No display string was specified.")); //errorsteam << tr("No display string was specified.") << endl; //encounteredError = true; } } #endif #endif #if (defined (Q_OS_UNIX) && defined(WITH_UINPUT) && defined(WITH_XTEST)) \ || (defined(Q_OS_WIN) && defined(WITH_VMULTI)) else if (eventgenRegexp.exactMatch(temp)) { if (iter.hasNext()) { QString temp = iter.next(); if (!eventGeneratorsList.contains(temp)) { eventGenerator = ""; setErrorMessage(tr("An invalid event generator was specified.")); //errorsteam << tr("An invalid event generator was specified.") << endl; //encounteredError = true; } else { eventGenerator = temp; } } else { setErrorMessage(tr("No event generator string was specified.")); //errorsteam << tr("No event generator string was specified.") << endl; //encounteredError = true; } } #endif else if (qtStyleRegexp.exactMatch(temp)) { if (iter.hasNext()) { // Skip over argument iter.next(); } else { setErrorMessage(tr("Qt style flag was detected but no style was specified.")); //errorsteam << tr("Qt style flag was detected but no style was specified.") << endl; //encounteredError = true; } } else if (logLevelRegexp.exactMatch(temp)) { if (iter.hasNext()) { QString temp = iter.next(); if (temp == "debug") { currentLogLevel = Logger::LOG_DEBUG; } else if (temp == "info") { currentLogLevel = Logger::LOG_INFO; } /*else if (temp == "warn") { currentLogLevel = Logger::LOG_WARNING; } else if (temp == "error") { currentLogLevel = Logger::LOG_ERROR; } */ } } else if (logFileRegexp.exactMatch(temp)) { if (iter.hasNext()) { currentLogFile = iter.next(); } else { setErrorMessage(tr("No log file specified.")); //errorsteam << tr("No log level specified.") << endl; //encounteredError = true; } } else if (isPossibleCommand(temp)) { // Flag is unrecognized. Assume that it is a Qt option. if (iter.hasNext()) { // Check next argument QString nextarg = iter.next(); if (isPossibleCommand(nextarg)) { // Flag likely didn't take an argument. Move iterator // back. iter.previous(); } } } // Check if this is the last argument. If it is and no command line flag // is active, the final argument is likely a profile that has // been specified. else if (!temp.isEmpty() && !iter.hasNext()) { // If the file exists and it is an xml file, assume that it is a // profile. QFileInfo fileInfo(temp); if (fileInfo.exists()) { if (fileInfo.suffix() != "amgp" && fileInfo.suffix() != "xml") { setErrorMessage(tr("Profile location %1 is not an XML file.").arg(temp)); } else { profileLocation = fileInfo.absoluteFilePath(); // Only use properties if no other OptionsInfo lines have // been defined. if (currentListsIndex > 0) { controllerNumber = 0; controllerIDString.clear(); } } } else { setErrorMessage(tr("Profile location %1 does not exist.").arg(temp)); } } } } bool CommandLineUtility::isLaunchInTrayEnabled() { return launchInTray; } void CommandLineUtility::printHelp() { QTextStream out(stdout); out << tr("antimicro version") << " " << PadderCommon::programVersion << endl; out << tr("Usage: antimicro [options...] [profile]") << endl; out << endl; out << tr("Options") << ":" << endl; out << "-h, --help " << " " << tr("Print help text.") << endl; out << "-v, --version " << " " << tr("Print version information.") << endl; out << "--tray " << " " << tr("Launch program in system tray only.") << endl; out << "--no-tray " << " " << tr("Launch program with the tray menu disabled.") << endl; out << "--hidden " << " " << tr("Launch program without the main window\n displayed.") << endl; out << "--profile " << " " << tr("Launch program with the configuration file\n selected as the default for selected\n controllers. Defaults to all controllers.") << endl; out << "--profile-controller " << " " << tr("Apply configuration file to a specific\n controller. Value can be a\n controller index, name, or GUID.") << endl; out << "--unload [] " << " " << tr("Unload currently enabled profile(s). \n Value can be a controller index, name, or GUID.") << endl; out << "--startSet [] " << " " << tr("Start joysticks on a specific set. \n Value can be a controller index, name, or GUID.") << endl; out << "--next " << " " << tr("Advance profile loading set options.") << endl; #ifdef Q_OS_UNIX out << "-d, --daemon " << " " << tr("Launch program as a daemon.") << endl; out << "--log-level {debug,info} " << " " << tr("Enable logging.") << endl; #ifdef WITH_X11 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif out << "--display " << " " << tr("Use specified display for X11 calls.\n" " Useful for ssh.") << endl; #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #endif #endif #if defined(Q_OS_UNIX) && defined(WITH_UINPUT) && defined(WITH_XTEST) out << "--eventgen {xtest,uinput} " << " " << tr("Choose between using XTest support and uinput\n" " support for event generation. Default: xtest.") << endl; #elif defined(Q_OS_WIN) && defined(WITH_VMULTI) out << "--eventgen {sendinput,vmulti} " << " " << tr("Choose between using SendInput and vmulti\n" " support for event generation. Default: sendinput.") << endl; #endif #ifdef USE_SDL_2 out << "-l, --list " << " " << tr("Print information about joysticks detected by \n" " SDL.") << endl; out << "--map " << " " << tr("Open game controller mapping window of selected\n" " controller. Value can be a controller index or\n" " GUID.") << endl; #endif } QString CommandLineUtility::generateHelpString() { QString temp; QTextStream out(&temp); out << tr("antimicro version") << " " << PadderCommon::programVersion << endl; out << tr("Usage: antimicro [options...] [profile]") << endl; out << endl; out << tr("Options") << ":" << endl; out << "-h, --help " << " " << tr("Print help text.") << endl; out << "-v, --version " << " " << tr("Print version information.") << endl; out << "--tray " << " " << tr("Launch program in system tray only.") << endl; out << "--no-tray " << " " << tr("Launch program with the tray menu disabled.") << endl; out << "--hidden " << " " << tr("Launch program without the main window\n displayed.") << endl; out << "--profile " << " " << tr("Launch program with the configuration file\n selected as the default for selected\n controllers. Defaults to all controllers.") << endl; out << "--profile-controller " << " " << tr("Apply configuration file to a specific\n controller. Value can be a\n controller index, name, or GUID.") << endl; out << "--unload [] " << " " << tr("Unload currently enabled profile(s). \n Value can be a controller index, name, or GUID.") << endl; out << "--startSet [] " << " " << tr("Start joysticks on a specific set. \n Value can be a controller index, name, or GUID.") << endl; out << "--next " << " " << tr("Advance profile loading set options.") << endl; #ifdef Q_OS_UNIX out << "-d, --daemon " << " " << tr("Launch program as a daemon.") << endl; out << "--log-level {debug,info} " << " " << tr("Enable logging.") << endl; #ifdef WITH_X11 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif out << "--display " << " " << tr("Use specified display for X11 calls.\n" " Useful for ssh.") << endl; #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #endif #endif #if defined(Q_OS_UNIX) && defined(WITH_UINPUT) && defined(WITH_XTEST) out << "--eventgen {xtest,uinput} " << " " << tr("Choose between using XTest support and uinput\n" " support for event generation. Default: xtest.") << endl; #elif defined(Q_OS_WIN) && defined(WITH_VMULTI) out << "--eventgen {sendinput,vmulti} " << " " << tr("Choose between using SendInput and vmulti\n" " support for event generation. Default: sendinput.") << endl; #endif #ifdef USE_SDL_2 out << "-l, --list " << " " << tr("Print information about joysticks detected by \n" " SDL.") << endl; out << "--map " << " " << tr("Open game controller mapping window of selected\n" " controller. Value can be a controller index or\n" " GUID.") << endl; #endif return temp; } bool CommandLineUtility::isHelpRequested() { return helpRequest; } bool CommandLineUtility::isVersionRequested() { return versionRequest; } void CommandLineUtility::printVersionString() { QTextStream out(stdout); out << tr("antimicro version") << " " << PadderCommon::programVersion << endl; } QString CommandLineUtility::generateVersionString() { QString temp; QTextStream out(&temp); out << tr("antimicro version") << " " << PadderCommon::programVersion; return temp; } bool CommandLineUtility::isTrayHidden() { return hideTrayIcon; } bool CommandLineUtility::hasProfile() { return !profileLocation.isEmpty(); } bool CommandLineUtility::hasControllerNumber() { return (controllerNumber > 0); } QString CommandLineUtility::getProfileLocation() { return profileLocation; } unsigned int CommandLineUtility::getControllerNumber() { return controllerNumber; } bool CommandLineUtility::hasError() { return encounteredError; } bool CommandLineUtility::isHiddenRequested() { return hiddenRequest; } bool CommandLineUtility::hasControllerID() { return !controllerIDString.isEmpty(); } QString CommandLineUtility::getControllerID() { return controllerIDString; } bool CommandLineUtility::isUnloadRequested() { return unloadProfile; } unsigned int CommandLineUtility::getStartSetNumber() { return startSetNumber; } unsigned int CommandLineUtility::getJoyStartSetNumber() { return startSetNumber - 1; } bool CommandLineUtility::isPossibleCommand(QString temp) { bool result = false; if (temp.startsWith("--") || temp.startsWith("-")) { result = true; } return result; } bool CommandLineUtility::shouldListControllers() { return listControllers; } bool CommandLineUtility::shouldMapController() { return mappingController; } QString CommandLineUtility::getEventGenerator() { return eventGenerator; } #ifdef Q_OS_UNIX bool CommandLineUtility::launchAsDaemon() { return daemonMode; } QString CommandLineUtility::getDisplayString() { return displayString; } #endif Logger::LogLevel CommandLineUtility::getCurrentLogLevel() { return currentLogLevel; } QString CommandLineUtility::getCurrentLogFile() { return currentLogFile; } QString CommandLineUtility::getErrorText() { return errorText; } void CommandLineUtility::setErrorMessage(QString temp) { errorText = temp; encounteredError = true; } QList* CommandLineUtility::getControllerOptionsList() { return &controllerOptionsList; } bool CommandLineUtility::hasProfileInOptions() { bool result = false; QListIterator iter(controllerOptionsList); while (iter.hasNext()) { ControllerOptionsInfo temp = iter.next(); if (temp.hasProfile()) { result = true; iter.toBack(); } } return result; } antimicro-2.23/src/commandlineutility.h000066400000000000000000000120571300750276700203130ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef COMMANDLINEPARSER_H #define COMMANDLINEPARSER_H #include #include #include #include #include "logger.h" class ControllerOptionsInfo { public: ControllerOptionsInfo() { controllerNumber = 0; startSetNumber = 0; unloadProfile = false; } bool hasProfile() { return !profileLocation.isEmpty(); } QString getProfileLocation() { return profileLocation; } void setProfileLocation(QString location) { profileLocation = location; } bool hasControllerNumber() { return (controllerNumber > 0); } unsigned int getControllerNumber() { return controllerNumber; } void setControllerNumber(unsigned int temp) { controllerNumber = temp; } bool hasControllerID() { return !controllerIDString.isEmpty(); } QString getControllerID() { return controllerIDString; } void setControllerID(QString temp) { controllerIDString = temp; } bool isUnloadRequested() { return unloadProfile; } void setUnloadRequest(bool status) { unloadProfile = status; } unsigned int getStartSetNumber() { return startSetNumber; } unsigned int getJoyStartSetNumber() { return startSetNumber - 1; } void setStartSetNumber(unsigned int temp) { if (temp >= 1 && temp <= 8) { startSetNumber = temp; } } protected: QString profileLocation; unsigned int controllerNumber; QString controllerIDString; unsigned int startSetNumber; bool unloadProfile; }; class CommandLineUtility : public QObject { Q_OBJECT public: explicit CommandLineUtility(QObject *parent = 0); void parseArguments(QStringList &arguments); bool isLaunchInTrayEnabled(); bool isHelpRequested(); bool isVersionRequested(); bool isTrayHidden(); bool hasProfile(); bool hasControllerNumber(); bool hasControllerID(); QString getProfileLocation(); unsigned int getControllerNumber(); QString getControllerID(); bool isHiddenRequested(); bool isUnloadRequested(); bool shouldListControllers(); bool shouldMapController(); unsigned int getStartSetNumber(); unsigned int getJoyStartSetNumber(); QList* getJoyStartSetNumberList(); QList* getControllerOptionsList(); bool hasProfileInOptions(); QString getEventGenerator(); #ifdef Q_OS_UNIX bool launchAsDaemon(); QString getDisplayString(); #endif void printHelp(); void printVersionString(); QString generateHelpString(); QString generateVersionString(); bool hasError(); Logger::LogLevel getCurrentLogLevel(); QString getCurrentLogFile(); QString getErrorText(); protected: bool isPossibleCommand(QString temp); void setErrorMessage(QString temp); bool launchInTray; bool helpRequest; bool versionRequest; bool hideTrayIcon; QString profileLocation; unsigned int controllerNumber; QString controllerIDString; bool encounteredError; bool hiddenRequest; bool unloadProfile; unsigned int startSetNumber; bool daemonMode; QString displayString; bool listControllers; bool mappingController; QString eventGenerator; QString errorText; Logger::LogLevel currentLogLevel; QString currentLogFile; unsigned int currentListsIndex; QList controllerOptionsList; static QRegExp trayRegexp; static QRegExp helpRegexp; static QRegExp versionRegexp; static QRegExp noTrayRegexp; static QRegExp loadProfileRegexp; static QRegExp loadProfileForControllerRegexp; static QRegExp hiddenRegexp; static QRegExp unloadRegexp; static QRegExp startSetRegexp; static QRegExp gamepadListRegexp; static QRegExp mappingRegexp; static QRegExp qtStyleRegexp; static QRegExp logLevelRegexp; static QRegExp logFileRegexp; static QRegExp eventgenRegexp; static QRegExp nextRegexp; static QStringList eventGeneratorsList; #ifdef Q_OS_UNIX static QRegExp daemonRegexp; static QRegExp displayRegexp; #endif signals: public slots: }; #endif // COMMANDLINEPARSER_H antimicro-2.23/src/common.cpp000066400000000000000000000126701300750276700162250ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #ifdef Q_OS_WIN #include #endif #include "common.h" namespace PadderCommon { QString preferredProfileDir(AntiMicroSettings *settings) { QString lastProfileDir = settings->value("LastProfileDir", "").toString(); QString defaultProfileDir = settings->value("DefaultProfileDir", "").toString(); QString lookupDir; if (!defaultProfileDir.isEmpty()) { QFileInfo dirinfo(defaultProfileDir); if (dirinfo.isDir() && dirinfo.isReadable()) { lookupDir = defaultProfileDir; } } if (lookupDir.isEmpty() && !lastProfileDir.isEmpty()) { QFileInfo dirinfo(lastProfileDir); if (dirinfo.isDir() && dirinfo.isReadable()) { lookupDir = lastProfileDir; } } if (lookupDir.isEmpty()) { #ifdef Q_OS_WIN #ifdef WIN_PORTABLE_PACKAGE QString portableProDir = QDir::currentPath().append("/profiles"); QFileInfo portableProDirInfo(portableProDir); if (portableProDirInfo.isDir() && portableProDirInfo.isReadable()) { lookupDir = portableProDir; } else { lookupDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); } #else lookupDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); #endif #else lookupDir = QDir::homePath(); #endif } return lookupDir; } QStringList arguments(int &argc, char **argv) { QStringList list; for (int a = 0; a < argc; ++a) { list << QString::fromLocal8Bit(argv[a]); } return list; } QStringList parseArgumentsString(QString tempString) { bool inside = (!tempString.isEmpty() && tempString.at(0) == QChar('"')); QStringList tempList = tempString.split(QRegExp("\""), QString::SkipEmptyParts); QStringList finalList; QStringListIterator iter(tempList); while (iter.hasNext()) { QString temp = iter.next(); if (inside) { finalList.append(temp); } else { finalList.append(temp.split(QRegExp("\\s+"), QString::SkipEmptyParts)); } inside = !inside; } return finalList; } /** * @brief Reload main application and base Qt translation files. * @param Based Qt translator * @param Application translator * @param Language code */ void reloadTranslations(QTranslator *translator, QTranslator *appTranslator, QString language) { // Remove application specific translation strings qApp->removeTranslator(translator); // Remove old Qt translation strings qApp->removeTranslator(appTranslator); // Load new Qt translation strings #if defined(Q_OS_UNIX) translator->load(QString("qt_").append(language), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); #elif defined(Q_OS_WIN) #ifdef QT_DEBUG translator->load(QString("qt_").append(language), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); #else translator->load(QString("qt_").append(language), QApplication::applicationDirPath().append("\\share\\qt\\translations")); #endif #endif qApp->installTranslator(appTranslator); // Load application specific translation strings #if defined(Q_OS_UNIX) translator->load("antimicro_" + language, QApplication::applicationDirPath().append("/../share/antimicro/translations")); #elif defined(Q_OS_WIN) translator->load("antimicro_" + language, QApplication::applicationDirPath().append("\\share\\antimicro\\translations")); #endif qApp->installTranslator(translator); } void lockInputDevices() { sdlWaitMutex.lock(); /*editingLock.lockForWrite(); editingBindings = true; editingLock.unlock(); waitMutex.lock(); //editingBindings = true; waitThisOut.wait(&waitMutex); */ } void unlockInputDevices() { sdlWaitMutex.unlock(); /*editingLock.lockForWrite(); editingBindings = false; editingLock.unlock(); waitMutex.unlock(); */ } QWaitCondition waitThisOut; QMutex sdlWaitMutex; QMutex inputDaemonMutex; QReadWriteLock editingLock; bool editingBindings = false; MouseHelper mouseHelperObj; } antimicro-2.23/src/common.h000066400000000000000000000121341300750276700156650ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef COMMON_H #define COMMON_H #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "antimicrosettings.h" #include "mousehelper.h" #ifdef Q_OS_WIN static QString findWinSystemConfigPath() { QString temp; temp = (!qgetenv("LocalAppData").isEmpty()) ? QString::fromUtf8(qgetenv("LocalAppData")) + "/antimicro" : QDir::homePath() + "/.antimicro"; return temp; } static QString findWinLocalConfigPath() { QString temp = QCoreApplication::applicationDirPath(); return temp; } static QString findWinDefaultConfigPath() { QString temp = findWinLocalConfigPath(); QFileInfo dirInfo(temp); if (!dirInfo.isWritable()) { temp = findWinSystemConfigPath(); } return temp; } static QString findWinConfigPath(QString configFileName) { QString temp; QFileInfo localConfigInfo(findWinLocalConfigPath().append("/").append(configFileName)); QFileInfo systemConfigInfo(findWinSystemConfigPath().append("/").append(configFileName)); if (localConfigInfo.exists() && localConfigInfo.isWritable()) { temp = localConfigInfo.absoluteFilePath(); } else if (systemConfigInfo.exists() && systemConfigInfo.isWritable()) { temp = systemConfigInfo.absoluteFilePath(); } else { temp = findWinDefaultConfigPath().append("/").append(configFileName); } return temp; } #endif namespace PadderCommon { inline QString configPath() { #if defined(Q_OS_WIN) && defined(WIN_PORTABLE_PACKAGE) return findWinLocalConfigPath(); #elif defined(Q_OS_WIN) return findWinSystemConfigPath(); #else return (!qgetenv("XDG_CONFIG_HOME").isEmpty()) ? QString::fromUtf8(qgetenv("XDG_CONFIG_HOME")) + "/antimicro" : QDir::homePath() + "/.config/antimicro"; #endif } const QString configFileName = "antimicro_settings.ini"; inline QString configFilePath() { #if defined(Q_OS_WIN) && defined(WIN_PORTABLE_PACKAGE) return QString(configPath()).append("/").append(configFileName); #elif defined(Q_OS_WIN) return QString(configPath()).append("/").append(configFileName); #else return QString(configPath()).append("/").append(configFileName); #endif } const int LATESTCONFIGFILEVERSION = 19; // Specify the last known profile version that requires a migration // to be performed in order to be compatible with the latest version. const int LATESTCONFIGMIGRATIONVERSION = 5; const QString localSocketKey = "antimicroSignalListener"; const QString githubProjectPage = "https://github.com/AntiMicro/antimicro"; const QString wikiPage = QString("%1/wiki").arg(githubProjectPage); const QString mouseDeviceName("antimicro Mouse Emulation"); const QString keyboardDeviceName("antimicro Keyboard Emulation"); const QString springMouseDeviceName("antimicro Abs Mouse Emulation"); const int ANTIMICRO_MAJOR_VERSION = PROJECT_MAJOR_VERSION; const int ANTIMICRO_MINOR_VERSION = PROJECT_MINOR_VERSION; const int ANTIMICRO_PATCH_VERSION = PROJECT_PATCH_VERSION; const QString programVersion = (ANTIMICRO_PATCH_VERSION > 0) ? QString("%1.%2.%3").arg(ANTIMICRO_MAJOR_VERSION) .arg(ANTIMICRO_MINOR_VERSION).arg(ANTIMICRO_PATCH_VERSION) : QString("%1.%2").arg(ANTIMICRO_MAJOR_VERSION) .arg(ANTIMICRO_MINOR_VERSION); extern QWaitCondition waitThisOut; extern QMutex sdlWaitMutex; extern QMutex inputDaemonMutex; extern bool editingBindings; extern QReadWriteLock editingLock; extern MouseHelper mouseHelperObj; QString preferredProfileDir(AntiMicroSettings *settings); QStringList arguments(int &argc, char **argv); QStringList parseArgumentsString(QString tempString); void reloadTranslations(QTranslator *translator, QTranslator *appTranslator, QString language); void lockInputDevices(); void unlockInputDevices(); /*! * \brief Returns the "human-readable" name of the given profile. */ inline QString getProfileName(QFileInfo& profile) { QString retVal = profile.completeBaseName(); return retVal; } } Q_DECLARE_METATYPE(QThread*) #endif // COMMON_H antimicro-2.23/src/config.h.in000066400000000000000000000003371300750276700162510ustar00rootroot00000000000000#ifndef CONFIG_H #define CONFIG_H #define PROJECT_MAJOR_VERSION @ANTIMICRO_MAJOR_VERSION@ #define PROJECT_MINOR_VERSION @ANTIMICRO_MINOR_VERSION@ #define PROJECT_PATCH_VERSION @ANTIMICRO_PATCH_VERSION@ #endif // CONFIG_H antimicro-2.23/src/dpadcontextmenu.cpp000066400000000000000000000514441300750276700201410ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "dpadcontextmenu.h" #include "mousedialog/mousedpadsettingsdialog.h" #include "antkeymapper.h" #include "inputdevice.h" #include "common.h" DPadContextMenu::DPadContextMenu(JoyDPad *dpad, QWidget *parent) : QMenu(parent), helper(dpad) { this->dpad = dpad; helper.moveToThread(dpad->thread()); connect(this, SIGNAL(aboutToHide()), this, SLOT(deleteLater())); } /** * @brief Generate the context menu that will be shown to a user when the person * right clicks on the DPad settings button. */ void DPadContextMenu::buildMenu() { QAction *action = 0; QActionGroup *presetGroup = new QActionGroup(this); int presetMode = 0; int currentPreset = getPresetIndex(); action = this->addAction(tr("Mouse (Normal)")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setDPadPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("Mouse (Inverted Horizontal)")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setDPadPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("Mouse (Inverted Vertical)")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setDPadPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("Mouse (Inverted Horizontal + Vertical)")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setDPadPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("Arrows")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setDPadPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("Keys: W | A | S | D")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setDPadPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("NumPad")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setDPadPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("None")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setDPadPreset())); presetGroup->addAction(action); this->addSeparator(); QActionGroup *modesGroup = new QActionGroup(this); int mode = (int)JoyDPad::StandardMode; action = this->addAction(tr("Standard")); action->setCheckable(true); action->setChecked(dpad->getJoyMode() == JoyDPad::StandardMode); action->setData(QVariant(mode)); connect(action, SIGNAL(triggered()), this, SLOT(setDPadMode())); modesGroup->addAction(action); action = this->addAction(tr("Eight Way")); action->setCheckable(true); action->setChecked(dpad->getJoyMode() == JoyDPad::EightWayMode); mode = (int)JoyDPad::EightWayMode; action->setData(QVariant(mode)); connect(action, SIGNAL(triggered()), this, SLOT(setDPadMode())); modesGroup->addAction(action); action = this->addAction(tr("4 Way Cardinal")); action->setCheckable(true); action->setChecked(dpad->getJoyMode() == JoyDPad::FourWayCardinal); mode = (int)JoyDPad::FourWayCardinal; action->setData(QVariant(mode)); connect(action, SIGNAL(triggered()), this, SLOT(setDPadMode())); modesGroup->addAction(action); action = this->addAction(tr("4 Way Diagonal")); action->setCheckable(true); action->setChecked(dpad->getJoyMode() == JoyDPad::FourWayDiagonal); mode = (int)JoyDPad::FourWayDiagonal; action->setData(QVariant(mode)); connect(action, SIGNAL(triggered()), this, SLOT(setDPadMode())); modesGroup->addAction(action); this->addSeparator(); action = this->addAction(tr("Mouse Settings")); action->setCheckable(false); connect(action, SIGNAL(triggered()), this, SLOT(openMouseSettingsDialog())); } /** * @brief Set the appropriate mode for a DPad based on the item chosen. */ void DPadContextMenu::setDPadMode() { QAction *action = static_cast(sender()); int item = action->data().toInt(); dpad->setJoyMode((JoyDPad::JoyMode)item); } /** * @brief Assign the appropriate slots to DPad buttons based on the preset item * that was chosen. */ void DPadContextMenu::setDPadPreset() { QAction *action = static_cast(sender()); int item = action->data().toInt(); JoyButtonSlot *upButtonSlot = 0; JoyButtonSlot *downButtonSlot = 0; JoyButtonSlot *leftButtonSlot = 0; JoyButtonSlot *rightButtonSlot = 0; JoyButtonSlot *upLeftButtonSlot = 0; JoyButtonSlot *upRightButtonSlot = 0; JoyButtonSlot *downLeftButtonSlot = 0; JoyButtonSlot *downRightButtonSlot = 0; if (item == 0) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); downButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); leftButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); rightButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); dpad->setJoyMode(JoyDPad::StandardMode); PadderCommon::inputDaemonMutex.unlock(); } else if (item == 1) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); downButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); leftButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); rightButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); dpad->setJoyMode(JoyDPad::StandardMode); PadderCommon::inputDaemonMutex.unlock(); } else if (item == 2) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); downButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); leftButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); rightButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); dpad->setJoyMode(JoyDPad::StandardMode); PadderCommon::inputDaemonMutex.unlock(); } else if (item == 3) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); downButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); leftButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); rightButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); dpad->setJoyMode(JoyDPad::StandardMode); PadderCommon::inputDaemonMutex.unlock(); } else if (item == 4) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Up), Qt::Key_Up, JoyButtonSlot::JoyKeyboard, this); downButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Down), Qt::Key_Down, JoyButtonSlot::JoyKeyboard, this); leftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Left), Qt::Key_Left, JoyButtonSlot::JoyKeyboard, this); rightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Right), Qt::Key_Right, JoyButtonSlot::JoyKeyboard, this); dpad->setJoyMode(JoyDPad::StandardMode); PadderCommon::inputDaemonMutex.unlock(); } else if (item == 5) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_W), Qt::Key_W, JoyButtonSlot::JoyKeyboard, this); downButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_S), Qt::Key_S, JoyButtonSlot::JoyKeyboard, this); leftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_A), Qt::Key_A, JoyButtonSlot::JoyKeyboard, this); rightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_D), Qt::Key_D, JoyButtonSlot::JoyKeyboard, this); dpad->setJoyMode(JoyDPad::StandardMode); PadderCommon::inputDaemonMutex.unlock(); } else if (item == 6) { PadderCommon::inputDaemonMutex.lock(); if (dpad->getJoyMode() == JoyDPad::StandardMode || dpad->getJoyMode() == JoyDPad::FourWayCardinal) { upButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_8), QtKeyMapperBase::AntKey_KP_8, JoyButtonSlot::JoyKeyboard, this); downButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_2), QtKeyMapperBase::AntKey_KP_2, JoyButtonSlot::JoyKeyboard, this); leftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_4), QtKeyMapperBase::AntKey_KP_4, JoyButtonSlot::JoyKeyboard, this); rightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_6), QtKeyMapperBase::AntKey_KP_6, JoyButtonSlot::JoyKeyboard, this); } else if (dpad->getJoyMode() == JoyDPad::EightWayMode) { upButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_8), QtKeyMapperBase::AntKey_KP_8, JoyButtonSlot::JoyKeyboard, this); downButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_2), QtKeyMapperBase::AntKey_KP_2, JoyButtonSlot::JoyKeyboard, this); leftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_4), QtKeyMapperBase::AntKey_KP_4, JoyButtonSlot::JoyKeyboard, this); rightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_6), QtKeyMapperBase::AntKey_KP_6, JoyButtonSlot::JoyKeyboard, this); upLeftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_7), QtKeyMapperBase::AntKey_KP_7, JoyButtonSlot::JoyKeyboard, this); upRightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_9), QtKeyMapperBase::AntKey_KP_9, JoyButtonSlot::JoyKeyboard, this); downLeftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_1), QtKeyMapperBase::AntKey_KP_1, JoyButtonSlot::JoyKeyboard, this); downRightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_3), QtKeyMapperBase::AntKey_KP_3, JoyButtonSlot::JoyKeyboard, this); } else if (dpad->getJoyMode() == JoyDPad::FourWayDiagonal) { upLeftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_7), QtKeyMapperBase::AntKey_KP_7, JoyButtonSlot::JoyKeyboard, this); upRightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_9), QtKeyMapperBase::AntKey_KP_9, JoyButtonSlot::JoyKeyboard, this); downLeftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_1), QtKeyMapperBase::AntKey_KP_1, JoyButtonSlot::JoyKeyboard, this); downRightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_3), QtKeyMapperBase::AntKey_KP_3, JoyButtonSlot::JoyKeyboard, this); } PadderCommon::inputDaemonMutex.unlock(); } else if (item == 7) { QMetaObject::invokeMethod(&helper, "clearButtonsSlotsEventReset", Qt::BlockingQueuedConnection); } QHash tempHash; tempHash.insert(JoyDPadButton::DpadUp, upButtonSlot); tempHash.insert(JoyDPadButton::DpadDown, downButtonSlot); tempHash.insert(JoyDPadButton::DpadLeft, leftButtonSlot); tempHash.insert(JoyDPadButton::DpadRight, rightButtonSlot); tempHash.insert(JoyDPadButton::DpadLeftUp, upLeftButtonSlot); tempHash.insert(JoyDPadButton::DpadRightUp, upRightButtonSlot); tempHash.insert(JoyDPadButton::DpadLeftDown, downLeftButtonSlot); tempHash.insert(JoyDPadButton::DpadRightDown, downRightButtonSlot); helper.setPendingSlots(&tempHash); QMetaObject::invokeMethod(&helper, "setFromPendingSlots", Qt::BlockingQueuedConnection); } /** * @brief Find the appropriate menu item index for the currently assigned * slots that are assigned to a DPad. * @return Menu index that corresponds to the currently assigned preset choice. * 0 means that no matching preset was found. */ int DPadContextMenu::getPresetIndex() { int result = 0; PadderCommon::inputDaemonMutex.lock(); JoyDPadButton *upButton = dpad->getJoyButton(JoyDPadButton::DpadUp); QList *upslots = upButton->getAssignedSlots(); JoyDPadButton *downButton = dpad->getJoyButton(JoyDPadButton::DpadDown); QList *downslots = downButton->getAssignedSlots(); JoyDPadButton *leftButton = dpad->getJoyButton(JoyDPadButton::DpadLeft); QList *leftslots = leftButton->getAssignedSlots(); JoyDPadButton *rightButton = dpad->getJoyButton(JoyDPadButton::DpadRight); QList *rightslots = rightButton->getAssignedSlots(); if (upslots->length() == 1 && downslots->length() == 1 && leftslots->length() == 1 && rightslots->length() == 1) { JoyButtonSlot *upslot = upslots->at(0); JoyButtonSlot *downslot = downslots->at(0); JoyButtonSlot *leftslot = leftslots->at(0); JoyButtonSlot *rightslot = rightslots->at(0); if (upslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && upslot->getSlotCode() == JoyButtonSlot::MouseUp && downslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && downslot->getSlotCode() == JoyButtonSlot::MouseDown && leftslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && leftslot->getSlotCode() == JoyButtonSlot::MouseLeft && rightslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && rightslot->getSlotCode() == JoyButtonSlot::MouseRight) { result = 1; } else if (upslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && upslot->getSlotCode() == JoyButtonSlot::MouseUp && downslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && downslot->getSlotCode() == JoyButtonSlot::MouseDown && leftslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && leftslot->getSlotCode() == JoyButtonSlot::MouseRight && rightslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && rightslot->getSlotCode() == JoyButtonSlot::MouseLeft) { result = 2; } else if (upslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && upslot->getSlotCode() == JoyButtonSlot::MouseDown && downslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && downslot->getSlotCode() == JoyButtonSlot::MouseUp && leftslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && leftslot->getSlotCode() == JoyButtonSlot::MouseLeft && rightslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && rightslot->getSlotCode() == JoyButtonSlot::MouseRight) { result = 3; } else if (upslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && upslot->getSlotCode() == JoyButtonSlot::MouseDown && downslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && downslot->getSlotCode() == JoyButtonSlot::MouseUp && leftslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && leftslot->getSlotCode() == JoyButtonSlot::MouseRight && rightslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && rightslot->getSlotCode() == JoyButtonSlot::MouseLeft) { result = 4; } else if (upslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(upslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Up) && downslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(downslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Down) && leftslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(leftslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Left) && rightslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(rightslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Right)) { result = 5; } else if (upslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(upslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_W) && downslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(downslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_S) && leftslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(leftslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_A) && rightslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(rightslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_D)) { result = 6; } else if (upslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(upslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_8) && downslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(downslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_2) && leftslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(leftslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_4) && rightslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(rightslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_6)) { result = 7; } } else if (upslots->length() == 0 && downslots->length() == 0 && leftslots->length() == 0 && rightslots->length() == 0) { result = 8; } PadderCommon::inputDaemonMutex.unlock(); return result; } /** * @brief Open a mouse settings dialog for changing the mouse speed settings * for all DPad buttons. */ void DPadContextMenu::openMouseSettingsDialog() { MouseDPadSettingsDialog *dialog = new MouseDPadSettingsDialog(dpad, parentWidget()); dialog->show(); } antimicro-2.23/src/dpadcontextmenu.h000066400000000000000000000024161300750276700176010ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DPADCONTEXTMENU_H #define DPADCONTEXTMENU_H #include #include "joydpad.h" #include "uihelpers/dpadcontextmenuhelper.h" class DPadContextMenu : public QMenu { Q_OBJECT public: explicit DPadContextMenu(JoyDPad *dpad, QWidget *parent = 0); void buildMenu(); protected: int getPresetIndex(); JoyDPad *dpad; DPadContextMenuHelper helper; signals: public slots: private slots: void setDPadPreset(); void setDPadMode(); void openMouseSettingsDialog(); }; #endif // DPADCONTEXTMENU_H antimicro-2.23/src/dpadeditdialog.cpp000066400000000000000000000473051300750276700176760ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include "dpadeditdialog.h" #include "ui_dpadeditdialog.h" #include "mousedialog/mousedpadsettingsdialog.h" #include "event.h" #include "antkeymapper.h" #include "setjoystick.h" #include "inputdevice.h" #include "common.h" DPadEditDialog::DPadEditDialog(JoyDPad *dpad, QWidget *parent) : QDialog(parent, Qt::Window), ui(new Ui::DPadEditDialog), helper(dpad) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); this->dpad = dpad; helper.moveToThread(dpad->thread()); PadderCommon::inputDaemonMutex.lock(); updateWindowTitleDPadName(); if (dpad->getJoyMode() == JoyDPad::StandardMode) { ui->joyModeComboBox->setCurrentIndex(0); } else if (dpad->getJoyMode() == JoyDPad::EightWayMode) { ui->joyModeComboBox->setCurrentIndex(1); } else if (dpad->getJoyMode() == JoyDPad::FourWayCardinal) { ui->joyModeComboBox->setCurrentIndex(2); } else if (dpad->getJoyMode() == JoyDPad::FourWayDiagonal) { ui->joyModeComboBox->setCurrentIndex(3); } selectCurrentPreset(); ui->dpadNameLineEdit->setText(dpad->getDpadName()); unsigned int dpadDelay = dpad->getDPadDelay(); ui->dpadDelaySlider->setValue(dpadDelay * .1); ui->dpadDelayDoubleSpinBox->setValue(dpadDelay * .001); PadderCommon::inputDaemonMutex.unlock(); connect(ui->presetsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(implementPresets(int))); connect(ui->joyModeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(implementModes(int))); connect(ui->mouseSettingsPushButton, SIGNAL(clicked()), this, SLOT(openMouseSettingsDialog())); connect(ui->dpadNameLineEdit, SIGNAL(textEdited(QString)), dpad, SLOT(setDPadName(QString))); connect(ui->dpadDelaySlider, SIGNAL(valueChanged(int)), &helper, SLOT(updateJoyDPadDelay(int))); connect(dpad, SIGNAL(dpadDelayChanged(int)), this, SLOT(updateDPadDelaySpinBox(int))); connect(ui->dpadDelayDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(updateDPadDelaySlider(double))); connect(dpad, SIGNAL(dpadNameChanged()), this, SLOT(updateWindowTitleDPadName())); } DPadEditDialog::~DPadEditDialog() { delete ui; } void DPadEditDialog::implementPresets(int index) { JoyButtonSlot *upButtonSlot = 0; JoyButtonSlot *downButtonSlot = 0; JoyButtonSlot *leftButtonSlot = 0; JoyButtonSlot *rightButtonSlot = 0; JoyButtonSlot *upLeftButtonSlot = 0; JoyButtonSlot *upRightButtonSlot = 0; JoyButtonSlot *downLeftButtonSlot = 0; JoyButtonSlot *downRightButtonSlot = 0; if (index == 1) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); downButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); leftButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); rightButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); PadderCommon::inputDaemonMutex.unlock(); ui->joyModeComboBox->setCurrentIndex(0); } else if (index == 2) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); downButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); leftButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); rightButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); PadderCommon::inputDaemonMutex.unlock(); ui->joyModeComboBox->setCurrentIndex(0); } else if (index == 3) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); downButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); leftButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); rightButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); PadderCommon::inputDaemonMutex.unlock(); ui->joyModeComboBox->setCurrentIndex(0); } else if (index == 4) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); downButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); leftButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); rightButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); PadderCommon::inputDaemonMutex.unlock(); ui->joyModeComboBox->setCurrentIndex(0); } else if (index == 5) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Up), Qt::Key_Up, JoyButtonSlot::JoyKeyboard, this); downButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Down), Qt::Key_Down, JoyButtonSlot::JoyKeyboard, this); leftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Left), Qt::Key_Left, JoyButtonSlot::JoyKeyboard, this); rightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Right), Qt::Key_Right, JoyButtonSlot::JoyKeyboard, this); PadderCommon::inputDaemonMutex.unlock(); ui->joyModeComboBox->setCurrentIndex(0); } else if (index == 6) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_W), Qt::Key_W, JoyButtonSlot::JoyKeyboard, this); downButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_S), Qt::Key_S, JoyButtonSlot::JoyKeyboard, this); leftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_A), Qt::Key_A, JoyButtonSlot::JoyKeyboard, this); rightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_D), Qt::Key_D, JoyButtonSlot::JoyKeyboard, this); PadderCommon::inputDaemonMutex.unlock(); ui->joyModeComboBox->setCurrentIndex(0); } else if (index == 7) { PadderCommon::inputDaemonMutex.lock(); if (ui->joyModeComboBox->currentIndex() == 0 || ui->joyModeComboBox->currentIndex() == 2) { upButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_8), QtKeyMapperBase::AntKey_KP_8, JoyButtonSlot::JoyKeyboard, this); downButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_2), QtKeyMapperBase::AntKey_KP_2, JoyButtonSlot::JoyKeyboard, this); leftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_4), QtKeyMapperBase::AntKey_KP_4, JoyButtonSlot::JoyKeyboard, this); rightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_6), QtKeyMapperBase::AntKey_KP_6, JoyButtonSlot::JoyKeyboard, this); } else if (ui->joyModeComboBox->currentIndex() == 1) { upButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_8), QtKeyMapperBase::AntKey_KP_8, JoyButtonSlot::JoyKeyboard, this); downButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_2), QtKeyMapperBase::AntKey_KP_2, JoyButtonSlot::JoyKeyboard, this); leftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_4), QtKeyMapperBase::AntKey_KP_4, JoyButtonSlot::JoyKeyboard, this); rightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_6), QtKeyMapperBase::AntKey_KP_6, JoyButtonSlot::JoyKeyboard, this); upLeftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_7), QtKeyMapperBase::AntKey_KP_7, JoyButtonSlot::JoyKeyboard, this); upRightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_9), QtKeyMapperBase::AntKey_KP_9, JoyButtonSlot::JoyKeyboard, this); downLeftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_1), QtKeyMapperBase::AntKey_KP_1, JoyButtonSlot::JoyKeyboard, this); downRightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_3), QtKeyMapperBase::AntKey_KP_3, JoyButtonSlot::JoyKeyboard, this); } else if (ui->joyModeComboBox->currentIndex() == 3) { upLeftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_7), QtKeyMapperBase::AntKey_KP_7, JoyButtonSlot::JoyKeyboard, this); upRightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_9), QtKeyMapperBase::AntKey_KP_9, JoyButtonSlot::JoyKeyboard, this); downLeftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_1), QtKeyMapperBase::AntKey_KP_1, JoyButtonSlot::JoyKeyboard, this); downRightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_3), QtKeyMapperBase::AntKey_KP_3, JoyButtonSlot::JoyKeyboard, this); } PadderCommon::inputDaemonMutex.unlock(); } else if (index == 8) { QMetaObject::invokeMethod(&helper, "clearButtonsSlotsEventReset", Qt::BlockingQueuedConnection); } QHash tempHash; tempHash.insert(JoyDPadButton::DpadUp, upButtonSlot); tempHash.insert(JoyDPadButton::DpadDown, downButtonSlot); tempHash.insert(JoyDPadButton::DpadLeft, leftButtonSlot); tempHash.insert(JoyDPadButton::DpadRight, rightButtonSlot); tempHash.insert(JoyDPadButton::DpadLeftUp, upLeftButtonSlot); tempHash.insert(JoyDPadButton::DpadRightUp, upRightButtonSlot); tempHash.insert(JoyDPadButton::DpadLeftDown, downLeftButtonSlot); tempHash.insert(JoyDPadButton::DpadRightDown, downRightButtonSlot); helper.setPendingSlots(&tempHash); QMetaObject::invokeMethod(&helper, "setFromPendingSlots", Qt::BlockingQueuedConnection); } void DPadEditDialog::implementModes(int index) { PadderCommon::inputDaemonMutex.lock(); dpad->releaseButtonEvents(); if (index == 0) { dpad->setJoyMode(JoyDPad::StandardMode); } else if (index == 1) { dpad->setJoyMode(JoyDPad::EightWayMode); } else if (index == 2) { dpad->setJoyMode(JoyDPad::FourWayCardinal); } else if (index == 3) { dpad->setJoyMode(JoyDPad::FourWayDiagonal); } PadderCommon::inputDaemonMutex.unlock(); } void DPadEditDialog::selectCurrentPreset() { JoyDPadButton *upButton = dpad->getJoyButton(JoyDPadButton::DpadUp); QList *upslots = upButton->getAssignedSlots(); JoyDPadButton *downButton = dpad->getJoyButton(JoyDPadButton::DpadDown); QList *downslots = downButton->getAssignedSlots(); JoyDPadButton *leftButton = dpad->getJoyButton(JoyDPadButton::DpadLeft); QList *leftslots = leftButton->getAssignedSlots(); JoyDPadButton *rightButton = dpad->getJoyButton(JoyDPadButton::DpadRight); QList *rightslots = rightButton->getAssignedSlots(); if (upslots->length() == 1 && downslots->length() == 1 && leftslots->length() == 1 && rightslots->length() == 1) { JoyButtonSlot *upslot = upslots->at(0); JoyButtonSlot *downslot = downslots->at(0); JoyButtonSlot *leftslot = leftslots->at(0); JoyButtonSlot *rightslot = rightslots->at(0); if (upslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && upslot->getSlotCode() == JoyButtonSlot::MouseUp && downslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && downslot->getSlotCode() == JoyButtonSlot::MouseDown && leftslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && leftslot->getSlotCode() == JoyButtonSlot::MouseLeft && rightslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && rightslot->getSlotCode() == JoyButtonSlot::MouseRight) { ui->presetsComboBox->setCurrentIndex(1); } else if (upslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && upslot->getSlotCode() == JoyButtonSlot::MouseUp && downslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && downslot->getSlotCode() == JoyButtonSlot::MouseDown && leftslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && leftslot->getSlotCode() == JoyButtonSlot::MouseRight && rightslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && rightslot->getSlotCode() == JoyButtonSlot::MouseLeft) { ui->presetsComboBox->setCurrentIndex(2); } else if (upslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && upslot->getSlotCode() == JoyButtonSlot::MouseDown && downslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && downslot->getSlotCode() == JoyButtonSlot::MouseUp && leftslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && leftslot->getSlotCode() == JoyButtonSlot::MouseLeft && rightslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && rightslot->getSlotCode() == JoyButtonSlot::MouseRight) { ui->presetsComboBox->setCurrentIndex(3); } else if (upslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && upslot->getSlotCode() == JoyButtonSlot::MouseDown && downslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && downslot->getSlotCode() == JoyButtonSlot::MouseUp && leftslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && leftslot->getSlotCode() == JoyButtonSlot::MouseRight && rightslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && rightslot->getSlotCode() == JoyButtonSlot::MouseLeft) { ui->presetsComboBox->setCurrentIndex(4); } else if (upslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(upslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Up) && downslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(downslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Down) && leftslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(leftslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Left) && rightslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(rightslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Right)) { ui->presetsComboBox->setCurrentIndex(5); } else if (upslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(upslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_W) && downslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(downslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_S) && leftslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(leftslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_A) && rightslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(rightslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_D)) { ui->presetsComboBox->setCurrentIndex(6); } else if (upslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(upslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_8) && downslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(downslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_2) && leftslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(leftslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_4) && rightslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(rightslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_6)) { ui->presetsComboBox->setCurrentIndex(7); } } else if (upslots->length() == 0 && downslots->length() == 0 && leftslots->length() == 0 && rightslots->length() == 0) { ui->presetsComboBox->setCurrentIndex(8); } } void DPadEditDialog::openMouseSettingsDialog() { ui->mouseSettingsPushButton->setEnabled(false); MouseDPadSettingsDialog *dialog = new MouseDPadSettingsDialog(this->dpad, this); dialog->show(); connect(this, SIGNAL(finished(int)), dialog, SLOT(close())); connect(dialog, SIGNAL(finished(int)), this, SLOT(enableMouseSettingButton())); } void DPadEditDialog::enableMouseSettingButton() { ui->mouseSettingsPushButton->setEnabled(true); } /** * @brief Update QDoubleSpinBox value based on updated dpad delay value. * @param Delay value obtained from JoyDPad. */ void DPadEditDialog::updateDPadDelaySpinBox(int value) { double temp = static_cast(value * 0.001); ui->dpadDelayDoubleSpinBox->setValue(temp); } /** * @brief Update QSlider value based on value from QDoubleSpinBox. * @param Value from QDoubleSpinBox. */ void DPadEditDialog::updateDPadDelaySlider(double value) { int temp = static_cast(value * 100); if (ui->dpadDelaySlider->value() != temp) { ui->dpadDelaySlider->setValue(temp); } } void DPadEditDialog::updateWindowTitleDPadName() { QString temp = QString(tr("Set")).append(" "); if (!dpad->getDpadName().isEmpty()) { temp.append(dpad->getName(false, true)); } else { temp.append(dpad->getName()); } if (dpad->getParentSet()->getIndex() != 0) { unsigned int setIndex = dpad->getParentSet()->getRealIndex(); temp.append(" [").append(tr("Set %1").arg(setIndex)); QString setName = dpad->getParentSet()->getName(); if (!setName.isEmpty()) { temp.append(": ").append(setName); } temp.append("]"); } setWindowTitle(temp); } antimicro-2.23/src/dpadeditdialog.h000066400000000000000000000030101300750276700173240ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DPADEDITDIALOG_H #define DPADEDITDIALOG_H #include #include "joydpad.h" #include "uihelpers/dpadeditdialoghelper.h" namespace Ui { class DPadEditDialog; } class DPadEditDialog : public QDialog { Q_OBJECT public: explicit DPadEditDialog(JoyDPad *dpad, QWidget *parent = 0); ~DPadEditDialog(); protected: void selectCurrentPreset(); JoyDPad *dpad; DPadEditDialogHelper helper; private: Ui::DPadEditDialog *ui; private slots: void implementPresets(int index); void implementModes(int index); void openMouseSettingsDialog(); void enableMouseSettingButton(); void updateWindowTitleDPadName(); void updateDPadDelaySpinBox(int value); void updateDPadDelaySlider(double value); }; #endif // DPADEDITDIALOG_H antimicro-2.23/src/dpadeditdialog.ui000066400000000000000000000211351300750276700175220ustar00rootroot00000000000000 DPadEditDialog Qt::WindowModal 0 0 528 334 Dialog Presets: 282 0 Mouse (Normal) Mouse (Inverted Horizontal) Mouse (Inverted Vertical) Mouse (Inverted Horizontal + Vertical) Arrows Keys: W | A | S | D NumPad None Dpad Mode: 282 0 Standard: 8 region dpad with two direction buttons active when the dpad is in a diagonal region. Eight Way: 8 region dpad with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region dpad with regions corresponding to the cardinal directions of the dpad. Useful for menus. 4 Way Diagonal: 4 region dpad with each region corresponding to a diagonal zone. Standard Eight Way 4 Way Cardinal 4 Way Diagonal Qt::Vertical QSizePolicy::Fixed 20 20 DPad Delay: Time lapsed before a direction change is taken into effect. 0 100 1 10 0 0 Qt::Horizontal QSlider::TicksBelow 0 Time lapsed before a direction change is taken into effect. false s 2 1.000000000000000 0.010000000000000 Qt::Vertical QSizePolicy::MinimumExpanding 20 36 10 6 &Name: dpadNameLineEdit Specify the name of a dpad. Mouse Settings Qt::Horizontal Qt::Horizontal QDialogButtonBox::Close buttonBox accepted() DPadEditDialog accept() 248 254 157 274 buttonBox rejected() DPadEditDialog reject() 316 260 286 274 antimicro-2.23/src/dpadpushbutton.cpp000066400000000000000000000045201300750276700177740ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "dpadpushbutton.h" #include "dpadcontextmenu.h" DPadPushButton::DPadPushButton(JoyDPad *dpad, bool displayNames, QWidget *parent) : FlashButtonWidget(displayNames, parent) { this->dpad = dpad; refreshLabel(); enableFlashes(); tryFlash(); this->setContextMenuPolicy(Qt::CustomContextMenu); connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint&))); connect(dpad, SIGNAL(dpadNameChanged()), this, SLOT(refreshLabel())); } JoyDPad* DPadPushButton::getDPad() { return dpad; } QString DPadPushButton::generateLabel() { QString temp; if (!dpad->getDpadName().isEmpty()) { temp.append(dpad->getName(false, displayNames)); } else { temp.append(dpad->getName()); } return temp; } void DPadPushButton::disableFlashes() { disconnect(dpad, SIGNAL(active(int)), this, SLOT(flash())); disconnect(dpad, SIGNAL(released(int)), this, SLOT(unflash())); this->unflash(); } void DPadPushButton::enableFlashes() { connect(dpad, SIGNAL(active(int)), this, SLOT(flash()), Qt::QueuedConnection); connect(dpad, SIGNAL(released(int)), this, SLOT(unflash()), Qt::QueuedConnection); } void DPadPushButton::showContextMenu(const QPoint &point) { QPoint globalPos = this->mapToGlobal(point); DPadContextMenu *contextMenu = new DPadContextMenu(dpad, this); contextMenu->buildMenu(); contextMenu->popup(globalPos); } void DPadPushButton::tryFlash() { if (dpad->getCurrentDirection() != static_cast(JoyDPadButton::DpadCentered)) { flash(); } } antimicro-2.23/src/dpadpushbutton.h000066400000000000000000000024421300750276700174420ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DPADPUSHBUTTON_H #define DPADPUSHBUTTON_H #include #include "flashbuttonwidget.h" #include "joydpad.h" class DPadPushButton : public FlashButtonWidget { Q_OBJECT public: explicit DPadPushButton(JoyDPad *dpad, bool displayNames, QWidget *parent = 0); JoyDPad* getDPad(); void tryFlash(); protected: QString generateLabel(); JoyDPad *dpad; signals: public slots: void disableFlashes(); void enableFlashes(); private slots: void showContextMenu(const QPoint &point); }; #endif // DPADPUSHBUTTON_H antimicro-2.23/src/dpadpushbuttongroup.cpp000066400000000000000000000155411300750276700210560ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "dpadpushbuttongroup.h" #include "buttoneditdialog.h" #include "dpadeditdialog.h" DPadPushButtonGroup::DPadPushButtonGroup(JoyDPad *dpad, bool displayNames, QWidget *parent) : QGridLayout(parent) { this->dpad = dpad; this->displayNames = displayNames; generateButtons(); changeButtonLayout(); connect(dpad, SIGNAL(joyModeChanged()), this, SLOT(changeButtonLayout())); } void DPadPushButtonGroup::generateButtons() { QHash *buttons = dpad->getJoyButtons(); JoyDPadButton *button = 0; JoyDPadButtonWidget *pushbutton = 0; button = buttons->value(JoyDPadButton::DpadLeftUp); upLeftButton = new JoyDPadButtonWidget(button, displayNames, parentWidget()); pushbutton = upLeftButton; connect(pushbutton, SIGNAL(clicked()), this, SLOT(openDPadButtonDialog())); button->establishPropertyUpdatedConnections(); connect(button, SIGNAL(slotsChanged()), this, SLOT(propogateSlotsChanged())); addWidget(pushbutton, 0, 0); button = buttons->value(JoyDPadButton::DpadUp); upButton = new JoyDPadButtonWidget(button, displayNames, parentWidget()); pushbutton = upButton; connect(pushbutton, SIGNAL(clicked()), this, SLOT(openDPadButtonDialog())); button->establishPropertyUpdatedConnections(); connect(button, SIGNAL(slotsChanged()), this, SLOT(propogateSlotsChanged())); addWidget(pushbutton, 0, 1); button = buttons->value(JoyDPadButton::DpadRightUp); upRightButton = new JoyDPadButtonWidget(button, displayNames, parentWidget()); pushbutton = upRightButton; connect(pushbutton, SIGNAL(clicked()), this, SLOT(openDPadButtonDialog())); button->establishPropertyUpdatedConnections(); connect(button, SIGNAL(slotsChanged()), this, SLOT(propogateSlotsChanged())); addWidget(pushbutton, 0, 2); button = buttons->value(JoyDPadButton::DpadLeft); leftButton = new JoyDPadButtonWidget(button, displayNames, parentWidget()); pushbutton = leftButton; connect(pushbutton, SIGNAL(clicked()), this, SLOT(openDPadButtonDialog())); button->establishPropertyUpdatedConnections(); connect(button, SIGNAL(slotsChanged()), this, SLOT(propogateSlotsChanged())); addWidget(pushbutton, 1, 0); dpadWidget = new DPadPushButton(dpad, displayNames, parentWidget()); dpadWidget->setIcon(QIcon::fromTheme(QString::fromUtf8("games-config-options"))); connect(dpadWidget, SIGNAL(clicked()), this, SLOT(showDPadDialog())); addWidget(dpadWidget, 1, 1); button = buttons->value(JoyDPadButton::DpadRight); rightButton = new JoyDPadButtonWidget(button, displayNames, parentWidget()); pushbutton = rightButton; connect(pushbutton, SIGNAL(clicked()), this, SLOT(openDPadButtonDialog())); button->establishPropertyUpdatedConnections(); connect(button, SIGNAL(slotsChanged()), this, SLOT(propogateSlotsChanged())); addWidget(pushbutton, 1, 2); button = buttons->value(JoyDPadButton::DpadLeftDown); downLeftButton = new JoyDPadButtonWidget(button, displayNames, parentWidget()); pushbutton = downLeftButton; connect(pushbutton, SIGNAL(clicked()), this, SLOT(openDPadButtonDialog())); button->establishPropertyUpdatedConnections(); connect(button, SIGNAL(slotsChanged()), this, SLOT(propogateSlotsChanged())); addWidget(pushbutton, 2, 0); button = buttons->value(JoyDPadButton::DpadDown); downButton = new JoyDPadButtonWidget(button, displayNames, parentWidget()); pushbutton = downButton; connect(pushbutton, SIGNAL(clicked()), this, SLOT(openDPadButtonDialog())); button->establishPropertyUpdatedConnections(); connect(button, SIGNAL(slotsChanged()), this, SLOT(propogateSlotsChanged())); addWidget(pushbutton, 2, 1); button = buttons->value(JoyDPadButton::DpadRightDown); downRightButton = new JoyDPadButtonWidget(button, displayNames, parentWidget()); pushbutton = downRightButton; connect(pushbutton, SIGNAL(clicked()), this, SLOT(openDPadButtonDialog())); button->establishPropertyUpdatedConnections(); connect(button, SIGNAL(slotsChanged()), this, SLOT(propogateSlotsChanged())); addWidget(pushbutton, 2, 2); } void DPadPushButtonGroup::changeButtonLayout() { if (dpad->getJoyMode() == JoyDPad::StandardMode || dpad->getJoyMode() == JoyDPad::EightWayMode || dpad->getJoyMode() == JoyDPad::FourWayCardinal) { upButton->setVisible(true); downButton->setVisible(true); leftButton->setVisible(true); rightButton->setVisible(true); } else { upButton->setVisible(false); downButton->setVisible(false); leftButton->setVisible(false); rightButton->setVisible(false); } if (dpad->getJoyMode() == JoyDPad::EightWayMode || dpad->getJoyMode() == JoyDPad::FourWayDiagonal) { upLeftButton->setVisible(true); upRightButton->setVisible(true); downLeftButton->setVisible(true); downRightButton->setVisible(true); } else { upLeftButton->setVisible(false); upRightButton->setVisible(false); downLeftButton->setVisible(false); downRightButton->setVisible(false); } } void DPadPushButtonGroup::propogateSlotsChanged() { emit buttonSlotChanged(); } JoyDPad* DPadPushButtonGroup::getDPad() { return dpad; } void DPadPushButtonGroup::openDPadButtonDialog() { JoyButtonWidget *buttonWidget = static_cast(sender()); JoyButton *button = buttonWidget->getJoyButton(); ButtonEditDialog *dialog = new ButtonEditDialog(button, parentWidget()); dialog->show(); } void DPadPushButtonGroup::showDPadDialog() { DPadEditDialog *dialog = new DPadEditDialog(dpad, parentWidget()); dialog->show(); } void DPadPushButtonGroup::toggleNameDisplay() { displayNames = !displayNames; upButton->toggleNameDisplay(); downButton->toggleNameDisplay(); leftButton->toggleNameDisplay(); rightButton->toggleNameDisplay(); upLeftButton->toggleNameDisplay(); upRightButton->toggleNameDisplay(); downLeftButton->toggleNameDisplay(); downRightButton->toggleNameDisplay(); dpadWidget->toggleNameDisplay(); } antimicro-2.23/src/dpadpushbuttongroup.h000066400000000000000000000034151300750276700205200ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DPADPUSHBUTTONGROUP_H #define DPADPUSHBUTTONGROUP_H #include #include "joydpad.h" #include "joydpadbuttonwidget.h" #include "dpadpushbutton.h" class DPadPushButtonGroup : public QGridLayout { Q_OBJECT public: explicit DPadPushButtonGroup(JoyDPad *dpad, bool displayNames = false, QWidget *parent = 0); JoyDPad *getDPad(); protected: void generateButtons(); JoyDPad *dpad; bool displayNames; JoyDPadButtonWidget *upButton; JoyDPadButtonWidget *downButton; JoyDPadButtonWidget *leftButton; JoyDPadButtonWidget *rightButton; JoyDPadButtonWidget *upLeftButton; JoyDPadButtonWidget *upRightButton; JoyDPadButtonWidget *downLeftButton; JoyDPadButtonWidget *downRightButton; DPadPushButton *dpadWidget; signals: void buttonSlotChanged(); public slots: void changeButtonLayout(); void toggleNameDisplay(); private slots: void propogateSlotsChanged(); void openDPadButtonDialog(); void showDPadDialog(); }; #endif // DPADPUSHBUTTONGROUP_H antimicro-2.23/src/editalldefaultautoprofiledialog.cpp000066400000000000000000000057041300750276700233520ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "editalldefaultautoprofiledialog.h" #include "ui_editalldefaultautoprofiledialog.h" #include "common.h" EditAllDefaultAutoProfileDialog::EditAllDefaultAutoProfileDialog(AutoProfileInfo *info, AntiMicroSettings *settings, QWidget *parent) : QDialog(parent), ui(new Ui::EditAllDefaultAutoProfileDialog) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); this->info = info; this->settings = settings; if (!info->getProfileLocation().isEmpty()) { ui->profileLineEdit->setText(info->getProfileLocation()); } connect(ui->profileBrowsePushButton, SIGNAL(clicked()), this, SLOT(openProfileBrowseDialog())); connect(this, SIGNAL(accepted()), this, SLOT(saveAutoProfileInformation())); } EditAllDefaultAutoProfileDialog::~EditAllDefaultAutoProfileDialog() { delete ui; } void EditAllDefaultAutoProfileDialog::openProfileBrowseDialog() { QString lookupDir = PadderCommon::preferredProfileDir(settings); QString filename = QFileDialog::getOpenFileName(this, tr("Open Config"), lookupDir, QString("Config Files (*.amgp *.xml)")); if (!filename.isNull() && !filename.isEmpty()) { ui->profileLineEdit->setText(filename); } } void EditAllDefaultAutoProfileDialog::saveAutoProfileInformation() { info->setGUID("all"); info->setProfileLocation(ui->profileLineEdit->text()); info->setActive(true); } AutoProfileInfo* EditAllDefaultAutoProfileDialog::getAutoProfile() { return info; } void EditAllDefaultAutoProfileDialog::accept() { bool validForm = true; QString errorString; if (ui->profileLineEdit->text().length() > 0) { QString profileFilename = ui->profileLineEdit->text(); QFileInfo info(profileFilename); if (!info.exists()) { validForm = false; errorString = tr("Profile file path is invalid."); } } if (validForm) { QDialog::accept(); } else { QMessageBox msgBox; msgBox.setText(errorString); msgBox.setStandardButtons(QMessageBox::Close); msgBox.exec(); } } antimicro-2.23/src/editalldefaultautoprofiledialog.h000066400000000000000000000030741300750276700230150ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef EDITALLDEFAULTAUTOPROFILEDIALOG_H #define EDITALLDEFAULTAUTOPROFILEDIALOG_H #include #include "autoprofileinfo.h" #include "antimicrosettings.h" namespace Ui { class EditAllDefaultAutoProfileDialog; } class EditAllDefaultAutoProfileDialog : public QDialog { Q_OBJECT public: explicit EditAllDefaultAutoProfileDialog(AutoProfileInfo *info, AntiMicroSettings *settings, QWidget *parent = 0); ~EditAllDefaultAutoProfileDialog(); AutoProfileInfo* getAutoProfile(); protected: virtual void accept(); AutoProfileInfo *info; AntiMicroSettings *settings; private: Ui::EditAllDefaultAutoProfileDialog *ui; private slots: void openProfileBrowseDialog(); void saveAutoProfileInformation(); }; #endif // EDITALLDEFAULTAUTOPROFILEDIALOG_H antimicro-2.23/src/editalldefaultautoprofiledialog.ui000066400000000000000000000047721300750276700232110ustar00rootroot00000000000000 EditAllDefaultAutoProfileDialog 0 0 384 114 Default Profile true Profile: profileLineEdit Browse Qt::Vertical QSizePolicy::Fixed 20 10 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() EditAllDefaultAutoProfileDialog accept() 248 254 157 274 buttonBox rejected() EditAllDefaultAutoProfileDialog reject() 316 260 286 274 antimicro-2.23/src/event.cpp000066400000000000000000000716201300750276700160560ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include #include #include #include #include #include #include #include "event.h" #include "eventhandlerfactory.h" #include "joybutton.h" #if defined(Q_OS_UNIX) #if defined(WITH_X11) #include #include #include #include "x11extras.h" #ifdef WITH_XTEST #include #endif #endif #if defined(WITH_UINPUT) #include "uinputhelper.h" #endif #elif defined (Q_OS_WIN) #include #include "winextras.h" #endif // TODO: Implement function for determining final mouse pointer position // based around a fixed bounding box resolution. void fakeAbsMouseCoordinates(double springX, double springY, unsigned int width, unsigned int height, unsigned int &finalx, unsigned int &finaly, int screen=-1) { //Q_UNUSED(finalx); //Q_UNUSED(finaly); //Q_UNUSED(width); //Q_UNUSED(height); int screenWidth = 0; int screenHeight = 0; int screenMidwidth = 0; int screenMidheight = 0; int destSpringWidth = 0; int destSpringHeight = 0; int destMidWidth = 0; int destMidHeight = 0; //int currentMouseX = 0; //int currentMouseY = 0; QRect deskRect = PadderCommon::mouseHelperObj.getDesktopWidget() ->screenGeometry(screen); screenWidth = deskRect.width(); screenHeight = deskRect.height(); screenMidwidth = screenWidth / 2; screenMidheight = screenHeight / 2; if (width >= 2 && height >= 2) { destSpringWidth = qMin(static_cast(width), screenWidth); destSpringHeight = qMin(static_cast(height), screenHeight); } else { destSpringWidth = screenWidth; destSpringHeight = screenHeight; } /*#if defined(Q_OS_UNIX) && defined(WITH_X11) QPoint currentPoint; #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif currentPoint = X11Extras::getInstance()->getPos(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } else { currentPoint = QCursor::pos(); } #endif #else QPoint currentPoint = QCursor::pos(); #endif */ destMidWidth = destSpringWidth / 2; destMidHeight = destSpringHeight / 2; finalx = (screenMidwidth + (springX * destMidWidth) + deskRect.x()); finaly = (screenMidheight + (springY * destMidHeight) + deskRect.y()); } // Create the event used by the operating system. void sendevent(JoyButtonSlot *slot, bool pressed) { //int code = slot->getSlotCode(); JoyButtonSlot::JoySlotInputAction device = slot->getSlotMode(); if (device == JoyButtonSlot::JoyKeyboard) { EventHandlerFactory::getInstance()->handler()->sendKeyboardEvent(slot, pressed); } else if (device == JoyButtonSlot::JoyMouseButton) { EventHandlerFactory::getInstance()->handler()->sendMouseButtonEvent(slot, pressed); } else if (device == JoyButtonSlot::JoyTextEntry && pressed && !slot->getTextData().isEmpty()) { EventHandlerFactory::getInstance()->handler()->sendTextEntryEvent(slot->getTextData()); } else if (device == JoyButtonSlot::JoyExecute && pressed && !slot->getTextData().isEmpty()) { QString execString = slot->getTextData(); if (slot->getExtraData().canConvert()) { QString argumentsString = slot->getExtraData().toString(); QStringList argumentsTempList(PadderCommon::parseArgumentsString(argumentsString)); QProcess::startDetached(execString, argumentsTempList); } else { QProcess::startDetached(execString); } } } // Create the relative mouse event used by the operating system. void sendevent(int code1, int code2) { EventHandlerFactory::getInstance()->handler()->sendMouseEvent(code1, code2); } // TODO: Re-implement spring event generation to simplify the process // and reduce overhead. Refactor old function to only be used when an absmouse // position must be faked. void sendSpringEventRefactor(PadderCommon::springModeInfo *fullSpring, PadderCommon::springModeInfo *relativeSpring, int* const mousePosX, int* const mousePosY) { Q_UNUSED(relativeSpring); Q_UNUSED(mousePosX); Q_UNUSED(mousePosY); PadderCommon::mouseHelperObj.mouseTimer.stop(); if (fullSpring) { unsigned int xmovecoor = 0; unsigned int ymovecoor = 0; int width = 0; int height = 0; int midwidth = 0; int midheight = 0; int destSpringWidth = 0; int destSpringHeight = 0; int destMidWidth = 0; int destMidHeight = 0; int currentMouseX = 0; int currentMouseY = 0; double displacementX = 0.0; double displacementY = 0.0; bool useFullScreen = true; PadderCommon::mouseHelperObj.mouseTimer.stop(); BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); if (fullSpring->screen >= -1 && fullSpring->screen >= PadderCommon::mouseHelperObj.getDesktopWidget()->screenCount()) { fullSpring->screen = -1; } int springWidth = fullSpring->width; int springHeight = fullSpring->height; if (springWidth >= 2 && springHeight >= 2) { useFullScreen = false; displacementX = fullSpring->displacementX; displacementY = fullSpring->displacementY; } else { useFullScreen = true; displacementX = fullSpring->displacementX; displacementY = fullSpring->displacementY; } unsigned int pivotX = 0; unsigned int pivotY = 0; if (relativeSpring && relativeSpring->width >= 2 && relativeSpring->height >= 2) { if (PadderCommon::mouseHelperObj.pivotPoint[0] != -1) { pivotX = PadderCommon::mouseHelperObj.pivotPoint[0]; } if (PadderCommon::mouseHelperObj.pivotPoint[1] != -1) { pivotY = PadderCommon::mouseHelperObj.pivotPoint[1]; } if (pivotX >= 0 && pivotY >= 0) { // Find a use for this routine in this context. int destRelativeWidth = relativeSpring->width; int destRelativeHeight = relativeSpring->height; int xRelativeMoovCoor = 0; if (relativeSpring->displacementX >= -1.0) { xRelativeMoovCoor = (relativeSpring->displacementX * destRelativeWidth) / 2; } int yRelativeMoovCoor = 0; if (relativeSpring->displacementY >= -1.0) { yRelativeMoovCoor = (relativeSpring->displacementY * destRelativeHeight) / 2; } xmovecoor += xRelativeMoovCoor; ymovecoor += yRelativeMoovCoor; } } if (handler->getIdentifier() == "xtest") { fakeAbsMouseCoordinates(displacementX, displacementY, springWidth, springHeight, xmovecoor, ymovecoor, fullSpring->screen); //EventHandlerFactory::getInstance()->handler()->sendMouseAbsEvent(xmovecoor, // ymovecoor); } else if (handler->getIdentifier() == "uinput") { //EventHandlerFactory::getInstance()->handler()->sendMouseAbsEvent(displacementX, // displacementY); fakeAbsMouseCoordinates(displacementX, displacementY, springWidth, springHeight, xmovecoor, ymovecoor, fullSpring->screen); //EventHandlerFactory::getInstance()->handler() // ->sendMouseSpringEvent(xmovecoor, ymovecoor, width, height); } } else { PadderCommon::mouseHelperObj.springMouseMoving = false; PadderCommon::mouseHelperObj.pivotPoint[0] = -1; PadderCommon::mouseHelperObj.pivotPoint[1] = -1; } } // TODO: Change to only use this routine when using a relative mouse // pointer to fake absolute mouse moves. Otherwise, don't worry about // current position of the mouse and just send an absolute mouse pointer // event. void sendSpringEvent(PadderCommon::springModeInfo *fullSpring, PadderCommon::springModeInfo *relativeSpring, int* const mousePosX, int* const mousePosY) { PadderCommon::mouseHelperObj.mouseTimer.stop(); if ((fullSpring->displacementX >= -2.0 && fullSpring->displacementX <= 1.0 && fullSpring->displacementY >= -2.0 && fullSpring->displacementY <= 1.0) || (relativeSpring && (relativeSpring->displacementX >= -2.0 && relativeSpring->displacementX <= 1.0 && relativeSpring->displacementY >= -2.0 && relativeSpring->displacementY <= 1.0))) { int xmovecoor = 0; int ymovecoor = 0; int width = 0; int height = 0; int midwidth = 0; int midheight = 0; int destSpringWidth = 0; int destSpringHeight = 0; int destMidWidth = 0; int destMidHeight = 0; int currentMouseX = 0; int currentMouseY = 0; //QDesktopWidget deskWid; if (fullSpring->screen >= -1 && fullSpring->screen >= PadderCommon::mouseHelperObj.getDesktopWidget()->screenCount()) { fullSpring->screen = -1; } QRect deskRect = PadderCommon::mouseHelperObj.getDesktopWidget() ->screenGeometry(fullSpring->screen); width = deskRect.width(); height = deskRect.height(); #if defined(Q_OS_UNIX) && defined(WITH_X11) QPoint currentPoint; #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif currentPoint = X11Extras::getInstance()->getPos(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } else { currentPoint = QCursor::pos(); } #endif #else QPoint currentPoint = QCursor::pos(); #endif currentMouseX = currentPoint.x(); currentMouseY = currentPoint.y(); midwidth = width / 2; midheight = height / 2; int springWidth = fullSpring->width; int springHeight = fullSpring->height; if (springWidth >= 2 && springHeight >= 2) { destSpringWidth = qMin(springWidth, width); destSpringHeight = qMin(springHeight, height); } else { destSpringWidth = width; destSpringHeight = height; } destMidWidth = destSpringWidth / 2; destMidHeight = destSpringHeight / 2; unsigned int pivotX = currentMouseX; unsigned int pivotY = currentMouseY; if (relativeSpring) { if (PadderCommon::mouseHelperObj.pivotPoint[0] != -1) { pivotX = PadderCommon::mouseHelperObj.pivotPoint[0]; } else { pivotX = currentMouseX; } if (PadderCommon::mouseHelperObj.pivotPoint[1] != -1) { pivotY = PadderCommon::mouseHelperObj.pivotPoint[1]; } else { pivotY = currentMouseY; } } xmovecoor = (fullSpring->displacementX >= -1.0) ? (midwidth + (fullSpring->displacementX * destMidWidth) + deskRect.x()): pivotX; ymovecoor = (fullSpring->displacementY >= -1.0) ? (midheight + (fullSpring->displacementY * destMidHeight) + deskRect.y()) : pivotY; unsigned int fullSpringDestX = xmovecoor; unsigned int fullSpringDestY = ymovecoor; unsigned int destRelativeWidth = 0; unsigned int destRelativeHeight = 0; if (relativeSpring && relativeSpring->width >= 2 && relativeSpring->height >= 2) { destRelativeWidth = relativeSpring->width; destRelativeHeight = relativeSpring->height; int xRelativeMoovCoor = 0; if (relativeSpring->displacementX >= -1.0) { xRelativeMoovCoor = (relativeSpring->displacementX * destRelativeWidth) / 2; } int yRelativeMoovCoor = 0; if (relativeSpring->displacementY >= -1.0) { yRelativeMoovCoor = (relativeSpring->displacementY * destRelativeHeight) / 2; } xmovecoor += xRelativeMoovCoor; ymovecoor += yRelativeMoovCoor; } if (mousePosX) { *mousePosX = xmovecoor; } if (mousePosY) { *mousePosY = ymovecoor; } if (xmovecoor != currentMouseX || ymovecoor != currentMouseY) { double diffx = abs(currentMouseX - xmovecoor); double diffy = abs(currentMouseY - ymovecoor); // If either position is set to center, force update. if (xmovecoor == (deskRect.x() + midwidth) || ymovecoor == (deskRect.y() + midheight)) { #if defined(Q_OS_UNIX) BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); if (fullSpring->screen <= -1) { if (handler->getIdentifier() == "xtest") { EventHandlerFactory::getInstance()->handler()->sendMouseAbsEvent(xmovecoor, ymovecoor, -1); } else if (handler->getIdentifier() == "uinput") { EventHandlerFactory::getInstance()->handler() ->sendMouseSpringEvent(xmovecoor, ymovecoor, width + deskRect.x(), height + deskRect.y()); } } else { EventHandlerFactory::getInstance()->handler()->sendMouseEvent(xmovecoor - currentMouseX, ymovecoor - currentMouseY); } #elif defined(Q_OS_WIN) if (fullSpring->screen <= -1) { EventHandlerFactory::getInstance()->handler() ->sendMouseSpringEvent(xmovecoor, ymovecoor, width + deskRect.x(), height + deskRect.y()); } else { sendevent(xmovecoor - currentMouseX, ymovecoor - currentMouseY); } #endif } else if (!PadderCommon::mouseHelperObj.springMouseMoving && relativeSpring && (relativeSpring->displacementX >= -1.0 || relativeSpring->displacementY >= -1.0) && (diffx >= destRelativeWidth*.013 || diffy >= destRelativeHeight*.013)) { PadderCommon::mouseHelperObj.springMouseMoving = true; #if defined(Q_OS_UNIX) BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); if (fullSpring->screen <= -1) { if (handler->getIdentifier() == "xtest") { EventHandlerFactory::getInstance()->handler()->sendMouseAbsEvent(xmovecoor, ymovecoor, -1); } else if (handler->getIdentifier() == "uinput") { EventHandlerFactory::getInstance()->handler() ->sendMouseSpringEvent(xmovecoor, ymovecoor, width + deskRect.x(), height + deskRect.y()); } } else { EventHandlerFactory::getInstance()->handler() ->sendMouseEvent(xmovecoor - currentMouseX, ymovecoor - currentMouseY); } #elif defined(Q_OS_WIN) if (fullSpring->screen <= -1) { EventHandlerFactory::getInstance()->handler() ->sendMouseSpringEvent(xmovecoor, ymovecoor, width + deskRect.x(), height + deskRect.y()); } else { sendevent(xmovecoor - currentMouseX, ymovecoor - currentMouseY); } #endif PadderCommon::mouseHelperObj.mouseTimer.start( qMax(JoyButton::getMouseRefreshRate(), JoyButton::getGamepadRefreshRate()) + 1); } else if (!PadderCommon::mouseHelperObj.springMouseMoving && (diffx >= destSpringWidth*.013 || diffy >= destSpringHeight*.013)) { PadderCommon::mouseHelperObj.springMouseMoving = true; #if defined(Q_OS_UNIX) BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); if (fullSpring->screen <= -1) { if (handler->getIdentifier() == "xtest") { EventHandlerFactory::getInstance()->handler()->sendMouseAbsEvent(xmovecoor, ymovecoor, -1); } else if (handler->getIdentifier() == "uinput") { EventHandlerFactory::getInstance()->handler() ->sendMouseSpringEvent(xmovecoor, ymovecoor, width + deskRect.x(), height + deskRect.y()); } } else { EventHandlerFactory::getInstance()->handler() ->sendMouseEvent(xmovecoor - currentMouseX, ymovecoor - currentMouseY); } #elif defined(Q_OS_WIN) if (fullSpring->screen <= -1) { EventHandlerFactory::getInstance()->handler() ->sendMouseSpringEvent(xmovecoor, ymovecoor, width + deskRect.x(), height + deskRect.y()); } else { sendevent(xmovecoor - currentMouseX, ymovecoor - currentMouseY); } #endif PadderCommon::mouseHelperObj.mouseTimer.start( qMax(JoyButton::getMouseRefreshRate(), JoyButton::getGamepadRefreshRate()) + 1); } else if (PadderCommon::mouseHelperObj.springMouseMoving && (diffx < 2 && diffy < 2)) { PadderCommon::mouseHelperObj.springMouseMoving = false; } else if (PadderCommon::mouseHelperObj.springMouseMoving) { #if defined(Q_OS_UNIX) BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); if (fullSpring->screen <= -1) { if (handler->getIdentifier() == "xtest") { EventHandlerFactory::getInstance()->handler()->sendMouseAbsEvent(xmovecoor, ymovecoor, -1); } else if (handler->getIdentifier() == "uinput") { EventHandlerFactory::getInstance()->handler() ->sendMouseSpringEvent(xmovecoor, ymovecoor, width + deskRect.x(), height + deskRect.y()); } } else { EventHandlerFactory::getInstance()->handler() ->sendMouseEvent(xmovecoor - currentMouseX, ymovecoor - currentMouseY); } #elif defined(Q_OS_WIN) if (fullSpring->screen <= -1) { EventHandlerFactory::getInstance()->handler() ->sendMouseSpringEvent(xmovecoor, ymovecoor, width + deskRect.x(), height + deskRect.y()); } else { sendevent(xmovecoor - currentMouseX, ymovecoor - currentMouseY); } #endif PadderCommon::mouseHelperObj.mouseTimer.start( qMax(JoyButton::getMouseRefreshRate(), JoyButton::getGamepadRefreshRate()) + 1); } PadderCommon::mouseHelperObj.previousCursorLocation[0] = currentMouseX; PadderCommon::mouseHelperObj.previousCursorLocation[1] = currentMouseY; PadderCommon::mouseHelperObj.pivotPoint[0] = fullSpringDestX; PadderCommon::mouseHelperObj.pivotPoint[1] = fullSpringDestY; } else if (PadderCommon::mouseHelperObj.previousCursorLocation[0] == xmovecoor && PadderCommon::mouseHelperObj.previousCursorLocation[1] == ymovecoor) { PadderCommon::mouseHelperObj.springMouseMoving = false; } else { PadderCommon::mouseHelperObj.previousCursorLocation[0] = currentMouseX; PadderCommon::mouseHelperObj.previousCursorLocation[1] = currentMouseY; PadderCommon::mouseHelperObj.pivotPoint[0] = fullSpringDestX; PadderCommon::mouseHelperObj.pivotPoint[1] = fullSpringDestY; PadderCommon::mouseHelperObj.mouseTimer.start( qMax(JoyButton::getMouseRefreshRate(), JoyButton::getGamepadRefreshRate()) + 1); } } else { PadderCommon::mouseHelperObj.springMouseMoving = false; PadderCommon::mouseHelperObj.pivotPoint[0] = -1; PadderCommon::mouseHelperObj.pivotPoint[1] = -1; } } int X11KeySymToKeycode(QString key) { int tempcode = 0; #if defined (Q_OS_UNIX) BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); if (key.length() > 0) { #ifdef WITH_XTEST if (handler->getIdentifier() == "xtest") { Display* display = X11Extras::getInstance()->display(); tempcode = XKeysymToKeycode(display, XStringToKeysym(key.toUtf8().data())); } #endif #ifdef WITH_UINPUT if (handler->getIdentifier() == "uinput") { tempcode = UInputHelper::getInstance()->getVirtualKey(key); } #endif } #elif defined (Q_OS_WIN) if (key.length() > 0) { tempcode = WinExtras::getVirtualKey(key); if (tempcode <= 0 && key.length() == 1) { //qDebug() << "KEY: " << key; //int oridnal = key.toUtf8().constData()[0]; int ordinal = QVariant(key.toUtf8().constData()[0]).toInt(); tempcode = VkKeyScan(ordinal); int modifiers = tempcode >> 8; tempcode = tempcode & 0xff; if ((modifiers & 1) != 0) tempcode |= VK_SHIFT; if ((modifiers & 2) != 0) tempcode |= VK_CONTROL; if ((modifiers & 4) != 0) tempcode |= VK_MENU; //tempcode = VkKeyScan(QVariant(key.constData()).toInt()); //tempcode = OemKeyScan(key.toUtf8().toInt()); //tempcode = OemKeyScan(ordinal); } } #endif return tempcode; } QString keycodeToKeyString(int keycode, unsigned int alias) { QString newkey; #if defined (Q_OS_UNIX) Q_UNUSED(alias); if (keycode <= 0) { newkey = "[NO KEY]"; } else { BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); #ifdef WITH_XTEST if (handler->getIdentifier() == "xtest") { Display* display = X11Extras::getInstance()->display(); newkey = QString("0x%1").arg(keycode, 0, 16); QString tempkey = XKeysymToString(XkbKeycodeToKeysym(display, keycode, 0, 0)); QString tempalias = X11Extras::getInstance()->getDisplayString(tempkey); if (!tempalias.isEmpty()) { newkey = tempalias; } else { XKeyPressedEvent tempevent; tempevent.keycode = keycode; tempevent.type = KeyPress; tempevent.display = display; tempevent.state = 0; char tempstring[256]; memset(tempstring, 0, sizeof(tempstring)); int bitestoreturn = sizeof(tempstring) - 1; int numchars = XLookupString(&tempevent, tempstring, bitestoreturn, NULL, NULL); if (numchars > 0) { tempstring[numchars] = '\0'; newkey = QString::fromUtf8(tempstring); //qDebug() << "NEWKEY:" << newkey << endl; //qDebug() << "NEWKEY LEGNTH:" << numchars << endl; } else { newkey = tempkey; } } } #endif #ifdef WITH_UINPUT if (handler->getIdentifier() == "uinput") { QString tempalias = UInputHelper::getInstance()->getDisplayString(keycode); if (!tempalias.isEmpty()) { newkey = tempalias; } else { newkey = QString("0x%1").arg(keycode, 0, 16); } } #endif } #elif defined (Q_OS_WIN) wchar_t buffer[50] = {0}; QString tempalias = WinExtras::getDisplayString(keycode); if (!tempalias.isEmpty()) { newkey = tempalias; } else { int scancode = WinExtras::scancodeFromVirtualKey(keycode, alias); if (keycode >= VK_BROWSER_BACK && keycode <= VK_LAUNCH_APP2) { newkey.append(QString("0x%1").arg(keycode, 0, 16)); } else { int length = GetKeyNameTextW(scancode << 16, buffer, sizeof(buffer)); if (length > 0) { newkey = QString::fromWCharArray(buffer); } else { newkey.append(QString("0x%1").arg(keycode, 0, 16)); } } } #endif return newkey; } unsigned int X11KeyCodeToX11KeySym(unsigned int keycode) { #ifdef Q_OS_WIN Q_UNUSED(keycode); return 0; #else #ifdef WITH_X11 Display* display = X11Extras::getInstance()->display(); unsigned int tempcode = XkbKeycodeToKeysym(display, keycode, 0, 0); return tempcode; #else Q_UNUSED(keycode); return 0; #endif #endif } QString keysymToKeyString(int keysym, unsigned int alias) { QString newkey; #if defined (Q_OS_UNIX) Q_UNUSED(alias); BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); if (handler->getIdentifier() == "xtest") { Display* display = X11Extras::getInstance()->display(); unsigned int keycode = 0; if (keysym > 0) { keycode = XKeysymToKeycode(display, keysym); } newkey = keycodeToKeyString(keycode); } else if (handler->getIdentifier() == "uinput") { newkey = keycodeToKeyString(keysym); } #else newkey = keycodeToKeyString(keysym, alias); #endif return newkey; } antimicro-2.23/src/event.h000066400000000000000000000032041300750276700155140ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef EVENT_H #define EVENT_H #include #include "joybuttonslot.h" //#include "mousehelper.h" #include "springmousemoveinfo.h" #include "common.h" void sendevent (JoyButtonSlot *slot, bool pressed=true); void sendevent(int code1, int code2); void sendSpringEventRefactor(PadderCommon::springModeInfo *fullSpring, PadderCommon::springModeInfo *relativeSpring=0, int* const mousePosX=0, int* const mousePos=0); void sendSpringEvent(PadderCommon::springModeInfo *fullSpring, PadderCommon::springModeInfo *relativeSpring=0, int* const mousePosX=0, int* const mousePos=0); int X11KeySymToKeycode(QString key); QString keycodeToKeyString(int keycode, unsigned int alias=0); unsigned int X11KeyCodeToX11KeySym(unsigned int keycode); QString keysymToKeyString(int keysym, unsigned int alias=0); #endif // EVENT_H antimicro-2.23/src/eventhandlerfactory.cpp000066400000000000000000000065551300750276700210110ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "eventhandlerfactory.h" static QHash buildDisplayNames() { QHash temp; #ifdef Q_OS_WIN temp.insert("sendinput", "SendInput"); #ifdef WITH_VMULTI temp.insert("vmulti", "Vmulti"); #endif #else temp.insert("xtest", "Xtest"); temp.insert("uinput", "uinput"); #endif return temp; } QHash handlerDisplayNames = buildDisplayNames(); EventHandlerFactory* EventHandlerFactory::instance = 0; EventHandlerFactory::EventHandlerFactory(QString handler, QObject *parent) : QObject(parent) { #ifdef Q_OS_UNIX #ifdef WITH_UINPUT if (handler == "uinput") { eventHandler = new UInputEventHandler(this); } #endif #ifdef WITH_XTEST if (handler == "xtest") { eventHandler = new XTestEventHandler(this); } #endif #elif defined(Q_OS_WIN) if (handler == "sendinput") { eventHandler = new WinSendInputEventHandler(this); } #ifdef WITH_VMULTI else if (handler == "vmulti") { eventHandler = new WinVMultiEventHandler(this); } #endif #endif } EventHandlerFactory::~EventHandlerFactory() { if (eventHandler) { delete eventHandler; eventHandler = 0; } } EventHandlerFactory* EventHandlerFactory::getInstance(QString handler) { if (!instance) { QStringList temp = buildEventGeneratorList(); if (!handler.isEmpty() && temp.contains(handler)) { instance = new EventHandlerFactory(handler); } else { instance = new EventHandlerFactory(fallBackIdentifier()); } } return instance; } void EventHandlerFactory::deleteInstance() { if (instance) { delete instance; instance = 0; } } BaseEventHandler* EventHandlerFactory::handler() { return eventHandler; } QString EventHandlerFactory::fallBackIdentifier() { QString temp; #ifdef Q_OS_UNIX #if defined(WITH_XTEST) temp = "xtest"; #elif defined(WITH_UINPUT) temp = "uinput"; #else temp = "xtest"; #endif #elif defined(Q_OS_WIN) temp = "sendinput"; #endif return temp; } QStringList EventHandlerFactory::buildEventGeneratorList() { QStringList temp; #ifdef Q_OS_WIN temp.append("sendinput"); #ifdef WITH_VMULTI temp.append("vmulti"); #endif #else temp.append("xtest"); temp.append("uinput"); #endif return temp; } QString EventHandlerFactory::handlerDisplayName(QString handler) { QString temp; if (handlerDisplayNames.contains(handler)) { temp = handlerDisplayNames.value(handler); } return temp; } antimicro-2.23/src/eventhandlerfactory.h000066400000000000000000000044171300750276700204510ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef EVENTHANDLERFACTORY_H #define EVENTHANDLERFACTORY_H #include #include #ifdef Q_OS_UNIX #ifdef WITH_UINPUT #include "eventhandlers/uinputeventhandler.h" #endif #ifdef WITH_XTEST #include "eventhandlers/xtesteventhandler.h" #endif #elif defined(Q_OS_WIN) #include "eventhandlers/winsendinputeventhandler.h" #ifdef WITH_VMULTI #include "eventhandlers/winvmultieventhandler.h" #endif #endif #ifdef Q_OS_WIN #define ADD_SENDINPUT 1 #ifdef WITH_VMULTI #define ADD_VMULTI 1 #else #define ADD_VMULTI 0 #endif #define NUM_BACKENDS (ADD_SENDINPUT + ADD_VMULTI) #else #ifdef WITH_XTEST #define ADD_XTEST 1 #else #define ADD_XTEST 0 #endif #ifdef WITH_UINPUT #define ADD_UINPUT 1 #else #define ADD_UINPUT 0 #endif #define NUM_BACKENDS (ADD_XTEST + ADD_UINPUT) #endif #if (NUM_BACKENDS > 1) #define BACKEND_ELSE_IF else if #else #define BACKEND_ELSE_IF if #endif class EventHandlerFactory : public QObject { Q_OBJECT public: static EventHandlerFactory* getInstance(QString handler = ""); void deleteInstance(); BaseEventHandler* handler(); static QString fallBackIdentifier(); static QStringList buildEventGeneratorList(); static QString handlerDisplayName(QString handler); protected: explicit EventHandlerFactory(QString handler, QObject *parent = 0); ~EventHandlerFactory(); BaseEventHandler *eventHandler; static EventHandlerFactory *instance; signals: public slots: }; #endif // EVENTHANDLERFACTORY_H antimicro-2.23/src/eventhandlers/000077500000000000000000000000001300750276700170655ustar00rootroot00000000000000antimicro-2.23/src/eventhandlers/baseeventhandler.cpp000066400000000000000000000042641300750276700231110ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "baseeventhandler.h" BaseEventHandler::BaseEventHandler(QObject *parent) : QObject(parent) { } QString BaseEventHandler::getErrorString() { return lastErrorString; } /** * @brief Do nothing by default. Allow child classes to specify text to output * to a text stream. */ void BaseEventHandler::printPostMessages() { } /** * @brief Do nothing by default. Useful for child classes to define behavior. * @param Displacement of X coordinate * @param Displacement of Y coordinate * @param Screen number or -1 to use default */ void BaseEventHandler::sendMouseAbsEvent(int xDis, int yDis, int screen) { Q_UNUSED(xDis); Q_UNUSED(yDis); Q_UNUSED(screen); } /** * @brief Do nothing by default. Useful for child classes to define behavior. * @param Displacement of X coordinate * @param Displacement of Y coordinate * @param Bounding box width * @param Bounding box height */ void BaseEventHandler::sendMouseSpringEvent(unsigned int xDis, unsigned int yDis, unsigned int width, unsigned int height) { Q_UNUSED(xDis); Q_UNUSED(yDis); Q_UNUSED(width); Q_UNUSED(height); } /** * @brief Do nothing by default. Useful for child classes to define behavior. * @param Displacement of X coordinate * @param Displacement of Y coordinate */ void BaseEventHandler::sendMouseSpringEvent(int xDis, int yDis) { } void BaseEventHandler::sendTextEntryEvent(QString maintext) { } antimicro-2.23/src/eventhandlers/baseeventhandler.h000066400000000000000000000035351300750276700225560ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BASEEVENTHANDLER_H #define BASEEVENTHANDLER_H #include #include #include #include class BaseEventHandler : public QObject { Q_OBJECT public: explicit BaseEventHandler(QObject *parent = 0); virtual bool init() = 0; virtual bool cleanup() = 0; virtual void sendKeyboardEvent(JoyButtonSlot *slot, bool pressed) = 0; virtual void sendMouseButtonEvent(JoyButtonSlot *slot, bool pressed) = 0; virtual void sendMouseEvent(int xDis, int yDis) = 0; virtual void sendMouseAbsEvent(int xDis, int yDis, int screen); virtual void sendMouseSpringEvent(unsigned int xDis, unsigned int yDis, unsigned int width, unsigned int height); virtual void sendMouseSpringEvent(int xDis, int yDis); virtual void sendTextEntryEvent(QString maintext); virtual QString getName() = 0; virtual QString getIdentifier() = 0; virtual void printPostMessages(); QString getErrorString(); protected: QString lastErrorString; signals: public slots: }; #endif // BASEEVENTHANDLER_H antimicro-2.23/src/eventhandlers/uinputeventhandler.cpp000066400000000000000000000423161300750276700235230ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include //#include #include #include #include #include #include #include #include static const QString mouseDeviceName = PadderCommon::mouseDeviceName; static const QString keyboardDeviceName = PadderCommon::keyboardDeviceName; static const QString springMouseDeviceName = PadderCommon::springMouseDeviceName; #ifdef WITH_X11 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include #endif #include #endif #include "uinputeventhandler.h" UInputEventHandler::UInputEventHandler(QObject *parent) : BaseEventHandler(parent) { keyboardFileHandler = 0; mouseFileHandler = 0; springMouseFileHandler = 0; } UInputEventHandler::~UInputEventHandler() { cleanup(); } /** * @brief Initialize keyboard and mouse virtual devices. Each device will * use its own file handle with various codes set to distinquish the two * devices. * @return */ bool UInputEventHandler::init() { bool result = true; // Open file handle for keyboard emulation. keyboardFileHandler = openUInputHandle(); if (keyboardFileHandler > 0) { setKeyboardEvents(keyboardFileHandler); populateKeyCodes(keyboardFileHandler); createUInputKeyboardDevice(keyboardFileHandler); } else { result = false; } if (result) { // Open mouse file handle to use for relative mouse emulation. mouseFileHandler = openUInputHandle(); if (mouseFileHandler > 0) { setRelMouseEvents(mouseFileHandler); createUInputMouseDevice(mouseFileHandler); } else { result = false; } } if (result) { // Open mouse file handle to use for absolute mouse emulation. springMouseFileHandler = openUInputHandle(); if (springMouseFileHandler > 0) { setSpringMouseEvents(springMouseFileHandler); createUInputSpringMouseDevice(springMouseFileHandler); } else { result = false; } } #ifdef WITH_X11 if (result) { #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif // Some time needs to elapse after device creation before changing // pointer settings. Otherwise, settings will not take effect. QTimer::singleShot(2000, this, SLOT(x11ResetMouseAccelerationChange())); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif } #endif return result; } #ifdef WITH_X11 void UInputEventHandler::x11ResetMouseAccelerationChange() { if (X11Extras::getInstance()) { X11Extras::getInstance()->x11ResetMouseAccelerationChange(); } } #endif bool UInputEventHandler::cleanup() { if (keyboardFileHandler > 0) { closeUInputDevice(keyboardFileHandler); keyboardFileHandler = 0; } if (mouseFileHandler > 0) { closeUInputDevice(mouseFileHandler); mouseFileHandler = 0; } if (springMouseFileHandler > 0) { closeUInputDevice(springMouseFileHandler); springMouseFileHandler = 0; } return true; } void UInputEventHandler::sendKeyboardEvent(JoyButtonSlot *slot, bool pressed) { JoyButtonSlot::JoySlotInputAction device = slot->getSlotMode(); int code = slot->getSlotCode(); if (device == JoyButtonSlot::JoyKeyboard) { write_uinput_event(keyboardFileHandler, EV_KEY, code, pressed ? 1 : 0); } } void UInputEventHandler::sendMouseButtonEvent(JoyButtonSlot *slot, bool pressed) { JoyButtonSlot::JoySlotInputAction device = slot->getSlotMode(); int code = slot->getSlotCode(); if (device == JoyButtonSlot::JoyMouseButton) { if (code <= 3) { unsigned int tempcode = BTN_LEFT; switch (code) { case 3: { tempcode = BTN_RIGHT; break; } case 2: { tempcode = BTN_MIDDLE; break; } case 1: default: { tempcode = BTN_LEFT; } } write_uinput_event(mouseFileHandler, EV_KEY, tempcode, pressed ? 1 : 0); } else if (code == 4) { if (pressed) { write_uinput_event(mouseFileHandler, EV_REL, REL_WHEEL, 1); } } else if (code == 5) { if (pressed) { write_uinput_event(mouseFileHandler, EV_REL, REL_WHEEL, -1); } } else if (code == 6) { if (pressed) { write_uinput_event(mouseFileHandler, EV_REL, REL_HWHEEL, 1); } } else if (code == 7) { if (pressed) { write_uinput_event(mouseFileHandler, EV_REL, REL_HWHEEL, -1); } } else if (code == 8) { write_uinput_event(mouseFileHandler, EV_KEY, BTN_SIDE, pressed ? 1 : 0); } else if (code == 9) { write_uinput_event(mouseFileHandler, EV_KEY, BTN_EXTRA, pressed ? 1 : 0); } } } void UInputEventHandler::sendMouseEvent(int xDis, int yDis) { write_uinput_event(mouseFileHandler, EV_REL, REL_X, xDis, false); write_uinput_event(mouseFileHandler, EV_REL, REL_Y, yDis); } void UInputEventHandler::sendMouseAbsEvent(int xDis, int yDis, int screen) { Q_UNUSED(screen); write_uinput_event(springMouseFileHandler, EV_ABS, ABS_X, xDis, false); write_uinput_event(springMouseFileHandler, EV_ABS, ABS_Y, yDis); } void UInputEventHandler::sendMouseSpringEvent(unsigned int xDis, unsigned int yDis, unsigned int width, unsigned int height) { if (width > 0 && height > 0) { double midwidth = static_cast(width) / 2.0; double midheight = static_cast(height) / 2.0; int fx = ceil(32767 * ((xDis - midwidth) / midwidth)); int fy = ceil(32767 * ((yDis - midheight) / midheight)); sendMouseAbsEvent(fx, fy, -1); //write_uinput_event(springMouseFileHandler, EV_ABS, ABS_X, fx, false); //write_uinput_event(springMouseFileHandler, EV_ABS, ABS_Y, fy); } } void UInputEventHandler::sendMouseSpringEvent(int xDis, int yDis) { if (xDis >= -1.0 && xDis <= 1.0 && yDis >= -1.0 && yDis <= 1.0) { int fx = ceil(32767 * xDis); int fy = ceil(32767 * yDis); sendMouseAbsEvent(fx, fy, -1); } } int UInputEventHandler::openUInputHandle() { int filehandle = -1; QStringList locations; locations.append("/dev/input/uinput"); locations.append("/dev/uinput"); locations.append("/dev/misc/uinput"); QString possibleLocation; QStringListIterator iter(locations); while (iter.hasNext()) { QString temp = iter.next(); QFileInfo tempFileInfo(temp); if (tempFileInfo.exists()) { possibleLocation = temp; iter.toBack(); } } if (possibleLocation.isEmpty()) { lastErrorString = tr("Could not find a valid uinput device file.\n" "Please check that you have the uinput module loaded.\n" "lsmod | grep uinput"); } else { QByteArray tempArray = possibleLocation.toUtf8(); filehandle = open(tempArray.constData(), O_WRONLY | O_NONBLOCK); if (filehandle < 0) { lastErrorString = tr("Could not open uinput device file\n" "Please check that you have permission to write to the device"); lastErrorString.append("\n").append(possibleLocation); } else { uinputDeviceLocation = possibleLocation; } } return filehandle; } void UInputEventHandler::setKeyboardEvents(int filehandle) { int result = 0; result = ioctl(filehandle, UI_SET_EVBIT, EV_KEY); result = ioctl(filehandle, UI_SET_EVBIT, EV_SYN); } void UInputEventHandler::setRelMouseEvents(int filehandle) { int result = 0; result = ioctl(filehandle, UI_SET_EVBIT, EV_KEY); result = ioctl(filehandle, UI_SET_EVBIT, EV_SYN); result = ioctl(filehandle, UI_SET_EVBIT, EV_REL); result = ioctl(filehandle, UI_SET_RELBIT, REL_X); result = ioctl(filehandle, UI_SET_RELBIT, REL_Y); result = ioctl(filehandle, UI_SET_RELBIT, REL_WHEEL); result = ioctl(filehandle, UI_SET_RELBIT, REL_HWHEEL); result = ioctl(filehandle, UI_SET_KEYBIT, BTN_LEFT); result = ioctl(filehandle, UI_SET_KEYBIT, BTN_RIGHT); result = ioctl(filehandle, UI_SET_KEYBIT, BTN_MIDDLE); result = ioctl(filehandle, UI_SET_KEYBIT, BTN_SIDE); result = ioctl(filehandle, UI_SET_KEYBIT, BTN_EXTRA); } void UInputEventHandler::setSpringMouseEvents(int filehandle) { int result = 0; result = ioctl(filehandle, UI_SET_EVBIT, EV_KEY); result = ioctl(filehandle, UI_SET_EVBIT, EV_SYN); result = ioctl(filehandle, UI_SET_KEYBIT, BTN_LEFT); result = ioctl(filehandle, UI_SET_KEYBIT, BTN_RIGHT); result = ioctl(filehandle, UI_SET_KEYBIT, BTN_MIDDLE); result = ioctl(filehandle, UI_SET_KEYBIT, BTN_SIDE); result = ioctl(filehandle, UI_SET_KEYBIT, BTN_EXTRA); result = ioctl(filehandle, UI_SET_EVBIT, EV_ABS); result = ioctl(filehandle, UI_SET_ABSBIT, ABS_X); result = ioctl(filehandle, UI_SET_ABSBIT, ABS_Y); result = ioctl(filehandle, UI_SET_KEYBIT, BTN_TOUCH); // BTN_TOOL_PEN is required for the mouse to be seen as an // absolute mouse as opposed to a relative mouse. result = ioctl(filehandle, UI_SET_KEYBIT, BTN_TOOL_PEN); } void UInputEventHandler::populateKeyCodes(int filehandle) { int result = 0; for (unsigned int i=KEY_ESC; i <= KEY_MICMUTE; i++) { result = ioctl(filehandle, UI_SET_KEYBIT, i); } } void UInputEventHandler::createUInputKeyboardDevice(int filehandle) { struct uinput_user_dev uidev; memset(&uidev, 0, sizeof(uidev)); QByteArray temp = keyboardDeviceName.toUtf8(); strncpy(uidev.name, temp.constData(), UINPUT_MAX_NAME_SIZE); uidev.id.bustype = BUS_USB; uidev.id.vendor = 0x0; uidev.id.product = 0x0; uidev.id.version = 1; int result = 0; result = write(filehandle, &uidev, sizeof(uidev)); result = ioctl(filehandle, UI_DEV_CREATE); } void UInputEventHandler::createUInputMouseDevice(int filehandle) { struct uinput_user_dev uidev; memset(&uidev, 0, sizeof(uidev)); QByteArray temp = mouseDeviceName.toUtf8(); strncpy(uidev.name, temp.constData(), UINPUT_MAX_NAME_SIZE); uidev.id.bustype = BUS_USB; uidev.id.vendor = 0x0; uidev.id.product = 0x0; uidev.id.version = 1; int result = 0; result = write(filehandle, &uidev, sizeof(uidev)); result = ioctl(filehandle, UI_DEV_CREATE); } void UInputEventHandler::createUInputSpringMouseDevice(int filehandle) { struct uinput_user_dev uidev; memset(&uidev, 0, sizeof(uidev)); QByteArray temp = springMouseDeviceName.toUtf8(); strncpy(uidev.name, temp.constData(), UINPUT_MAX_NAME_SIZE); uidev.id.bustype = BUS_USB; uidev.id.vendor = 0x0; uidev.id.product = 0x0; uidev.id.version = 1; uidev.absmin[ABS_X] = -32767; uidev.absmax[ABS_X] = 32767; uidev.absflat[ABS_X] = 0; uidev.absmin[ABS_Y] = -32767; uidev.absmax[ABS_Y] = 32767; uidev.absflat[ABS_Y] = 0; int result = 0; result = write(filehandle, &uidev, sizeof(uidev)); result = ioctl(filehandle, UI_DEV_CREATE); } void UInputEventHandler::closeUInputDevice(int filehandle) { int result = 0; result = ioctl(filehandle, UI_DEV_DESTROY); result = close(filehandle); } void UInputEventHandler::write_uinput_event(int filehandle, unsigned int type, unsigned int code, int value, bool syn) { struct input_event ev; struct input_event ev2; memset(&ev, 0, sizeof(struct input_event)); gettimeofday(&ev.time, 0); ev.type = type; ev.code = code; ev.value = value; int result = 0; result = write(filehandle, &ev, sizeof(struct input_event)); if (syn) { memset(&ev2, 0, sizeof(struct input_event)); gettimeofday(&ev2.time, 0); ev2.type = EV_SYN; ev2.code = SYN_REPORT; ev2.value = 0; result = write(filehandle, &ev2, sizeof(struct input_event)); } } QString UInputEventHandler::getName() { return QString("uinput"); } QString UInputEventHandler::getIdentifier() { return getName(); } /** * @brief Print extra help messages to stdout. */ void UInputEventHandler::printPostMessages() { //QTextStream out(stdout); if (!lastErrorString.isEmpty()) { Logger::LogInfo(lastErrorString); } if (!uinputDeviceLocation.isEmpty()) { Logger::LogInfo(tr("Using uinput device file %1").arg(uinputDeviceLocation)); } } void UInputEventHandler::sendTextEntryEvent(QString maintext) { AntKeyMapper *mapper = AntKeyMapper::getInstance(); if (mapper && mapper->getKeyMapper()) { QtUInputKeyMapper *keymapper = static_cast(mapper->getKeyMapper()); QtX11KeyMapper *nativeWinKeyMapper = 0; if (mapper->getNativeKeyMapper()) { nativeWinKeyMapper = static_cast(mapper->getNativeKeyMapper()); } QList tempList; for (int i=0; i < maintext.size(); i++) { tempList.clear(); QtUInputKeyMapper::charKeyInformation temp; temp.virtualkey = 0; temp.modifiers = Qt::NoModifier; if (nativeWinKeyMapper) { QtX11KeyMapper::charKeyInformation tempX11 = nativeWinKeyMapper->getCharKeyInformation(maintext.at(i)); tempX11.virtualkey = X11Extras::getInstance()->getGroup1KeySym(tempX11.virtualkey); unsigned int tempQtKey = nativeWinKeyMapper->returnQtKey(tempX11.virtualkey); if (tempQtKey > 0) { temp.virtualkey = keymapper->returnVirtualKey(tempQtKey); temp.modifiers = tempX11.modifiers; } else { temp = keymapper->getCharKeyInformation(maintext.at(i)); } } else { temp = keymapper->getCharKeyInformation(maintext.at(i)); } if (temp.virtualkey > KEY_RESERVED) { if (temp.modifiers != Qt::NoModifier) { if (temp.modifiers.testFlag(Qt::ShiftModifier)) { tempList.append(KEY_LEFTSHIFT); write_uinput_event(keyboardFileHandler, EV_KEY, KEY_LEFTSHIFT, 1, false); } if (temp.modifiers.testFlag(Qt::ControlModifier)) { tempList.append(KEY_LEFTCTRL); write_uinput_event(keyboardFileHandler, EV_KEY, KEY_LEFTCTRL, 1, false); } if (temp.modifiers.testFlag(Qt::AltModifier)) { tempList.append(KEY_LEFTALT); write_uinput_event(keyboardFileHandler, EV_KEY, KEY_LEFTALT, 1, false); } if (temp.modifiers.testFlag(Qt::MetaModifier)) { tempList.append(KEY_LEFTMETA); write_uinput_event(keyboardFileHandler, EV_KEY, KEY_LEFTMETA, 1, false); } } tempList.append(temp.virtualkey); write_uinput_event(keyboardFileHandler, EV_KEY, temp.virtualkey, 1, true); } if (tempList.size() > 0) { QListIterator tempiter(tempList); tempiter.toBack(); while (tempiter.hasPrevious()) { unsigned int currentcode = tempiter.previous(); bool sync = !tempiter.hasPrevious() ? true : false; write_uinput_event(keyboardFileHandler, EV_KEY, currentcode, 0, sync); } } } } } antimicro-2.23/src/eventhandlers/uinputeventhandler.h000066400000000000000000000050671300750276700231720ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UINPUTEVENTHANDLER_H #define UINPUTEVENTHANDLER_H #include "baseeventhandler.h" #include "../qtx11keymapper.h" #include #include class UInputEventHandler : public BaseEventHandler { Q_OBJECT public: explicit UInputEventHandler(QObject *parent = 0); ~UInputEventHandler(); virtual bool init(); virtual bool cleanup(); virtual void sendKeyboardEvent(JoyButtonSlot *slot, bool pressed); virtual void sendMouseButtonEvent(JoyButtonSlot *slot, bool pressed); virtual void sendMouseEvent(int xDis, int yDis); virtual void sendMouseAbsEvent(int xDis, int yDis, int screen); virtual void sendMouseSpringEvent(unsigned int xDis, unsigned int yDis, unsigned int width, unsigned int height); virtual void sendMouseSpringEvent(int xDis, int yDis); virtual QString getName(); virtual QString getIdentifier(); virtual void printPostMessages(); virtual void sendTextEntryEvent(QString maintext); protected: int openUInputHandle(); void setKeyboardEvents(int filehandle); void setRelMouseEvents(int filehandle); void setSpringMouseEvents(int filehandle); void populateKeyCodes(int filehandle); void createUInputKeyboardDevice(int filehandle); void createUInputMouseDevice(int filehandle); void createUInputSpringMouseDevice(int filehandle); void closeUInputDevice(int filehandle); void write_uinput_event(int filehandle, unsigned int type, unsigned int code, int value, bool syn=true); int keyboardFileHandler; int mouseFileHandler; int springMouseFileHandler; QString uinputDeviceLocation; signals: public slots: private slots: #ifdef WITH_X11 void x11ResetMouseAccelerationChange(); #endif }; #endif // UINPUTEVENTHANDLER_H antimicro-2.23/src/eventhandlers/winsendinputeventhandler.cpp000066400000000000000000000166431300750276700247320ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "winsendinputeventhandler.h" #include #include WinSendInputEventHandler::WinSendInputEventHandler(QObject *parent) : BaseEventHandler(parent) { } bool WinSendInputEventHandler::init() { return true; } bool WinSendInputEventHandler::cleanup() { return true; } void WinSendInputEventHandler::sendKeyboardEvent(JoyButtonSlot *slot, bool pressed) { int code = slot->getSlotCode(); INPUT temp[1] = {}; unsigned int scancode = WinExtras::scancodeFromVirtualKey(code, slot->getSlotCodeAlias()); int extended = (scancode & WinExtras::EXTENDED_FLAG) != 0; int tempflags = extended ? KEYEVENTF_EXTENDEDKEY : 0; temp[0].type = INPUT_KEYBOARD; //temp[0].ki.wScan = MapVirtualKey(code, MAPVK_VK_TO_VSC); temp[0].ki.wScan = scancode; temp[0].ki.time = 0; temp[0].ki.dwExtraInfo = 0; temp[0].ki.wVk = code; temp[0].ki.dwFlags = pressed ? tempflags : (tempflags | KEYEVENTF_KEYUP); // 0 for key press SendInput(1, temp, sizeof(INPUT)); } void WinSendInputEventHandler::sendMouseButtonEvent(JoyButtonSlot *slot, bool pressed) { int code = slot->getSlotCode(); INPUT temp[1] = {}; temp[0].type = INPUT_MOUSE; if (code == 1) { temp[0].mi.dwFlags = pressed ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP; } else if (code == 2) { temp[0].mi.dwFlags = pressed ? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP; } else if (code == 3) { temp[0].mi.dwFlags = pressed ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP; } else if (code == 4) { temp[0].mi.dwFlags = MOUSEEVENTF_WHEEL; temp[0].mi.mouseData = pressed ? WHEEL_DELTA : 0; } else if (code == 5) { temp[0].mi.dwFlags = MOUSEEVENTF_WHEEL; temp[0].mi.mouseData = pressed ? -WHEEL_DELTA : 0; } else if (code == 6) { temp[0].mi.dwFlags = 0x01000; temp[0].mi.mouseData = pressed ? -WHEEL_DELTA : 0; } else if (code == 7) { temp[0].mi.dwFlags = 0x01000; temp[0].mi.mouseData = pressed ? WHEEL_DELTA : 0; } else if (code == 8) { temp[0].mi.dwFlags = pressed ? MOUSEEVENTF_XDOWN : MOUSEEVENTF_XUP; temp[0].mi.mouseData = XBUTTON1; } else if (code == 9) { temp[0].mi.dwFlags = pressed ? MOUSEEVENTF_XDOWN : MOUSEEVENTF_XUP; temp[0].mi.mouseData = XBUTTON2; } SendInput(1, temp, sizeof(INPUT)); } void WinSendInputEventHandler::sendMouseEvent(int xDis, int yDis) { INPUT temp[1] = {}; temp[0].type = INPUT_MOUSE; temp[0].mi.mouseData = 0; temp[0].mi.dwFlags = MOUSEEVENTF_MOVE; temp[0].mi.dx = xDis; temp[0].mi.dy = yDis; SendInput(1, temp, sizeof(INPUT)); } QString WinSendInputEventHandler::getName() { return QString("SendInput"); } QString WinSendInputEventHandler::getIdentifier() { return QString("sendinput"); } void WinSendInputEventHandler::sendMouseSpringEvent(unsigned int xDis, unsigned int yDis, unsigned int width, unsigned int height) { if (width > 0 && height > 0) { INPUT temp[1] = {}; temp[0].type = INPUT_MOUSE; temp[0].mi.mouseData = 0; temp[0].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; int fx = ceil(xDis * (65535.0/static_cast(width))); int fy = ceil(yDis * (65535.0/static_cast(height))); temp[0].mi.dx = fx; temp[0].mi.dy = fy; SendInput(1, temp, sizeof(INPUT)); } } void WinSendInputEventHandler::sendTextEntryEvent(QString maintext) { AntKeyMapper *mapper = AntKeyMapper::getInstance(); if (mapper && mapper->getKeyMapper()) { QtWinKeyMapper *keymapper = static_cast(mapper->getKeyMapper()); for (int i=0; i < maintext.size(); i++) { QtWinKeyMapper::charKeyInformation temp = keymapper->getCharKeyInformation(maintext.at(i)); QList tempList; if (temp.modifiers != Qt::NoModifier) { if (temp.modifiers.testFlag(Qt::ShiftModifier)) { tempList.append(VK_LSHIFT); } if (temp.modifiers.testFlag(Qt::ControlModifier)) { tempList.append(VK_LCONTROL); } if (temp.modifiers.testFlag(Qt::AltModifier)) { tempList.append(VK_LMENU); } if (temp.modifiers.testFlag(Qt::MetaModifier)) { tempList.append(VK_LWIN); } } tempList.append(temp.virtualkey); if (tempList.size() > 0) { INPUT tempBuffer[tempList.size()] = {0}; QListIterator tempiter(tempList); unsigned int j = 0; while (tempiter.hasNext()) { unsigned int tempcode = tempiter.next(); unsigned int scancode = WinExtras::scancodeFromVirtualKey(tempcode); int extended = (scancode & WinExtras::EXTENDED_FLAG) != 0; int tempflags = extended ? KEYEVENTF_EXTENDEDKEY : 0; tempBuffer[j].type = INPUT_KEYBOARD; tempBuffer[j].ki.wScan = scancode; tempBuffer[j].ki.time = 0; tempBuffer[j].ki.dwExtraInfo = 0; tempBuffer[j].ki.wVk = tempcode; tempBuffer[j].ki.dwFlags = tempflags; j++; } SendInput(j, tempBuffer, sizeof(INPUT)); tempiter.toBack(); j = 0; memset(tempBuffer, 0, sizeof(tempBuffer)); //INPUT tempBuffer2[tempList.size()] = {0}; while (tempiter.hasPrevious()) { unsigned int tempcode = tempiter.previous(); unsigned int scancode = WinExtras::scancodeFromVirtualKey(tempcode); int extended = (scancode & WinExtras::EXTENDED_FLAG) != 0; int tempflags = extended ? KEYEVENTF_EXTENDEDKEY : 0; tempBuffer[j].type = INPUT_KEYBOARD; tempBuffer[j].ki.wScan = scancode; tempBuffer[j].ki.time = 0; tempBuffer[j].ki.dwExtraInfo = 0; tempBuffer[j].ki.wVk = tempcode; tempBuffer[j].ki.dwFlags = tempflags | KEYEVENTF_KEYUP; j++; } SendInput(j, tempBuffer, sizeof(INPUT)); } } } } antimicro-2.23/src/eventhandlers/winsendinputeventhandler.h000066400000000000000000000031561300750276700243720ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef WINSENDINPUTEVENTHANDLER_H #define WINSENDINPUTEVENTHANDLER_H #include #include "baseeventhandler.h" #include class WinSendInputEventHandler : public BaseEventHandler { Q_OBJECT public: explicit WinSendInputEventHandler(QObject *parent = 0); virtual bool init(); virtual bool cleanup(); virtual void sendKeyboardEvent(JoyButtonSlot *slot, bool pressed); virtual void sendMouseButtonEvent(JoyButtonSlot *slot, bool pressed); virtual void sendMouseEvent(int xDis, int yDis); virtual void sendMouseSpringEvent(unsigned int xDis, unsigned int yDis, unsigned int width, unsigned int height); virtual void sendTextEntryEvent(QString maintext); virtual QString getName(); virtual QString getIdentifier(); signals: public slots: }; #endif // WINSENDINPUTEVENTHANDLER_H antimicro-2.23/src/eventhandlers/winvmultieventhandler.cpp000066400000000000000000000236431300750276700242370ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include #include "winvmultieventhandler.h" #include WinVMultiEventHandler::WinVMultiEventHandler(QObject *parent) : BaseEventHandler(parent), sendInputHandler(this) { vmulti = 0; mouseButtons = 0; shiftKeys = 0; multiKeys = 0; extraKeys = 0; keyboardKeys.resize(6); keyboardKeys.fill(0); nativeKeyMapper = 0; } WinVMultiEventHandler::~WinVMultiEventHandler() { cleanup(); } bool WinVMultiEventHandler::init() { bool result = true; vmulti = vmulti_alloc(); if (vmulti == NULL) { result = false; } if (vmulti && !vmulti_connect(vmulti)) { vmulti_free(vmulti); vmulti = 0; result = false; } if (vmulti) { nativeKeyMapper = 0; if (AntKeyMapper::getInstance("vmulti")->hasNativeKeyMapper()) { nativeKeyMapper = AntKeyMapper::getInstance("vmulti")->getNativeKeyMapper(); } } return result; } bool WinVMultiEventHandler::cleanup() { bool result = true; if (vmulti) { vmulti_disconnect(vmulti); vmulti_free(vmulti); vmulti = 0; } nativeKeyMapper = 0; return result; } void WinVMultiEventHandler::sendKeyboardEvent(JoyButtonSlot *slot, bool pressed) { int code = slot->getSlotCode(); BYTE pendingShift = 0x0; BYTE pendingMultimedia = 0x0; BYTE pendingExtra = 0x0; BYTE pendingKey = 0x0; JoyButtonSlot tempSendInputSlot(slot); bool useSendInput = false; bool exists = keyboardKeys.contains(code); if (code <= 0x65) { pendingKey = code; } else if (code >= 0xE0 && code <= 0xE7) { //pendingShift = 1 << (code - 0xE0); if (nativeKeyMapper) { unsigned int nativeKey = nativeKeyMapper->returnVirtualKey(slot->getSlotCodeAlias()); if (nativeKey > 0) { tempSendInputSlot.setSlotCode(nativeKey); useSendInput = true; } } } else if (code > QtVMultiKeyMapper::consumerUsagePagePrefix) { if (nativeKeyMapper) { unsigned int nativeKey = nativeKeyMapper->returnVirtualKey(slot->getSlotCodeAlias()); if (nativeKey > 0) { tempSendInputSlot.setSlotCode(nativeKey); useSendInput = true; } } /*if (code == 0xB5 | QtVMultiKeyMapper::consumerUsagePagePrefix) { pendingMultimedia = 1 << 0; // (Scan Next Track) } else if (code == 0xB6 | QtVMultiKeyMapper::consumerUsagePagePrefix) { pendingMultimedia = 1 << 1; // (Scan Previous Track) } else if (code == 0xB1 | QtVMultiKeyMapper::consumerUsagePagePrefix) { pendingMultimedia = 1 << 3; // (Play / Pause) } else if (code == 0x189 | QtVMultiKeyMapper::consumerUsagePagePrefix) { pendingMultimedia = 1 << 6; // (WWW Home) } else if (code == 0x194 | QtVMultiKeyMapper::consumerUsagePagePrefix) { pendingExtra = 1 << 0; // (My Computer) } else if (code == 0x192 | QtVMultiKeyMapper::consumerUsagePagePrefix) { pendingExtra = 1 << 1; // (Calculator) } else if (code == 0x22a | QtVMultiKeyMapper::consumerUsagePagePrefix) { pendingExtra = 1 << 2; // (WWW fav) } else if (code == 0x221 | QtVMultiKeyMapper::consumerUsagePagePrefix) { pendingExtra = 1 << 3; // (WWW search) } else if (code == 0xB7 | QtVMultiKeyMapper::consumerUsagePagePrefix) { pendingExtra = 1 << 3; // (WWW stop) } else if (code == 0x224 | QtVMultiKeyMapper::consumerUsagePagePrefix) { pendingExtra = 1 << 4; // (WWW back) } else if (code == 0x87 | QtVMultiKeyMapper::consumerUsagePagePrefix) { pendingExtra = 1 << 5; // (Media Select) } else if (code == 0x18a | QtVMultiKeyMapper::consumerUsagePagePrefix) { pendingExtra = 1 << 6; // (Mail) } */ } else if (code > 0x65) { if (nativeKeyMapper) { unsigned int nativeKey = nativeKeyMapper->returnVirtualKey(slot->getSlotCodeAlias()); if (nativeKey > 0) { tempSendInputSlot.setSlotCode(nativeKey); //sendInputHandler.sendKeyboardEvent(tempslot, pressed); useSendInput = true; } } /*if (code == 0x78) { pendingMultimedia = 1 << 2; // (Stop) } else if (code == 0x7F) { pendingMultimedia = 1 << 4; // (Mute) } else if (code == 0x81) { pendingMultimedia = 1 << 5; // (Volume Down) } else if (code == 0x80) { pendingMultimedia = 1 << 6; // (Volume Up) } */ } if (!useSendInput) { if (pressed) { shiftKeys = shiftKeys | pendingShift; multiKeys = multiKeys | pendingMultimedia; extraKeys = extraKeys | pendingExtra; if (!exists) { // Check for an empty key value int index = keyboardKeys.indexOf(0); if (index != -1) { keyboardKeys.replace(index, pendingKey); } } } else { shiftKeys = shiftKeys ^ pendingShift; multiKeys = multiKeys ^ pendingMultimedia; extraKeys = extraKeys ^ pendingExtra; if (exists) { int index = keyboardKeys.indexOf(pendingKey); if (index != -1) { keyboardKeys.replace(index, 0); } } } BYTE *keykeyArray = keyboardKeys.data(); /*QStringList trying; for (int i=0; i < 6; i++) { BYTE current = keykeyArray[i]; trying.append(QString("0x%1").arg(QString::number(current, 16))); } */ //qDebug() << "CURRENT: " << trying.join(","); //qDebug() << keykeyArray; if (pendingKey > 0x0) { vmulti_update_keyboard(vmulti, shiftKeys, keykeyArray); } if (pendingMultimedia > 0 || pendingExtra > 0) { //vmulti_update_keyboard_enhanced(vmulti, multiKeys, extraKeys); } } else { sendInputHandler.sendKeyboardEvent(&tempSendInputSlot, pressed); useSendInput = false; } } void WinVMultiEventHandler::sendMouseButtonEvent(JoyButtonSlot *slot, bool pressed) { BYTE pendingButton = 0; BYTE pendingWheel = 0; BYTE pendingHWheel = 0; bool useSendInput = false; int code = slot->getSlotCode(); if (code == 1) { pendingButton = 0x01; } else if (code == 2) { pendingButton = 0x04; } else if (code == 3) { pendingButton = 0x02; } else if (code == 4) { pendingWheel = pressed ? 1 : 0; } else if (code == 5) { pendingWheel = pressed ? -1 : 0; } else if (code >= 6 && code <= 9) { useSendInput = true; } /* else if (code == 6) { pendingHWheel = pressed ? -1 : 0; } else if (code == 7) { pendingHWheel = pressed ? 1 : 0; } else if (code == 8) { pendingButton = 0x08; } else if (code == 9) { pendingButton = 0x10; } */ if (!useSendInput) { if (pressed) { mouseButtons = mouseButtons | pendingButton; vmulti_update_relative_mouse(vmulti, mouseButtons, 0, 0, pendingWheel);//, pendingHWheel); } else { mouseButtons = mouseButtons ^ pendingButton; vmulti_update_relative_mouse(vmulti, mouseButtons, 0, 0, pendingWheel);//, pendingHWheel); } } else { sendInputHandler.sendMouseButtonEvent(slot, pressed); } } void WinVMultiEventHandler::sendMouseEvent(int xDis, int yDis) { vmulti_update_relative_mouse(vmulti, mouseButtons, xDis, yDis, 0);//, 0); } void WinVMultiEventHandler::sendMouseSpringEvent(unsigned int xDis, unsigned int yDis, unsigned int width, unsigned int height) { if (width > 0 && height > 0) { int fx = ceil(xDis * (32767.0/static_cast(width))); int fy = ceil(yDis * (32767.0/static_cast(height))); sendMouseAbsEvent(fx, fy, -1); } } void WinVMultiEventHandler::sendMouseAbsEvent(int xDis, int yDis, int screen) { Q_UNUSED(screen); vmulti_update_mouse(vmulti, mouseButtons, xDis, yDis, 0);//, 0); } /* * TODO: Implement text event using information from QtWinKeyMapper. */ void WinVMultiEventHandler::sendTextEntryEvent(QString maintext) { sendInputHandler.sendTextEntryEvent(maintext); } QString WinVMultiEventHandler::getName() { return QString("Vmulti"); } QString WinVMultiEventHandler::getIdentifier() { return QString("vmulti"); } antimicro-2.23/src/eventhandlers/winvmultieventhandler.h000066400000000000000000000041521300750276700236760ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef WINVMULTIEVENTHANDLER_H #define WINVMULTIEVENTHANDLER_H #include #include #include "baseeventhandler.h" #include #include #include #include "winsendinputeventhandler.h" class WinVMultiEventHandler : public BaseEventHandler { Q_OBJECT public: explicit WinVMultiEventHandler(QObject *parent = 0); ~WinVMultiEventHandler(); virtual bool init(); virtual bool cleanup(); virtual void sendKeyboardEvent(JoyButtonSlot *slot, bool pressed); virtual void sendMouseButtonEvent(JoyButtonSlot *slot, bool pressed); virtual void sendMouseEvent(int xDis, int yDis); virtual void sendMouseAbsEvent(int xDis, int yDis, int screen); virtual void sendMouseSpringEvent(unsigned int xDis, unsigned int yDis, unsigned int width, unsigned int height); // TODO: Implement text event using information from QtWinKeyMapper. virtual void sendTextEntryEvent(QString maintext); virtual QString getName(); virtual QString getIdentifier(); protected: pvmulti_client vmulti; BYTE mouseButtons; BYTE shiftKeys; BYTE multiKeys; BYTE extraKeys; QVector keyboardKeys; WinSendInputEventHandler sendInputHandler; QtKeyMapperBase *nativeKeyMapper; signals: public slots: }; #endif // WINVMULTIEVENTHANDLER_H antimicro-2.23/src/eventhandlers/xtesteventhandler.cpp000066400000000000000000000154011300750276700233410ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "xtesteventhandler.h" #include #include #include #include #include #include #include XTestEventHandler::XTestEventHandler(QObject *parent) : BaseEventHandler(parent) { } bool XTestEventHandler::init() { X11Extras *instance = X11Extras::getInstance(); if (instance) { instance->x11ResetMouseAccelerationChange(X11Extras::xtestMouseDeviceName); } return true; } bool XTestEventHandler::cleanup() { return true; } void XTestEventHandler::sendKeyboardEvent(JoyButtonSlot *slot, bool pressed) { Display* display = X11Extras::getInstance()->display(); JoyButtonSlot::JoySlotInputAction device = slot->getSlotMode(); int code = slot->getSlotCode(); if (device == JoyButtonSlot::JoyKeyboard) { unsigned int tempcode = XKeysymToKeycode(display, code); if (tempcode > 0) { XTestFakeKeyEvent(display, tempcode, pressed, 0); XFlush(display); } } } void XTestEventHandler::sendMouseButtonEvent(JoyButtonSlot *slot, bool pressed) { Display* display = X11Extras::getInstance()->display(); JoyButtonSlot::JoySlotInputAction device = slot->getSlotMode(); int code = slot->getSlotCode(); if (device == JoyButtonSlot::JoyMouseButton) { XTestFakeButtonEvent(display, code, pressed, 0); XFlush(display); } } void XTestEventHandler::sendMouseEvent(int xDis, int yDis) { Display* display = X11Extras::getInstance()->display(); XTestFakeRelativeMotionEvent(display, xDis, yDis, 0); XFlush(display); } void XTestEventHandler::sendMouseAbsEvent(int xDis, int yDis, int screen) { Display* display = X11Extras::getInstance()->display(); XTestFakeMotionEvent(display, screen, xDis, yDis, 0); XFlush(display); } QString XTestEventHandler::getName() { return QString("XTest"); } QString XTestEventHandler::getIdentifier() { return QString("xtest"); } void XTestEventHandler::sendTextEntryEvent(QString maintext) { AntKeyMapper *mapper = AntKeyMapper::getInstance(); // Populated as needed. unsigned int shiftcode = 0; unsigned int controlcode = 0; unsigned int metacode = 0; unsigned int altcode = 0; if (mapper && mapper->getKeyMapper()) { //Qt::KeyboardModifiers originalModifiers = Qt::KeyboardModifiers(QApplication::keyboardModifiers()); //Qt::KeyboardModifiers currentModifiers = Qt::KeyboardModifiers(QApplication::keyboardModifiers()); Display* display = X11Extras::getInstance()->display(); QtX11KeyMapper *keymapper = static_cast(mapper->getKeyMapper()); for (int i=0; i < maintext.size(); i++) { QtX11KeyMapper::charKeyInformation temp = keymapper->getCharKeyInformation(maintext.at(i)); unsigned int tempcode = XKeysymToKeycode(display, temp.virtualkey); if (tempcode > 0) { QList tempList; if (temp.modifiers != Qt::NoModifier) { if (temp.modifiers.testFlag(Qt::ShiftModifier)) { if (shiftcode == 0) { shiftcode = XKeysymToKeycode(display, XK_Shift_L); } unsigned int modifiercode = shiftcode; XTestFakeKeyEvent(display, modifiercode, 1, 0); //currentModifiers |= Qt::ShiftModifier; tempList.append(modifiercode); } if (temp.modifiers.testFlag(Qt::ControlModifier)) { if (controlcode == 0) { controlcode = XKeysymToKeycode(display, XK_Control_L); } unsigned int modifiercode = controlcode; XTestFakeKeyEvent(display, modifiercode, 1, 0); //currentModifiers |= Qt::ControlModifier; tempList.append(modifiercode); } if (temp.modifiers.testFlag(Qt::AltModifier)) { if (altcode == 0) { altcode = XKeysymToKeycode(display, XK_Alt_L); } unsigned int modifiercode = altcode; XTestFakeKeyEvent(display, modifiercode, 1, 0); //currentModifiers |= Qt::AltModifier; tempList.append(modifiercode); } if (temp.modifiers.testFlag(Qt::MetaModifier)) { if (metacode == 0) { metacode = XKeysymToKeycode(display, XK_Meta_L); } unsigned int modifiercode = metacode; XTestFakeKeyEvent(display, modifiercode, 1, 0); //currentModifiers |= Qt::MetaModifier; tempList.append(modifiercode); } } XTestFakeKeyEvent(display, tempcode, 1, 0); tempList.append(tempcode); XFlush(display); if (tempList.size() > 0) { QListIterator tempiter(tempList); tempiter.toBack(); while (tempiter.hasPrevious()) { unsigned int currentcode = tempiter.previous(); XTestFakeKeyEvent(display, currentcode, 0, 0); } XFlush(display); } } } // Perform a flush at the end. //XFlush(display); // Restore modifiers in place /*if (originalModifiers != currentModifiers) { } */ } } antimicro-2.23/src/eventhandlers/xtesteventhandler.h000066400000000000000000000027371300750276700230160ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef XTESTEVENTHANDLER_H #define XTESTEVENTHANDLER_H #include "baseeventhandler.h" #include class XTestEventHandler : public BaseEventHandler { Q_OBJECT public: explicit XTestEventHandler(QObject *parent = 0); virtual bool init(); virtual bool cleanup(); virtual void sendKeyboardEvent(JoyButtonSlot *slot, bool pressed); virtual void sendMouseButtonEvent(JoyButtonSlot *slot, bool pressed); virtual void sendMouseEvent(int xDis, int yDis); virtual void sendMouseAbsEvent(int xDis, int yDis, int screen); virtual QString getName(); virtual QString getIdentifier(); virtual void sendTextEntryEvent(QString maintext); signals: public slots: }; #endif // XTESTEVENTHANDLER_H antimicro-2.23/src/extraprofilesettingsdialog.cpp000066400000000000000000000042211300750276700223730ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include "extraprofilesettingsdialog.h" #include "ui_extraprofilesettingsdialog.h" ExtraProfileSettingsDialog::ExtraProfileSettingsDialog(InputDevice *device, QWidget *parent) : QDialog(parent), ui(new Ui::ExtraProfileSettingsDialog) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); this->device = device; ui->pressValueLabel->setText(QString::number(0.10, 'g', 3).append("").append(tr("s"))); if (device->getDeviceKeyPressTime() > 0) { int temppress = device->getDeviceKeyPressTime(); ui->keyPressHorizontalSlider->setValue(device->getDeviceKeyPressTime() / 10); ui->pressValueLabel->setText(QString::number(temppress / 1000.0, 'g', 3).append("").append(tr("s"))); } if (!device->getProfileName().isEmpty()) { ui->profileNameLineEdit->setText(device->getProfileName()); } connect(ui->keyPressHorizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(changeDeviceKeyPress(int))); connect(ui->profileNameLineEdit, SIGNAL(textChanged(QString)), device, SLOT(setProfileName(QString))); } ExtraProfileSettingsDialog::~ExtraProfileSettingsDialog() { delete ui; } void ExtraProfileSettingsDialog::changeDeviceKeyPress(int value) { int temppress = value * 10; device->setDeviceKeyPressTime(temppress); ui->pressValueLabel->setText(QString::number(temppress / 1000.0, 'g', 3).append("").append(tr("s"))); } antimicro-2.23/src/extraprofilesettingsdialog.h000066400000000000000000000023711300750276700220440ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef KEYDELAYDIALOG_H #define KEYDELAYDIALOG_H #include #include "inputdevice.h" namespace Ui { class ExtraProfileSettingsDialog; } class ExtraProfileSettingsDialog : public QDialog { Q_OBJECT public: explicit ExtraProfileSettingsDialog(InputDevice *device, QWidget *parent = 0); ~ExtraProfileSettingsDialog(); protected: InputDevice *device; private: Ui::ExtraProfileSettingsDialog *ui; private slots: void changeDeviceKeyPress(int value); }; #endif // KEYDELAYDIALOG_H antimicro-2.23/src/extraprofilesettingsdialog.ui000066400000000000000000000075421300750276700222370ustar00rootroot00000000000000 ExtraProfileSettingsDialog 0 0 439 144 396 136 Extra Profile Settings true 10 10 20 0 Key Press Time: 1 100 10 Qt::Horizontal 0.00 ms 36 Profile Name: 50 Qt::Vertical QSizePolicy::Fixed 20 10 Qt::Horizontal QDialogButtonBox::Close buttonBox accepted() ExtraProfileSettingsDialog accept() 248 254 157 274 buttonBox rejected() ExtraProfileSettingsDialog reject() 316 260 286 274 antimicro-2.23/src/flashbuttonwidget.cpp000066400000000000000000000062211300750276700204650ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include #include "flashbuttonwidget.h" FlashButtonWidget::FlashButtonWidget(QWidget *parent) : QPushButton(parent) { isflashing = false; displayNames = false; leftAlignText = false; } FlashButtonWidget::FlashButtonWidget(bool displayNames, QWidget *parent) : QPushButton(parent) { isflashing = false; this->displayNames = displayNames; leftAlignText = false; } void FlashButtonWidget::flash() { isflashing = true; this->style()->unpolish(this); this->style()->polish(this); emit flashed(isflashing); } void FlashButtonWidget::unflash() { isflashing = false; this->style()->unpolish(this); this->style()->polish(this); emit flashed(isflashing); } void FlashButtonWidget::refreshLabel() { setText(generateLabel()); } bool FlashButtonWidget::isButtonFlashing() { return isflashing; } void FlashButtonWidget::toggleNameDisplay() { displayNames = !displayNames; refreshLabel(); } void FlashButtonWidget::setDisplayNames(bool display) { displayNames = display; } bool FlashButtonWidget::isDisplayingNames() { return displayNames; } void FlashButtonWidget::paintEvent(QPaintEvent *event) { QPainter painter(this); QFont tempScaledFont = painter.font(); QFont temp; tempScaledFont.setPointSize(temp.pointSize()); QFontMetrics fm(tempScaledFont); bool reduce = false; while ((this->width() < fm.width(text())) && tempScaledFont.pointSize() >= 7) { tempScaledFont.setPointSize(tempScaledFont.pointSize()-1); painter.setFont(tempScaledFont); fm = painter.fontMetrics(); reduce = true; } bool changeFontSize = this->font().pointSize() != tempScaledFont.pointSize(); if (changeFontSize) { if (reduce && !leftAlignText) { leftAlignText = !leftAlignText; setStyleSheet("text-align: left;"); this->style()->unpolish(this); this->style()->polish(this); } else if (!reduce && leftAlignText) { leftAlignText = !leftAlignText; setStyleSheet("text-align: center;"); this->style()->unpolish(this); this->style()->polish(this); } this->setFont(tempScaledFont); } QPushButton::paintEvent(event); } void FlashButtonWidget::retranslateUi() { refreshLabel(); } antimicro-2.23/src/flashbuttonwidget.h000066400000000000000000000032351300750276700201340ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef FLASHBUTTONWIDGET_H #define FLASHBUTTONWIDGET_H #include #include class FlashButtonWidget : public QPushButton { Q_OBJECT Q_PROPERTY(bool isflashing READ isButtonFlashing) public: explicit FlashButtonWidget(QWidget *parent = 0); explicit FlashButtonWidget(bool displayNames, QWidget *parent = 0); bool isButtonFlashing(); void setDisplayNames(bool display); bool isDisplayingNames(); protected: virtual void paintEvent(QPaintEvent *event); virtual QString generateLabel() = 0; virtual void retranslateUi(); bool isflashing; bool displayNames; bool leftAlignText; signals: void flashed(bool flashing); public slots: void refreshLabel(); void toggleNameDisplay(); virtual void disableFlashes() = 0; virtual void enableFlashes() = 0; protected slots: void flash(); void unflash(); }; #endif // FLASHBUTTONWIDGET_H antimicro-2.23/src/gamecontroller/000077500000000000000000000000001300750276700172405ustar00rootroot00000000000000antimicro-2.23/src/gamecontroller/gamecontroller.cpp000066400000000000000000001104721300750276700227660ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include "gamecontroller.h" //#include "logger.h" const QString GameController::xmlName = "gamecontroller"; GameController::GameController(SDL_GameController *controller, int deviceIndex, AntiMicroSettings *settings, QObject *parent) : InputDevice(deviceIndex, settings, parent) { this->controller = controller; SDL_Joystick *joyhandle = SDL_GameControllerGetJoystick(controller); joystickID = SDL_JoystickInstanceID(joyhandle); for (int i=0; i < NUMBER_JOYSETS; i++) { GameControllerSet *controllerset = new GameControllerSet(this, i, this); joystick_sets.insert(i, controllerset); enableSetConnections(controllerset); } } QString GameController::getName() { return QString(tr("Game Controller")).append(" ").append(QString::number(getRealJoyNumber())); } QString GameController::getSDLName() { QString temp; if (controller) { temp = SDL_GameControllerName(controller); } return temp; } QString GameController::getGUIDString() { QString temp = getRawGUIDString(); #ifdef Q_OS_WIN // On Windows, if device is seen as a game controller by SDL // and the device has an empty GUID, assume that it is an XInput // compatible device. Send back xinput as the GUID since SDL uses it // internally anyway. /*if (!temp.isEmpty() && temp.contains(emptyGUID)) { temp = "xinput"; } */ #endif return temp; } QString GameController::getRawGUIDString() { QString temp; if (controller) { SDL_Joystick *joyhandle = SDL_GameControllerGetJoystick(controller); if (joyhandle) { SDL_JoystickGUID tempGUID = SDL_JoystickGetGUID(joyhandle); char guidString[65] = {'0'}; SDL_JoystickGetGUIDString(tempGUID, guidString, sizeof(guidString)); temp = QString(guidString); } } return temp; } QString GameController::getXmlName() { return this->xmlName; } void GameController::closeSDLDevice() { if (controller && SDL_GameControllerGetAttached(controller)) { SDL_GameControllerClose(controller); controller = 0; } } int GameController::getNumberRawButtons() { return SDL_CONTROLLER_BUTTON_MAX; } int GameController::getNumberRawAxes() { return SDL_CONTROLLER_AXIS_MAX; } int GameController::getNumberRawHats() { return 0; } void GameController::readJoystickConfig(QXmlStreamReader *xml) { if (xml->isStartElement() && xml->name() == "joystick") { //reset(); transferReset(); QHash buttons; QHash axes; QList hatButtons; for (int i=(int)SDL_CONTROLLER_BUTTON_A; i < (int)SDL_CONTROLLER_BUTTON_MAX; i++) { SDL_GameControllerButton currentButton = (SDL_GameControllerButton)i; SDL_GameControllerButtonBind bound = SDL_GameControllerGetBindForButton(this->controller, currentButton); if (bound.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON) { buttons.insert(bound.value.button, currentButton); } else if (bound.bindType == SDL_CONTROLLER_BINDTYPE_HAT) { hatButtons.append(bound); } } for (int i=(int)SDL_CONTROLLER_AXIS_LEFTX; i < (int)SDL_CONTROLLER_AXIS_MAX; i++) { SDL_GameControllerAxis currentAxis = (SDL_GameControllerAxis)i; SDL_GameControllerButtonBind bound = SDL_GameControllerGetBindForAxis(this->controller, currentAxis); if (bound.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) { axes.insert(bound.value.axis, currentAxis); } } xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "joystick")) { if (xml->name() == "sets" && xml->isStartElement()) { xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "sets")) { if (xml->name() == "set" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); index = index - 1; if (index >= 0 && index < joystick_sets.size()) { GameControllerSet *currentSet = static_cast(joystick_sets.value(index)); currentSet->readJoystickConfig(xml, buttons, axes, hatButtons); } } else { // If none of the above, skip the element xml->skipCurrentElement(); } xml->readNextStartElement(); } } else if (xml->name() == "names" && xml->isStartElement()) { bool dpadNameExists = false; bool vdpadNameExists = false; xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "names")) { if (xml->name() == "buttonname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty()) { SDL_GameControllerButton current = buttons.value(index); if (current) { setButtonName(current, temp); } } } else if (xml->name() == "axisbuttonname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); int buttonIndex = xml->attributes().value("button").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; buttonIndex = buttonIndex - 1; if (index >= 0 && !temp.isEmpty()) { SDL_GameControllerAxis current = axes.value(index); if (current) { if (current == SDL_CONTROLLER_AXIS_LEFTX) { setStickButtonName(0, buttonIndex, temp); } else if (current == SDL_CONTROLLER_AXIS_LEFTY) { setStickButtonName(0, buttonIndex, temp); } else if (current == SDL_CONTROLLER_AXIS_RIGHTX) { setStickButtonName(1, buttonIndex, temp); } else if (current == SDL_CONTROLLER_AXIS_RIGHTY) { setStickButtonName(1, buttonIndex, temp); } else if (current == SDL_CONTROLLER_AXIS_TRIGGERLEFT) { setAxisName(current, temp); } else if (current == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) { setAxisName(current, temp); } } } } else if (xml->name() == "controlstickbuttonname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); int buttonIndex = xml->attributes().value("button").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty()) { setStickButtonName(index, buttonIndex, temp); } } else if (xml->name() == "dpadbuttonname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); int buttonIndex = xml->attributes().value("button").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty()) { bool found = false; QListIterator iter(hatButtons); SDL_GameControllerButtonBind current; while (iter.hasNext()) { current = iter.next(); if (current.value.hat.hat == index) { found = true; iter.toBack(); } } if (found) { VDPad *dpad = getActiveSetJoystick()->getVDPad(0); if (dpad) { JoyDPadButton *dpadbutton = dpad->getJoyButton(buttonIndex); if (dpad && dpadbutton->getActionName().isEmpty()) { setVDPadButtonName(index, buttonIndex, temp); } } } } } else if (xml->name() == "vdpadbuttonname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); int buttonIndex = xml->attributes().value("button").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty()) { bool found = false; QListIterator iter(hatButtons); SDL_GameControllerButtonBind current; while (iter.hasNext()) { current = iter.next(); if (current.value.hat.hat == index) { found = true; iter.toBack(); } } if (found) { VDPad *dpad = getActiveSetJoystick()->getVDPad(0); if (dpad) { JoyDPadButton *dpadbutton = dpad->getJoyButton(buttonIndex); if (dpad && dpadbutton->getActionName().isEmpty()) { setVDPadButtonName(index, buttonIndex, temp); } } } } } else if (xml->name() == "axisname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty()) { if (axes.contains(index)) { SDL_GameControllerAxis current = axes.value(index); setAxisName((int)current, temp); } } } else if (xml->name() == "controlstickname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty()) { setStickName(index, temp); } } else if (xml->name() == "dpadname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty() && !vdpadNameExists) { bool found = false; QListIterator iter(hatButtons); SDL_GameControllerButtonBind current; while (iter.hasNext()) { current = iter.next(); if (current.value.hat.hat == index) { found = true; iter.toBack(); } } if (found) { dpadNameExists = true; VDPad *dpad = getActiveSetJoystick()->getVDPad(0); if (dpad) { if (dpad->getDpadName().isEmpty()) { setVDPadName(index, temp); } } } } } else if (xml->name() == "vdpadname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty() && !dpadNameExists) { bool found = false; QListIterator iter(hatButtons); SDL_GameControllerButtonBind current; while (iter.hasNext()) { current = iter.next(); if (current.value.hat.hat == index) { found = true; iter.toBack(); } } if (found) { vdpadNameExists = true; VDPad *dpad = getActiveSetJoystick()->getVDPad(0); if (dpad) { if (dpad->getDpadName().isEmpty()) { setVDPadName(index, temp); } } } } } else { // If none of the above, skip the element xml->skipCurrentElement(); } xml->readNextStartElement(); } } else if (xml->name() == "keyPressTime" && xml->isStartElement()) { QString temptext = xml->readElementText(); int tempchoice = temptext.toInt(); if (tempchoice >= 10) { this->setDeviceKeyPressTime(tempchoice); } } else if (xml->name() == "profilename" && xml->isStartElement()) { QString temptext = xml->readElementText(); this->setProfileName(temptext); } else { // If none of the above, skip the element xml->skipCurrentElement(); } xml->readNextStartElement(); } reInitButtons(); } } void GameController::readConfig(QXmlStreamReader *xml) { if (xml->isStartElement() && xml->name() == getXmlName()) { //reset(); transferReset(); xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != getXmlName())) { if (xml->name() == "sets" && xml->isStartElement()) { xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "sets")) { if (xml->name() == "set" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); index = index - 1; if (index >= 0 && index < joystick_sets.size()) { joystick_sets.value(index)->readConfig(xml); } } else { // If none of the above, skip the element xml->skipCurrentElement(); } xml->readNextStartElement(); } } else if (xml->name() == "names" && xml->isStartElement()) { xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "names")) { if (xml->name() == "buttonname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty()) { setButtonName(index, temp); } } else if (xml->name() == "triggerbuttonname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); int buttonIndex = xml->attributes().value("button").toString().toInt(); QString temp = xml->readElementText(); index = (index - 1) + SDL_CONTROLLER_AXIS_TRIGGERLEFT; buttonIndex = buttonIndex - 1; if ((index == SDL_CONTROLLER_AXIS_TRIGGERLEFT || index == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) && !temp.isEmpty()) { setAxisButtonName(index, buttonIndex, temp); } } else if (xml->name() == "controlstickbuttonname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); int buttonIndex = xml->attributes().value("button").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty()) { setStickButtonName(index, buttonIndex, temp); } } else if (xml->name() == "dpadbuttonname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); int buttonIndex = xml->attributes().value("button").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty()) { setVDPadButtonName(index, buttonIndex, temp); } } else if (xml->name() == "triggername" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); QString temp = xml->readElementText(); index = (index - 1) + SDL_CONTROLLER_AXIS_TRIGGERLEFT; if ((index == SDL_CONTROLLER_AXIS_TRIGGERLEFT || index == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) && !temp.isEmpty()) { setAxisName(index, temp); } } else if (xml->name() == "controlstickname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty()) { setStickName(index, temp); } } else if (xml->name() == "dpadname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty()) { setVDPadName(index, temp); } } else { // If none of the above, skip the element xml->skipCurrentElement(); } xml->readNextStartElement(); } } else if (xml->name() == "keyPressTime" && xml->isStartElement()) { QString temptext = xml->readElementText(); int tempchoice = temptext.toInt(); if (tempchoice >= 10) { this->setDeviceKeyPressTime(tempchoice); } } else if (xml->name() == "profilename" && xml->isStartElement()) { QString temptext = xml->readElementText(); this->setProfileName(temptext); } else { // If none of the above, skip the element xml->skipCurrentElement(); } xml->readNextStartElement(); } reInitButtons(); } else if (xml->isStartElement() && xml->name() == "joystick") { this->readJoystickConfig(xml); } } void GameController::writeConfig(QXmlStreamWriter *xml) { xml->writeStartElement(getXmlName()); xml->writeAttribute("configversion", QString::number(PadderCommon::LATESTCONFIGFILEVERSION)); xml->writeAttribute("appversion", PadderCommon::programVersion); xml->writeComment("The SDL name for a joystick is included for informational purposes only."); xml->writeTextElement("sdlname", getSDLName()); #ifdef USE_SDL_2 xml->writeComment("The GUID for a joystick is included for informational purposes only."); xml->writeTextElement("guid", getGUIDString()); #endif if (!profileName.isEmpty()) { xml->writeTextElement("profilename", profileName); } xml->writeStartElement("names"); // SetJoystick *tempSet = getActiveSetJoystick(); for (int i=0; i < getNumberButtons(); i++) { JoyButton *button = tempSet->getJoyButton(i); if (button && !button->getButtonName().isEmpty()) { xml->writeStartElement("buttonname"); xml->writeAttribute("index", QString::number(button->getRealJoyNumber())); xml->writeCharacters(button->getButtonName()); xml->writeEndElement(); } } for (int i=0; i < getNumberAxes(); i++) { JoyAxis *axis = tempSet->getJoyAxis(i); if (axis) { if (!axis->getAxisName().isEmpty()) { xml->writeStartElement("axisname"); xml->writeAttribute("index", QString::number(axis->getRealJoyIndex())); xml->writeCharacters(axis->getAxisName()); xml->writeEndElement(); } JoyAxisButton *naxisbutton = axis->getNAxisButton(); if (!naxisbutton->getButtonName().isEmpty()) { xml->writeStartElement("axisbuttonname"); xml->writeAttribute("index", QString::number(axis->getRealJoyIndex())); xml->writeAttribute("button", QString::number(naxisbutton->getRealJoyNumber())); xml->writeCharacters(naxisbutton->getButtonName()); xml->writeEndElement(); } JoyAxisButton *paxisbutton = axis->getPAxisButton(); if (!paxisbutton->getButtonName().isEmpty()) { xml->writeStartElement("axisbuttonname"); xml->writeAttribute("index", QString::number(axis->getRealJoyIndex())); xml->writeAttribute("button", QString::number(paxisbutton->getRealJoyNumber())); xml->writeCharacters(paxisbutton->getButtonName()); xml->writeEndElement(); } } } for (int i=0; i < getNumberSticks(); i++) { JoyControlStick *stick = tempSet->getJoyStick(i); if (stick) { if (!stick->getStickName().isEmpty()) { xml->writeStartElement("controlstickname"); xml->writeAttribute("index", QString::number(stick->getRealJoyIndex())); xml->writeCharacters(stick->getStickName()); xml->writeEndElement(); } QHash *buttons = stick->getButtons(); QHashIterator iter(*buttons); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); if (button && !button->getButtonName().isEmpty()) { xml->writeStartElement("controlstickbuttonname"); xml->writeAttribute("index", QString::number(stick->getRealJoyIndex())); xml->writeAttribute("button", QString::number(button->getRealJoyNumber())); xml->writeCharacters(button->getButtonName()); xml->writeEndElement(); } } } } for (int i=0; i < getNumberVDPads(); i++) { VDPad *vdpad = getActiveSetJoystick()->getVDPad(i); if (vdpad) { if (!vdpad->getDpadName().isEmpty()) { xml->writeStartElement("dpadname"); xml->writeAttribute("index", QString::number(vdpad->getRealJoyNumber())); xml->writeCharacters(vdpad->getDpadName()); xml->writeEndElement(); } QHash *temp = vdpad->getButtons(); QHashIterator iter(*temp); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); if (button && !button->getButtonName().isEmpty()) { xml->writeStartElement("dpadbutton"); xml->writeAttribute("index", QString::number(vdpad->getRealJoyNumber())); xml->writeAttribute("button", QString::number(button->getRealJoyNumber())); xml->writeCharacters(button->getButtonName()); xml->writeEndElement(); } } } } xml->writeEndElement(); // if (keyPressTime > 0 && keyPressTime != DEFAULTKEYPRESSTIME) { xml->writeTextElement("keyPressTime", QString::number(keyPressTime)); } xml->writeStartElement("sets"); for (int i=0; i < joystick_sets.size(); i++) { joystick_sets.value(i)->writeConfig(xml); } xml->writeEndElement(); xml->writeEndElement(); } QString GameController::getBindStringForAxis(int index, bool trueIndex) { QString temp; SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(controller, static_cast(index)); if (bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE) { int offset = trueIndex ? 0 : 1; if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON) { temp.append(QString("Button %1").arg(bind.value.button + offset)); } else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) { temp.append(QString("Axis %1").arg(bind.value.axis + offset)); } } return temp; } QString GameController::getBindStringForButton(int index, bool trueIndex) { QString temp; SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForButton(controller, static_cast(index)); if (bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE) { int offset = trueIndex ? 0 : 1; if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON) { temp.append(QString("Button %1").arg(bind.value.button + offset)); } else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) { temp.append(QString("Axis %1").arg(bind.value.axis + offset)); } else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_HAT) { temp.append(QString("Hat %1.%2").arg(bind.value.hat.hat + offset) .arg(bind.value.hat.hat_mask)); } } return temp; } SDL_GameControllerButtonBind GameController::getBindForAxis(int index) { SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForAxis(controller, (SDL_GameControllerAxis)index); return bind; } SDL_GameControllerButtonBind GameController::getBindForButton(int index) { SDL_GameControllerButtonBind bind = SDL_GameControllerGetBindForButton(controller, (SDL_GameControllerButton)index); return bind; } void GameController::buttonClickEvent(int buttonindex) { SDL_GameControllerButtonBind bind = getBindForButton(static_cast(buttonindex)); if (bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE) { if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) { //emit rawAxisButtonClick(bind.value.axis, 0); //emit rawAxisActivated(bind.value.axis, JoyAxis::AXISMAX); } else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON) { //emit rawButtonClick(bind.value.button); } else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_HAT) { //emit rawDPadButtonClick(bind.value.hat.hat, bind.value.hat.hat_mask); } } } void GameController::buttonReleaseEvent(int buttonindex) { SDL_GameControllerButtonBind bind = getBindForButton(static_cast(buttonindex)); if (bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE) { if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) { //emit rawAxisButtonRelease(bind.value.axis, 0); } else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON) { //emit rawButtonRelease(bind.value.button); } else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_HAT) { //emit rawDPadButtonRelease(bind.value.hat.hat, bind.value.hat.hat_mask); } } } void GameController::axisActivatedEvent(int setindex, int axisindex, int value) { Q_UNUSED(setindex); SDL_GameControllerButtonBind bind = getBindForAxis(static_cast(axisindex)); if (bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE) { if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) { //emit rawAxisButtonClick(bind.value.axis, 0); //emit rawAxisActivated(bind.value.axis, value); } else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON) { //emit rawButtonClick(bind.value.button); } else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_HAT) { //emit rawDPadButtonClick(bind.value.hat.hat, bind.value.hat.hat_mask); } } } SDL_JoystickID GameController::getSDLJoystickID() { return joystickID; } /** * @brief Check if device is using the SDL Game Controller API * @return Status showing if device is using the Game Controller API */ bool GameController::isGameController() { return true; } /** * @brief Check if GUID passed matches the expected GUID for a device. * Needed for xinput GUID abstraction. * @param GUID string * @return if GUID is considered a match. */ bool GameController::isRelevantGUID(QString tempGUID) { bool result = false; if (InputDevice::isRelevantGUID(tempGUID))// || isEmptyGUID(tempGUID)) { result = true; } return result; } void GameController::rawButtonEvent(int index, bool pressed) { bool knownbutton = rawbuttons.contains(index); if (!knownbutton && pressed) { rawbuttons.insert(index, pressed); emit rawButtonClick(index); } else if (knownbutton && !pressed) { rawbuttons.remove(index); emit rawButtonRelease(index); } } void GameController::rawAxisEvent(int index, int value) { bool knownaxis = axisvalues.contains(index); if (!knownaxis && fabs(value) > rawAxisDeadZone) { axisvalues.insert(index, value); emit rawAxisActivated(index, value); } else if (knownaxis && fabs(value) < rawAxisDeadZone) { axisvalues.remove(index); emit rawAxisReleased(index, value); } emit rawAxisMoved(index, value); } void GameController::rawDPadEvent(int index, int value) { bool knowndpad = dpadvalues.contains(index); if (!knowndpad && value != 0) { dpadvalues.insert(index, value); emit rawDPadButtonClick(index, value); } else if (knowndpad && value == 0) { dpadvalues.remove(index); emit rawDPadButtonRelease(index, value); } } antimicro-2.23/src/gamecontroller/gamecontroller.h000066400000000000000000000051511300750276700224300ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef GAMECONTROLLER_H #define GAMECONTROLLER_H #include #include #include #include #include "gamecontrollerdpad.h" #include "gamecontrollerset.h" class GameController : public InputDevice { Q_OBJECT public: explicit GameController(SDL_GameController *controller, int deviceIndex, AntiMicroSettings *settings, QObject *parent = 0); virtual QString getName(); virtual QString getSDLName(); // GUID available on SDL 2. virtual QString getGUIDString(); virtual QString getRawGUIDString(); virtual QString getXmlName(); virtual bool isGameController(); virtual void closeSDLDevice(); virtual SDL_JoystickID getSDLJoystickID(); virtual int getNumberRawButtons(); virtual int getNumberRawAxes(); virtual int getNumberRawHats(); QString getBindStringForAxis(int index, bool trueIndex=true); QString getBindStringForButton(int index, bool trueIndex=true); SDL_GameControllerButtonBind getBindForAxis(int index); SDL_GameControllerButtonBind getBindForButton(int index); bool isRelevantGUID(QString tempGUID); void rawButtonEvent(int index, bool pressed); void rawAxisEvent(int index, int value); void rawDPadEvent(int index, int value); QHash rawbuttons; QHash axisvalues; QHash dpadvalues; static const QString xmlName; protected: void readJoystickConfig(QXmlStreamReader *xml); SDL_GameController *controller; signals: public slots: virtual void readConfig(QXmlStreamReader *xml); virtual void writeConfig(QXmlStreamWriter *xml); protected slots: virtual void axisActivatedEvent(int setindex, int axisindex, int value); virtual void buttonClickEvent(int buttonindex); virtual void buttonReleaseEvent(int buttonindex); }; #endif // GAMECONTROLLER_H antimicro-2.23/src/gamecontroller/gamecontrollerdpad.cpp000066400000000000000000000044611300750276700236170ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "gamecontrollerdpad.h" const QString GameControllerDPad::xmlName = "dpad"; GameControllerDPad::GameControllerDPad(JoyButton *upButton, JoyButton *downButton, JoyButton *leftButton, JoyButton *rightButton, int index, int originset, SetJoystick *parentSet, QObject *parent) : VDPad(upButton, downButton, leftButton, rightButton, index, originset, parentSet, parent) { } QString GameControllerDPad::getName(bool forceFullFormat, bool displayName) { QString label; if (!dpadName.isEmpty() && displayName) { if (forceFullFormat) { label.append(tr("DPad")).append(" "); } label.append(dpadName); } else if (!defaultDPadName.isEmpty()) { if (forceFullFormat) { label.append(tr("DPad")).append(" "); } label.append(defaultDPadName); } else { label.append(tr("DPad")).append(" "); label.append(QString::number(getRealJoyNumber())); } return label; } QString GameControllerDPad::getXmlName() { return this->xmlName; } void GameControllerDPad::readJoystickConfig(QXmlStreamReader *xml) { if (xml->isStartElement() && xml->name() == VDPad::xmlName) { xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != VDPad::xmlName)) { bool found = readMainConfig(xml); if (!found) { xml->skipCurrentElement(); } xml->readNextStartElement(); } } } antimicro-2.23/src/gamecontroller/gamecontrollerdpad.h000066400000000000000000000025661300750276700232700ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef GAMECONTROLLERDPAD_H #define GAMECONTROLLERDPAD_H #include #include "vdpad.h" class GameControllerDPad : public VDPad { Q_OBJECT public: explicit GameControllerDPad(JoyButton *upButton, JoyButton *downButton, JoyButton *leftButton, JoyButton *rightButton, int index, int originset, SetJoystick *parentSet, QObject *parent = 0); virtual QString getName(bool forceFullFormat, bool displayName); virtual QString getXmlName(); void readJoystickConfig(QXmlStreamReader *xml); static const QString xmlName; signals: public slots: }; #endif // GAMECONTROLLERDPAD_H antimicro-2.23/src/gamecontroller/gamecontrollerset.cpp000066400000000000000000000301041300750276700234730ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include "gamecontrollerset.h" #include GameControllerSet::GameControllerSet(InputDevice *device, int index, QObject *parent) : SetJoystick(device, index, false, parent) { reset(); } void GameControllerSet::reset() { SetJoystick::reset(); populateSticksDPad(); } void GameControllerSet::populateSticksDPad() { // Left Stick Assignment JoyAxis *axisX = getJoyAxis(SDL_CONTROLLER_AXIS_LEFTX); JoyAxis *axisY = getJoyAxis(SDL_CONTROLLER_AXIS_LEFTY); JoyControlStick *stick1 = new JoyControlStick(axisX, axisY, 0, index, this); //stick1->setStickDelay(10); stick1->setDefaultStickName("L Stick"); addControlStick(0, stick1); // Right Stick Assignment axisX = getJoyAxis(SDL_CONTROLLER_AXIS_RIGHTX); axisY = getJoyAxis(SDL_CONTROLLER_AXIS_RIGHTY); JoyControlStick *stick2 = new JoyControlStick(axisX, axisY, 1, index, this); stick2->setDefaultStickName("R Stick"); addControlStick(1, stick2); // Assign DPad buttons as a virtual DPad. Allows rougelike controls // to be assigned. JoyButton *buttonUp = getJoyButton(SDL_CONTROLLER_BUTTON_DPAD_UP); JoyButton *buttonDown = getJoyButton(SDL_CONTROLLER_BUTTON_DPAD_DOWN); JoyButton *buttonLeft = getJoyButton(SDL_CONTROLLER_BUTTON_DPAD_LEFT); JoyButton *buttonRight = getJoyButton(SDL_CONTROLLER_BUTTON_DPAD_RIGHT); GameControllerDPad *controllerDPad = new GameControllerDPad(buttonUp, buttonDown, buttonLeft, buttonRight, 0, index, this, this); controllerDPad->setDefaultDPadName("DPad"); //controllerDPad->setDPadDelay(10); addVDPad(0, controllerDPad); // Give default names to buttons getJoyButton(SDL_CONTROLLER_BUTTON_A)->setDefaultButtonName("A"); getJoyButton(SDL_CONTROLLER_BUTTON_B)->setDefaultButtonName("B"); getJoyButton(SDL_CONTROLLER_BUTTON_X)->setDefaultButtonName("X"); getJoyButton(SDL_CONTROLLER_BUTTON_Y)->setDefaultButtonName("Y"); getJoyButton(SDL_CONTROLLER_BUTTON_BACK)->setDefaultButtonName(tr("Back")); getJoyButton(SDL_CONTROLLER_BUTTON_GUIDE)->setDefaultButtonName(tr("Guide")); getJoyButton(SDL_CONTROLLER_BUTTON_START)->setDefaultButtonName(tr("Start")); getJoyButton(SDL_CONTROLLER_BUTTON_LEFTSTICK)->setDefaultButtonName(tr("LS Click")); getJoyButton(SDL_CONTROLLER_BUTTON_RIGHTSTICK)->setDefaultButtonName(tr("RS Click")); getJoyButton(SDL_CONTROLLER_BUTTON_LEFTSHOULDER)->setDefaultButtonName(tr("L Shoulder")); getJoyButton(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)->setDefaultButtonName(tr("R Shoulder")); // Give default names to triggers getJoyAxis(SDL_CONTROLLER_AXIS_TRIGGERLEFT)->setDefaultAxisName(tr("L Trigger")); getJoyAxis(SDL_CONTROLLER_AXIS_TRIGGERRIGHT)->setDefaultAxisName(tr("R Trigger")); } void GameControllerSet::readJoystickConfig(QXmlStreamReader *xml, QHash &buttons, QHash &axes, QList &hatButtons) { if (xml->isStartElement() && xml->name() == "set") { xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "set")) { bool dpadExists = false; bool vdpadExists = false; if (xml->name() == "button" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); JoyButton *button = 0; if (buttons.contains(index-1)) { SDL_GameControllerButton current = buttons.value(index-1); button = getJoyButton(current); } if (button) { button->readConfig(xml); } else { xml->skipCurrentElement(); } } else if (xml->name() == "axis" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); GameControllerTrigger *trigger = 0; if (axes.contains(index-1)) { SDL_GameControllerAxis current = axes.value(index-1); trigger = static_cast(getJoyAxis((int)current)); } if (trigger) { trigger->readJoystickConfig(xml); } else { xml->skipCurrentElement(); } } else if (xml->name() == "dpad" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); index = index - 1; bool found = false; QListIterator iter(hatButtons); SDL_GameControllerButtonBind current; while (iter.hasNext()) { current = iter.next(); if (current.value.hat.hat == index) { found = true; iter.toBack(); } } VDPad *dpad = 0; if (found) { dpad = getVDPad(0); } if (dpad && !vdpadExists) { dpadExists = true; dpad->readConfig(xml); } else { xml->skipCurrentElement(); } } else if (xml->name() == "stick" && xml->isStartElement()) { int stickIndex = xml->attributes().value("index").toString().toInt(); if (stickIndex > 0) { stickIndex -= 1; JoyControlStick *stick = getJoyStick(stickIndex); if (stick) { stick->readConfig(xml); } else { xml->skipCurrentElement(); } } else { xml->skipCurrentElement(); } } else if (xml->name() == "vdpad" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); index = index - 1; bool found = false; QListIterator iter(hatButtons); SDL_GameControllerButtonBind current; while (iter.hasNext()) { current = iter.next(); if (current.value.hat.hat == index) { found = true; iter.toBack(); } } VDPad *dpad = 0; if (found) { dpad = getVDPad(0); } if (dpad && !dpadExists) { vdpadExists = true; dpad->readConfig(xml); } else { xml->skipCurrentElement(); } } else if (xml->name() == "name" && xml->isStartElement()) { QString temptext = xml->readElementText(); if (!temptext.isEmpty()) { setName(temptext); } } else { // If none of the above, skip the element xml->skipCurrentElement(); } xml->readNextStartElement(); } } } void GameControllerSet::readConfig(QXmlStreamReader *xml) { if (xml->isStartElement() && xml->name() == "set") { xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "set")) { if (xml->name() == "button" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); JoyButton *button = getJoyButton(index-1); if (button) { button->readConfig(xml); } else { xml->skipCurrentElement(); } } else if (xml->name() == "trigger" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); GameControllerTrigger *axis = qobject_cast(getJoyAxis((index-1) + SDL_CONTROLLER_AXIS_TRIGGERLEFT)); if (axis) { axis->readConfig(xml); } else { xml->skipCurrentElement(); } } else if (xml->name() == "stick" && xml->isStartElement()) { int stickIndex = xml->attributes().value("index").toString().toInt(); if (stickIndex > 0) { stickIndex -= 1; JoyControlStick *stick = getJoyStick(stickIndex); if (stick) { stick->readConfig(xml); } else { xml->skipCurrentElement(); } } else { xml->skipCurrentElement(); } } else if (xml->name() == "dpad" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); GameControllerDPad *vdpad = qobject_cast(getVDPad(index-1)); if (vdpad) { vdpad->readConfig(xml); } else { xml->skipCurrentElement(); } } else if (xml->name() == "name" && xml->isStartElement()) { QString temptext = xml->readElementText(); if (!temptext.isEmpty()) { setName(temptext); } } else { // If none of the above, skip the element xml->skipCurrentElement(); } xml->readNextStartElement(); } } } void GameControllerSet::refreshAxes() { deleteAxes(); for (int i=0; i < device->getNumberRawAxes(); i++) { if (i == SDL_CONTROLLER_AXIS_TRIGGERLEFT || i == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) { GameControllerTrigger *trigger = new GameControllerTrigger(i, index, this, this); axes.insert(i, trigger); enableAxisConnections(trigger); } else { JoyAxis *axis = new JoyAxis(i, index, this, this); axes.insert(i, axis); enableAxisConnections(axis); } } } antimicro-2.23/src/gamecontroller/gamecontrollerset.h000066400000000000000000000032501300750276700231420ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef GAMECONTROLLERSET_H #define GAMECONTROLLERSET_H #include #include #include #include #include #include #include "gamecontrollerdpad.h" #include "gamecontrollertrigger.h" class GameControllerSet : public SetJoystick { Q_OBJECT public: explicit GameControllerSet(InputDevice *device, int index, QObject *parent = 0); virtual void refreshAxes(); virtual void readConfig(QXmlStreamReader *xml); virtual void readJoystickConfig(QXmlStreamReader *xml, QHash &buttons, QHash &axes, QList &hatButtons); protected: void populateSticksDPad(); signals: public slots: virtual void reset(); }; #endif // GAMECONTROLLERSET_H antimicro-2.23/src/gamecontroller/gamecontrollertrigger.cpp000066400000000000000000000132721300750276700243520ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include "gamecontrollertrigger.h" const int GameControllerTrigger::AXISDEADZONE = 2000; const int GameControllerTrigger::AXISMAXZONE = 32000; const GameControllerTrigger::ThrottleTypes GameControllerTrigger::DEFAULTTHROTTLE = GameControllerTrigger::PositiveHalfThrottle; const QString GameControllerTrigger::xmlName = "trigger"; GameControllerTrigger::GameControllerTrigger(int index, int originset, SetJoystick *parentSet, QObject *parent) : JoyAxis(index, originset, parentSet, parent) { naxisbutton = new GameControllerTriggerButton(this, 0, originset, parentSet, this); paxisbutton = new GameControllerTriggerButton(this, 1, originset, parentSet, this); reset(index); } QString GameControllerTrigger::getXmlName() { return this->xmlName; } QString GameControllerTrigger::getPartialName(bool forceFullFormat, bool displayNames) { QString label; if (!axisName.isEmpty() && displayNames) { label.append(axisName); if (forceFullFormat) { label.append(" ").append(tr("Trigger")); } } else if (!defaultAxisName.isEmpty()) { label.append(defaultAxisName); if (forceFullFormat) { label.append(" ").append(tr("Trigger")); } } else { label.append(tr("Trigger")).append(" "); label.append(QString::number(getRealJoyIndex() - SDL_CONTROLLER_AXIS_TRIGGERLEFT)); } return label; } void GameControllerTrigger::readJoystickConfig(QXmlStreamReader *xml) { if (xml->isStartElement() && xml->name() == JoyAxis::xmlName) { xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != JoyAxis::xmlName)) { bool found = readMainConfig(xml); if (!found && xml->name() == JoyAxisButton::xmlName && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); if (index == 1) { found = true; GameControllerTriggerButton *triggerButton = static_cast(naxisbutton); triggerButton->readJoystickConfig(xml); } else if (index == 2) { found = true; GameControllerTriggerButton *triggerButton = static_cast(paxisbutton); triggerButton->readJoystickConfig(xml); } } if (!found) { xml->skipCurrentElement(); } xml->readNextStartElement(); } } if (this->throttle != PositiveHalfThrottle) { this->setThrottle(PositiveHalfThrottle); setCurrentRawValue(currentThrottledDeadValue); currentThrottledValue = calculateThrottledValue(currentRawValue); } } void GameControllerTrigger::correctJoystickThrottle() { if (this->throttle != PositiveHalfThrottle) { this->setThrottle(PositiveHalfThrottle); setCurrentRawValue(currentThrottledDeadValue); currentThrottledValue = calculateThrottledValue(currentRawValue); } } void GameControllerTrigger::writeConfig(QXmlStreamWriter *xml) { bool currentlyDefault = isDefault(); xml->writeStartElement(getXmlName()); xml->writeAttribute("index", QString::number((index+1)-SDL_CONTROLLER_AXIS_TRIGGERLEFT)); if (!currentlyDefault) { if (deadZone != AXISDEADZONE) { xml->writeTextElement("deadZone", QString::number(deadZone)); } if (maxZoneValue != AXISMAXZONE) { xml->writeTextElement("maxZone", QString::number(maxZoneValue)); } } //if (throttle != DEFAULTTHROTTLE) //{ xml->writeStartElement("throttle"); if (throttle == JoyAxis::NegativeHalfThrottle) { xml->writeCharacters("negativehalf"); } else if (throttle == JoyAxis::NegativeThrottle) { xml->writeCharacters("negative"); } else if (throttle == JoyAxis::NormalThrottle) { xml->writeCharacters("normal"); } else if (throttle == JoyAxis::PositiveThrottle) { xml->writeCharacters("positive"); } else if (throttle == JoyAxis::PositiveHalfThrottle) { xml->writeCharacters("positivehalf"); } xml->writeEndElement(); //} if (!currentlyDefault) { naxisbutton->writeConfig(xml); paxisbutton->writeConfig(xml); } xml->writeEndElement(); } int GameControllerTrigger::getDefaultDeadZone() { return this->AXISDEADZONE; } int GameControllerTrigger::getDefaultMaxZone() { return this->AXISMAXZONE; } JoyAxis::ThrottleTypes GameControllerTrigger::getDefaultThrottle() { return (ThrottleTypes)this->DEFAULTTHROTTLE; } antimicro-2.23/src/gamecontroller/gamecontrollertrigger.h000066400000000000000000000034101300750276700240100ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef GAMECONTROLLERTRIGGER_H #define GAMECONTROLLERTRIGGER_H #include #include #include #include #include #include "gamecontrollertriggerbutton.h" #include class GameControllerTrigger : public JoyAxis { Q_OBJECT public: explicit GameControllerTrigger(int index, int originset, SetJoystick *parentSet, QObject *parent = 0); virtual QString getXmlName(); virtual QString getPartialName(bool forceFullFormat, bool displayNames); virtual int getDefaultDeadZone(); virtual int getDefaultMaxZone(); virtual ThrottleTypes getDefaultThrottle(); void readJoystickConfig(QXmlStreamReader *xml); virtual void writeConfig(QXmlStreamWriter *xml); static const int AXISDEADZONE; static const int AXISMAXZONE; static const ThrottleTypes DEFAULTTHROTTLE; static const QString xmlName; protected: void correctJoystickThrottle(); signals: public slots: }; #endif // GAMECONTROLLERTRIGGER_H antimicro-2.23/src/gamecontroller/gamecontrollertriggerbutton.cpp000066400000000000000000000035721300750276700256100ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "gamecontrollertriggerbutton.h" const QString GameControllerTriggerButton::xmlName = "triggerbutton"; GameControllerTriggerButton::GameControllerTriggerButton(JoyAxis *axis, int index, int originset, SetJoystick *parentSet, QObject *parent) : JoyAxisButton(axis, index, originset, parentSet, parent) { } QString GameControllerTriggerButton::getXmlName() { return this->xmlName; } void GameControllerTriggerButton::readJoystickConfig(QXmlStreamReader *xml) { if (xml->isStartElement() && xml->name() == JoyAxisButton::xmlName) { disconnect(this, SIGNAL(slotsChanged()), parentSet->getInputDevice(), SLOT(profileEdited())); xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != JoyAxisButton::xmlName)) { bool found = readButtonConfig(xml); if (!found) { xml->skipCurrentElement(); } xml->readNextStartElement(); } connect(this, SIGNAL(slotsChanged()), parentSet->getInputDevice(), SLOT(profileEdited())); } } antimicro-2.23/src/gamecontroller/gamecontrollertriggerbutton.h000066400000000000000000000024271300750276700252530ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef GAMECONTROLLERBUTTON_H #define GAMECONTROLLERBUTTON_H #include #include #include class GameControllerTriggerButton : public JoyAxisButton { Q_OBJECT public: explicit GameControllerTriggerButton(JoyAxis *axis, int index, int originset, SetJoystick *parentSet, QObject *parent = 0); virtual QString getXmlName(); void readJoystickConfig(QXmlStreamReader *xml); static const QString xmlName; signals: public slots: }; #endif // GAMECONTROLLERBUTTON_H antimicro-2.23/src/gamecontrollerexample.cpp000066400000000000000000000077631300750276700213350ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "gamecontrollerexample.h" struct ButtonImagePlacement { int x; int y; GameControllerExample::ButtonType buttontype; }; static ButtonImagePlacement buttonLocations[] = { {225, 98, GameControllerExample::Button}, // SDL_CONTROLLER_BUTTON_A {252, 77, GameControllerExample::Button}, // SDL_CONTROLLER_BUTTON_B {200, 77, GameControllerExample::Button}, // SDL_CONTROLLER_BUTTON_X {227, 59, GameControllerExample::Button}, // SDL_CONTROLLER_BUTTON_Y {102, 77, GameControllerExample::Button}, // SDL_CONTROLLER_BUTTON_BACK {169, 77, GameControllerExample::Button}, // SDL_CONTROLLER_BUTTON_START {137, 77, GameControllerExample::Button}, // SDL_CONTROLLER_BUTTON_GUIDE {45, 23, GameControllerExample::Button}, // SDL_CONTROLLER_BUTTON_LEFTSHOULDER {232, 21, GameControllerExample::Button}, // SDL_CONTROLLER_BUTTON_RIGHTSHOULDER {44, 90, GameControllerExample::Button}, // SDL_CONTROLLER_BUTTON_LEFTSTICK {179, 135, GameControllerExample::Button}, // SDL_CONTROLLER_BUTTON_RIGHTSTICK {44, 90, GameControllerExample::AxisX}, // SDL_CONTROLLER_AXIS_LEFTX {44, 90, GameControllerExample::AxisY}, // SDL_CONTROLLER_AXIS_LEFTY {179, 135, GameControllerExample::AxisX}, // SDL_CONTROLLER_AXIS_RIGHTX {179, 135, GameControllerExample::AxisY}, // SDL_CONTROLLER_AXIS_RIGHTY {53, 0, GameControllerExample::Button}, // SDL_CONTROLLER_AXIS_TRIGGERLEFT {220, 0, GameControllerExample::Button}, // SDL_CONTROLLER_AXIS_TRIGGERRIGHT {90, 110, GameControllerExample::Button}, // SDL_CONTROLLER_BUTTON_DPAD_UP {68, 127, GameControllerExample::Button}, // SDL_CONTROLLER_BUTTON_DPAD_DOWN {90, 146, GameControllerExample::Button}, // SDL_CONTROLLER_BUTTON_DPAD_LEFT {109, 127, GameControllerExample::Button}, // SDL_CONTROLLER_BUTTON_DPAD_RIGHT }; GameControllerExample::GameControllerExample(QWidget *parent) : QWidget(parent) { controllerimage = QImage(":/images/controllermap.png"); buttonimage = QImage(":/images/button.png"); axisimage = QImage(":/images/axis.png"); QTransform myTransform; myTransform.rotate(90); rotatedaxisimage = axisimage.transformed(myTransform); currentIndex = 0; connect(this, SIGNAL(indexUpdated(int)), this, SLOT(update())); } void GameControllerExample::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter paint(this); paint.drawImage(controllerimage.rect(), controllerimage); ButtonImagePlacement current = buttonLocations[currentIndex]; paint.setOpacity(0.85); if (current.buttontype == Button) { paint.drawImage(QRect(current.x, current.y, buttonimage.width(), buttonimage.height()), buttonimage); } else if (current.buttontype == AxisX) { paint.drawImage(QRect(current.x, current.y, axisimage.width(), axisimage.height()), axisimage); } else if (current.buttontype == AxisY) { paint.drawImage(QRect(current.x, current.y, rotatedaxisimage.width(), rotatedaxisimage.height()), rotatedaxisimage); } paint.setOpacity(1.0); } void GameControllerExample::setActiveButton(int button) { if (button >= 0 && button <= MAXBUTTONINDEX) { currentIndex = button; emit indexUpdated(button); } } antimicro-2.23/src/gamecontrollerexample.h000066400000000000000000000026171300750276700207730ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef GAMECONTROLLEREXAMPLE_H #define GAMECONTROLLEREXAMPLE_H #include #include class GameControllerExample : public QWidget { Q_OBJECT public: explicit GameControllerExample(QWidget *parent = 0); enum ButtonType { Button, AxisX, AxisY, }; static const unsigned int MAXBUTTONINDEX = 20; protected: virtual void paintEvent(QPaintEvent *event); QImage controllerimage; QImage buttonimage; QImage axisimage; QImage rotatedaxisimage; int currentIndex; signals: void indexUpdated(int index); public slots: void setActiveButton(int button); }; #endif // GAMECONTROLLEREXAMPLE_H antimicro-2.23/src/gamecontrollermappingdialog.cpp000066400000000000000000000545101300750276700225050ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include #include #include #include #include #include #include #include "gamecontrollermappingdialog.h" #include "ui_gamecontrollermappingdialog.h" static QHash initAliases() { QHash temp; temp.insert(0, "a"); temp.insert(1, "b"); temp.insert(2, "x"); temp.insert(3, "y"); temp.insert(4, "back"); temp.insert(5, "start"); temp.insert(6, "guide"); temp.insert(7, "leftshoulder"); temp.insert(8, "rightshoulder"); temp.insert(9, "leftstick"); temp.insert(10, "rightstick"); temp.insert(11, "leftx"); temp.insert(12, "lefty"); temp.insert(13, "rightx"); temp.insert(14, "righty"); temp.insert(15, "lefttrigger"); temp.insert(16, "righttrigger"); temp.insert(17, "dpup"); temp.insert(18, "dpleft"); temp.insert(19, "dpdown"); temp.insert(20, "dpright"); return temp; } static QHash initButtonPlacement() { QHash temp; temp.insert(SDL_CONTROLLER_BUTTON_A, 0); temp.insert(SDL_CONTROLLER_BUTTON_B, 1); temp.insert(SDL_CONTROLLER_BUTTON_X, 2); temp.insert(SDL_CONTROLLER_BUTTON_Y, 3); temp.insert(SDL_CONTROLLER_BUTTON_BACK, 4); temp.insert(SDL_CONTROLLER_BUTTON_START, 5); temp.insert(SDL_CONTROLLER_BUTTON_GUIDE, 6); temp.insert(SDL_CONTROLLER_BUTTON_LEFTSHOULDER, 7); temp.insert(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, 8); temp.insert(SDL_CONTROLLER_BUTTON_LEFTSTICK, 9); temp.insert(SDL_CONTROLLER_BUTTON_RIGHTSTICK, 10); temp.insert(SDL_CONTROLLER_BUTTON_DPAD_UP, 17); temp.insert(SDL_CONTROLLER_BUTTON_DPAD_LEFT, 18); temp.insert(SDL_CONTROLLER_BUTTON_DPAD_DOWN, 19); temp.insert(SDL_CONTROLLER_BUTTON_DPAD_RIGHT, 20); return temp; } static QHash initAxisPlacement() { QHash temp; temp.insert(SDL_CONTROLLER_AXIS_LEFTX, 11); temp.insert(SDL_CONTROLLER_AXIS_LEFTY, 12); temp.insert(SDL_CONTROLLER_AXIS_RIGHTX, 13); temp.insert(SDL_CONTROLLER_AXIS_RIGHTY, 14); temp.insert(SDL_CONTROLLER_AXIS_TRIGGERLEFT, 15); temp.insert(SDL_CONTROLLER_AXIS_TRIGGERRIGHT, 16); return temp; } QHash GameControllerMappingDialog::tempaliases = initAliases(); QHash GameControllerMappingDialog::buttonPlacement = initButtonPlacement(); QHash GameControllerMappingDialog::axisPlacement = initAxisPlacement(); GameControllerMappingDialog::GameControllerMappingDialog(InputDevice *device, AntiMicroSettings *settings, QWidget *parent) : QDialog(parent), ui(new Ui::GameControllerMappingDialog), helper(device) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); buttonGrabs = 0; usingGameController = false; this->device = device; this->settings = settings; helper.moveToThread(device->thread()); PadderCommon::lockInputDevices(); QMetaObject::invokeMethod(device, "haltServices"); QMetaObject::invokeMethod(&helper, "setupDeadZones", Qt::BlockingQueuedConnection); GameController *controller = qobject_cast(device); if (controller) { usingGameController = true; populateGameControllerBindings(controller); ui->mappingStringPlainTextEdit->document()->setPlainText(generateSDLMappingString()); } QString tempWindowTitle = QString(tr("Game Controller Mapping (%1) (#%2)")).arg(device->getSDLName()) .arg(device->getRealJoyNumber()); setWindowTitle(tempWindowTitle); enableDeviceConnections(); ui->buttonMappingTableWidget->setCurrentCell(0, 0); ui->axisDeadZoneComboBox->clear(); populateAxisDeadZoneComboBox(); currentDeadZoneValue = 20000; int index = ui->axisDeadZoneComboBox->findData(currentDeadZoneValue); if (index != -1) { ui->axisDeadZoneComboBox->setCurrentIndex(index); } connect(device, SIGNAL(destroyed()), this, SLOT(obliterate())); connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(saveChanges())); connect(ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(discardMapping(QAbstractButton*))); connect(ui->buttonMappingTableWidget, SIGNAL(itemSelectionChanged()), this, SLOT(changeButtonDisplay())); connect(ui->axisDeadZoneComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeAxisDeadZone(int))); connect(this, SIGNAL(finished(int)), this, SLOT(enableButtonEvents(int))); PadderCommon::unlockInputDevices(); } GameControllerMappingDialog::~GameControllerMappingDialog() { delete ui; } void GameControllerMappingDialog::buttonAssign(int buttonindex) { // Only perform assignment if no other control is currently active. if (ui->buttonMappingTableWidget->currentRow() > -1) { QTableWidgetItem* item = ui->buttonMappingTableWidget->currentItem(); int column = ui->buttonMappingTableWidget->currentColumn(); int row = ui->buttonMappingTableWidget->currentRow(); if (!item) { item = new QTableWidgetItem(QString("Button %1").arg(buttonindex+1)); ui->buttonMappingTableWidget->setItem(row, column, item); } QList templist; templist.append(QVariant(0)); templist.append(QVariant(buttonindex)); QAbstractItemModel *model = ui->buttonMappingTableWidget->model(); QModelIndexList matchlist = model->match(model->index(0,0), Qt::UserRole, templist, 1, Qt::MatchExactly); foreach (const QModelIndex &index, matchlist) { QTableWidgetItem *existingItem = ui->buttonMappingTableWidget->item(index.row(), index.column()); if (existingItem) { existingItem->setText(""); existingItem->setData(Qt::UserRole, QVariant()); } } QList tempvalue; tempvalue.append(QVariant(0)); tempvalue.append(QVariant(buttonindex)); item->setData(Qt::UserRole, tempvalue); item->setText(QString("Button %1").arg(buttonindex+1)); if (row < ui->buttonMappingTableWidget->rowCount()-1) { ui->buttonMappingTableWidget->setCurrentCell(row+1, column); } ui->mappingStringPlainTextEdit->document()->setPlainText(generateSDLMappingString()); } } void GameControllerMappingDialog::axisAssign(int axis, int value) { bool skip = false; bool change = true; if (usingGameController) { if (eventTriggerAxes.contains(axis) && value < -currentDeadZoneValue) { skip = true; eventTriggerAxes.removeAll(axis); } } if (!skip && ui->buttonMappingTableWidget->currentRow() > -1) { QTableWidgetItem* item = ui->buttonMappingTableWidget->currentItem(); int column = ui->buttonMappingTableWidget->currentColumn(); int row = ui->buttonMappingTableWidget->currentRow(); if (row < 17) { if (usingGameController) { bool considerTrigger = (row == 15 || row == 16); if (considerTrigger && value > currentDeadZoneValue && !eventTriggerAxes.contains(axis)) { eventTriggerAxes.append(axis); } else if (considerTrigger && value < currentDeadZoneValue) { skip = true; } } if (!skip) { if (!item) { item = new QTableWidgetItem(QString("Axis %1").arg(axis+1)); ui->buttonMappingTableWidget->setItem(row, column, item); } QList templist; templist.append(QVariant(axis+1)); templist.append(QVariant(0)); QAbstractItemModel *model = ui->buttonMappingTableWidget->model(); QModelIndexList matchlist = model->match(model->index(0,0), Qt::UserRole, templist, 1, Qt::MatchExactly); foreach (const QModelIndex &index, matchlist) { QTableWidgetItem *existingItem = ui->buttonMappingTableWidget->item(index.row(), index.column()); if (existingItem) { existingItem->setText(""); existingItem->setData(Qt::UserRole, QVariant()); } } QList tempvalue; tempvalue.append(QVariant(axis+1)); tempvalue.append(QVariant(0)); item->setData(Qt::UserRole, tempvalue); item->setText(QString("Axis %1").arg(axis+1)); if (row < ui->buttonMappingTableWidget->rowCount()-1) { ui->buttonMappingTableWidget->setCurrentCell(row+1, column); } ui->mappingStringPlainTextEdit->document()->setPlainText(generateSDLMappingString()); } } else { change = false; skip = true; } } } void GameControllerMappingDialog::dpadAssign(int dpad, int buttonindex) { if (ui->buttonMappingTableWidget->currentRow() > -1) { if (buttonindex == 1 || buttonindex == 2 || buttonindex == 4 || buttonindex == 8) { QTableWidgetItem* item = ui->buttonMappingTableWidget->currentItem(); int column = ui->buttonMappingTableWidget->currentColumn(); int row = ui->buttonMappingTableWidget->currentRow(); if (row <= 10 || row >= 17) { if (!item) { item = new QTableWidgetItem(QString("Hat %1.%2").arg(dpad+1).arg(buttonindex)); ui->buttonMappingTableWidget->setItem(row, column, item); } QList templist; templist.append(QVariant(-dpad-1)); templist.append(QVariant(buttonindex)); QAbstractItemModel *model = ui->buttonMappingTableWidget->model(); QModelIndexList matchlist = model->match(model->index(0,0), Qt::UserRole, templist, 1, Qt::MatchExactly); foreach (const QModelIndex &index, matchlist) { QTableWidgetItem *existingItem = ui->buttonMappingTableWidget->item(index.row(), index.column()); if (existingItem) { existingItem->setText(""); existingItem->setData(Qt::UserRole, QVariant()); } } QList tempvalue; tempvalue.append(QVariant(-dpad-1)); tempvalue.append(QVariant(buttonindex)); item->setData(Qt::UserRole, tempvalue); item->setText(QString("Hat %1.%2").arg(dpad+1).arg(buttonindex)); } if (row < ui->buttonMappingTableWidget->rowCount()-1) { ui->buttonMappingTableWidget->setCurrentCell(row+1, column); } ui->mappingStringPlainTextEdit->document()->setPlainText(generateSDLMappingString()); } } } void GameControllerMappingDialog::saveChanges() { QString mappingString = generateSDLMappingString(); settings->getLock()->lock(); settings->setValue(QString("Mappings/").append(device->getGUIDString()), mappingString); settings->setValue(QString("Mappings/%1%2").arg(device->getGUIDString()).arg("Disable"), "0"); settings->sync(); bool displayMapping = settings->runtimeValue("DisplaySDLMapping", false).toBool(); settings->getLock()->unlock(); if (displayMapping) { QTextStream out(stdout); out << generateSDLMappingString(); } emit mappingUpdate(mappingString, device); } void GameControllerMappingDialog::populateGameControllerBindings(GameController *controller) { if (controller) { for (int i = 0; i < controller->getNumberButtons(); i++) { int associatedRow = buttonPlacement.value((SDL_GameControllerButton)i); SDL_GameControllerButtonBind bind = controller->getBindForButton(i); QString temptext = bindingString(bind); if (!temptext.isEmpty()) { QList tempvariant = bindingValues(bind); QTableWidgetItem* item = new QTableWidgetItem(); ui->buttonMappingTableWidget->setItem(associatedRow, 0, item); item->setText(temptext); item->setData(Qt::UserRole, tempvariant); } } for (int i = 0; i < controller->getNumberAxes(); i++) { int associatedRow = axisPlacement.value((SDL_GameControllerAxis)i); SDL_GameControllerButtonBind bind = controller->getBindForAxis(i); QString temptext = bindingString(bind); if (!temptext.isEmpty()) { QList tempvariant = bindingValues(bind); QTableWidgetItem* item = new QTableWidgetItem(); ui->buttonMappingTableWidget->setItem(associatedRow, 0, item); item->setText(temptext); item->setData(Qt::UserRole, tempvariant); } } } } QString GameControllerMappingDialog::bindingString(SDL_GameControllerButtonBind bind) { QString temp; if (bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE) { if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON) { temp.append(QString("Button %1").arg(bind.value.button+1)); } else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) { temp.append(QString("Axis %1").arg(bind.value.axis+1)); } else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_HAT) { temp.append(QString("Hat %1.%2").arg(bind.value.hat.hat+1) .arg(bind.value.hat.hat_mask)); } } return temp; } QList GameControllerMappingDialog::bindingValues(SDL_GameControllerButtonBind bind) { QList temp; if (bind.bindType != SDL_CONTROLLER_BINDTYPE_NONE) { if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON) { temp.append(QVariant(0)); temp.append(QVariant(bind.value.button)); } else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS) { temp.append(QVariant(bind.value.axis+1)); temp.append(QVariant(0)); } else if (bind.bindType == SDL_CONTROLLER_BINDTYPE_HAT) { temp.append(QVariant(-bind.value.hat.hat-1)); temp.append(QVariant(bind.value.hat.hat_mask)); } } return temp; } void GameControllerMappingDialog::discardMapping(QAbstractButton *button) { disableDeviceConnections(); QDialogButtonBox::ButtonRole currentRole = ui->buttonBox->buttonRole(button); if (currentRole == QDialogButtonBox::DestructiveRole) { QMessageBox msgBox; msgBox.setWindowTitle(tr("Discard Controller Mapping?")); msgBox.setText(tr("Discard mapping for this controller?\n\nIf discarded, the controller will be reverted to a joystick once you refresh all joysticks.")); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel); int status = msgBox.exec(); if (status == QMessageBox::Yes) { removeControllerMapping(); close(); } else { enableDeviceConnections(); } } } void GameControllerMappingDialog::removeControllerMapping() { settings->getLock()->lock(); settings->beginGroup("Mappings"); settings->remove(device->getGUIDString()); settings->remove(QString("%1Disable").arg(device->getGUIDString())); settings->endGroup(); settings->sync(); settings->getLock()->unlock(); } void GameControllerMappingDialog::enableDeviceConnections() { connect(device, SIGNAL(rawButtonClick(int)), this, SLOT(buttonAssign(int))); connect(device, SIGNAL(rawButtonRelease(int)), this, SLOT(buttonRelease(int))); connect(device, SIGNAL(rawAxisMoved(int,int)), this, SLOT(updateLastAxisLineEditRaw(int,int))); connect(device, SIGNAL(rawAxisActivated(int,int)), this, SLOT(axisAssign(int,int))); connect(device, SIGNAL(rawAxisReleased(int,int)), this, SLOT(axisRelease(int,int))); connect(device, SIGNAL(rawDPadButtonClick(int,int)), this, SLOT(dpadAssign(int,int))); connect(device, SIGNAL(rawDPadButtonRelease(int,int)), this, SLOT(dpadRelease(int,int))); } void GameControllerMappingDialog::disableDeviceConnections() { disconnect(device, SIGNAL(rawButtonClick(int)), this, 0); disconnect(device, SIGNAL(rawButtonRelease(int)), this, 0); disconnect(device, SIGNAL(rawAxisMoved(int,int)), this, 0); disconnect(device, SIGNAL(rawAxisActivated(int,int)), this, 0); disconnect(device, SIGNAL(rawAxisReleased(int,int)), this, 0); disconnect(device, SIGNAL(rawDPadButtonClick(int,int)), this, 0); disconnect(device, SIGNAL(rawDPadButtonRelease(int,int)), this, 0); } void GameControllerMappingDialog::enableButtonEvents(int code) { Q_UNUSED(code); QMetaObject::invokeMethod(&helper, "restoreDeviceDeadZones", Qt::BlockingQueuedConnection); } QString GameControllerMappingDialog::generateSDLMappingString() { QStringList templist; templist.append(device->getGUIDString()); templist.append(device->getSDLName()); templist.append(QString("platform:").append(device->getSDLPlatform())); for (int i=0; i < ui->buttonMappingTableWidget->rowCount(); i++) { QTableWidgetItem *item = ui->buttonMappingTableWidget->item(i, 0); if (item) { QString mapNative; QList tempassociation = item->data(Qt::UserRole).toList(); if (tempassociation.size() == 2) { int bindingType = tempassociation.value(0).toInt(); if (bindingType == 0) { mapNative.append("b"); mapNative.append(QString::number(tempassociation.value(1).toInt())); } else if (bindingType > 0) { mapNative.append("a"); mapNative.append(QString::number(tempassociation.value(0).toInt()-1)); } else if (bindingType < 0) { mapNative.append("h"); mapNative.append(QString::number(tempassociation.value(0).toInt()+1)); mapNative.append(".").append(QString::number(tempassociation.value(1).toInt())); } } if (!mapNative.isEmpty()) { QString sdlButtonName = tempaliases.value(i); QString temp = QString("%1:%2").arg(sdlButtonName).arg(mapNative); templist.append(temp); } } } return templist.join(",").append(","); } void GameControllerMappingDialog::obliterate() { this->done(QDialogButtonBox::DestructiveRole); } void GameControllerMappingDialog::changeButtonDisplay() { ui->gameControllerDisplayWidget->setActiveButton(ui->buttonMappingTableWidget->currentRow()); } /** * @brief TODO: Possibly remove. This was used for decrementing a reference * count. * @param axis * @param value */ void GameControllerMappingDialog::axisRelease(int axis, int value) { Q_UNUSED(axis); Q_UNUSED(value); } /** * @brief TODO: Possibly remove. This was used for decrementing a reference * count. * @param buttonindex */ void GameControllerMappingDialog::buttonRelease(int buttonindex) { Q_UNUSED(buttonindex); } /** * @brief TODO: Possibly remove. This was used for decrementing a reference * count. * @param dpad * @param buttonindex */ void GameControllerMappingDialog::dpadRelease(int dpad, int buttonindex) { Q_UNUSED(dpad); Q_UNUSED(buttonindex); } void GameControllerMappingDialog::populateAxisDeadZoneComboBox() { for (int i=0; i < 28; i++) { unsigned int temp = (i * 1000) + 5000; ui->axisDeadZoneComboBox->addItem(QString::number(temp), temp); } } void GameControllerMappingDialog::changeAxisDeadZone(int index) { unsigned int value = ui->axisDeadZoneComboBox->itemData(index).toInt(); if (value >= 5000 && value <= 32000) { QMetaObject::invokeMethod(&helper, "raiseDeadZones", Qt::BlockingQueuedConnection, Q_ARG(int, value)); currentDeadZoneValue = value; } } void GameControllerMappingDialog::updateLastAxisLineEdit(int value) { if (abs(value) >= 5000) { JoyAxis *tempAxis = static_cast(sender()); QString temp; if (device->isGameController()) { GameController *controller = static_cast(device); temp = QString("%1: %2").arg(controller->getBindStringForAxis(tempAxis->getIndex(), false)) .arg(value); } else { temp = QString("Axis %1: %2").arg(tempAxis->getRealJoyIndex()) .arg(value); } ui->lastAxisEventLineEdit->setText(temp); } } void GameControllerMappingDialog::updateLastAxisLineEditRaw(int index, int value) { if (abs(value) >= 5000) { QString temp; temp = QString("Axis %1: %2").arg(index) .arg(value); ui->lastAxisEventLineEdit->setText(temp); } } antimicro-2.23/src/gamecontrollermappingdialog.h000066400000000000000000000056011300750276700221470ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef GAMECONTROLLERMAPPINGDIALOG_H #define GAMECONTROLLERMAPPINGDIALOG_H #include #include #include #include #include "uihelpers/gamecontrollermappingdialoghelper.h" #include "inputdevice.h" #include "gamecontroller/gamecontroller.h" #include "antimicrosettings.h" namespace Ui { class GameControllerMappingDialog; } class GameControllerMappingDialog : public QDialog { Q_OBJECT public: explicit GameControllerMappingDialog(InputDevice *device, AntiMicroSettings *settings, QWidget *parent = 0); ~GameControllerMappingDialog(); static QHash tempaliases; static QHash buttonPlacement; static QHash axisPlacement; protected: void populateGameControllerBindings(GameController *controller); void removeControllerMapping(); void enableDeviceConnections(); void disableDeviceConnections(); QString generateSDLMappingString(); void populateAxisDeadZoneComboBox(); QString bindingString(SDL_GameControllerButtonBind bind); QList bindingValues(SDL_GameControllerButtonBind bind); InputDevice *device; AntiMicroSettings *settings; unsigned int buttonGrabs; QList eventTriggerAxes; QList originalAxesDeadZones; GameControllerMappingDialogHelper helper; int currentDeadZoneValue; bool usingGameController; private: Ui::GameControllerMappingDialog *ui; signals: void mappingUpdate(QString mapping, InputDevice *device); private slots: void buttonAssign(int buttonindex); void axisAssign(int axis, int value); void dpadAssign(int dpad, int buttonindex); void buttonRelease(int buttonindex); void axisRelease(int axis, int value); void dpadRelease(int dpad, int buttonindex); void saveChanges(); void discardMapping(QAbstractButton *button); void enableButtonEvents(int code); void obliterate(); void changeButtonDisplay(); void changeAxisDeadZone(int index); void updateLastAxisLineEdit(int value); void updateLastAxisLineEditRaw(int index, int value); }; #endif // GAMECONTROLLERMAPPINGDIALOG_H antimicro-2.23/src/gamecontrollermappingdialog.ui000066400000000000000000000314621300750276700223410ustar00rootroot00000000000000 GameControllerMappingDialog 0 0 918 600 600 400 Game Controller Mapping 40 20 <html><head/><body><p>antimicro makes use of the <a href="https://wiki.libsdl.org/CategoryGameController"><span style=" text-decoration: underline; color:#0057ae;">Game Controller API</span></a> provided by SDL 2 in order to abstract various gamepads to fit a unified standard. In order to make a button assignment, please highlight the mapping cell for the appropriate button row below. You can then press a button or move an axis on your gamepad and the cell will update with the physical button or axis that will be used.</p><p>antimicro will use the mapping that you specify to save a mapping string that will be loaded into SDL.</p></body></html> true true QFrame::Sunken 1 true QAbstractItemView::NoEditTriggers false false false QAbstractItemView::SingleSelection QAbstractItemView::SelectItems Qt::ElideRight true Qt::SolidLine false true true 21 1 true false 100 true true true false 30 true 20 false false A B X Y Back Start Guide Left Shoulder Right Shoulder Left Stick Click Right Stick Click Left Stick X Left Stick Y Right Stick X Right Stick Y Left Trigger Right Trigger DPad Up DPad Left DPad Down DPad Right Mapping 75 true SDL 2 Game Controller Mapping String 0 0 0 0 16777215 100 true 20 300 200 Last Axis Event: true Current Axis Detection Dead Zone: 5000 10000 15000 20000 25000 30000 32000 Qt::Vertical 20 40 Qt::Horizontal Qt::Horizontal QDialogButtonBox::Close|QDialogButtonBox::Discard|QDialogButtonBox::Save GameControllerExample QWidget
gamecontrollerexample.h
1
buttonBox accepted() GameControllerMappingDialog accept() 248 254 157 274 buttonBox rejected() GameControllerMappingDialog reject() 316 260 286 274
antimicro-2.23/src/icons/000077500000000000000000000000001300750276700153365ustar00rootroot00000000000000antimicro-2.23/src/icons/16x16/000077500000000000000000000000001300750276700161235ustar00rootroot00000000000000antimicro-2.23/src/icons/16x16/actions/000077500000000000000000000000001300750276700175635ustar00rootroot00000000000000antimicro-2.23/src/icons/16x16/actions/application-exit.png000066400000000000000000000014151300750276700235440ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<ŠIDAT8m’ËoLQÇ?çq§÷ž{CÆ«ÂBtC%hˆÖFb£IÓXHÑ’ðWP•Øx,ÄÆÚ+¡±éJ”¶éF‰Šx„J¦í0}Ì9sïµ3ÚòKÎæ$ßïù|Ïï+w<ëœëæ?#¥Äó<|?@k @ÇXg.\»r£[;çºÛÛö366Æôô4333ÌÍÍa­EJÉ¥KQJ#¥ MSŠÅ"Ý='O=ÀƒïûÄqL’$(¥ÐZ#¥Bk¥T… Iˆ¢ˆ 0H€(Šˆ¢ˆ0 Ãc A`ŒaâÙSúwìàaS?GG‘R „@© ‘¬fÍd25QA@8;Ëó®.vîNÙ¾Õ2|ôÈâo5)%J)”Rxž‡VŠÕ}}lÙ•E•’boÉ’¿Jøƒ¤j&RJ–ŽŒ°Þæ¨oÜ@¾÷+/¿MR,¿ã®—`ó²,zïnÓóWV=^¡ÀÊGh<¾žÉþïÈzÅžã›°O¾.0pÿÓåÕ×¥R”L åp¯á­ª£p>?/¸ nqReõr~–/§°¯•‘W0>«:ÖñquCÎ1äƒ%Ë“¼Ù왚bAŒ¤¹™üÆŒ/[Aü%KKçf‚†ŽÍÎpèGžÏ86>>\3¨R(¥*+5ÙÙÉ‹\ŽB¼‚_SKÙ,Ζ(Ù9â$Hh­ñ}c ¹\³v -ׯÒÿ~ŒÇ£E¶ž>EñOÝ­µ‰BÔð}¿Ž7oÞ˜:ÚÚ[ Ã!{ïÝ®Q~Na¥T*Uz „ “ÉÏO`Ë–¦Ûð„VâØØØYú iD-¬ÔÂÀb²Y]°PILœp†YB>8Üê~sf`Of Íx’™ d/oH±‰‰ a4‚aˆBŒ(ƒb‚q]Œ"0Mƒ—ˆx²ˆT%zñb1§’J¦Ô XÒXÀËZ¤VÀµ+‘4r¢¦"S¡½;·QÑ ´ËAÀ2m\¿_À²€þÆ $©V £å´Ð[îÁ¿ ½à îŒÆ]oÑÿœ|€tõñŽ}l_n"#B ÂÑýáÒÁÍî£Ò`v“ç·W„_cÌÏ |'6^¢!:]'Sÿ™~~“<FñÚ™—í\­æ+çmRñNžºÙ$–eøë§îCgv*þr”ü2Œ‡K Ü IEND®B`‚antimicro-2.23/src/icons/16x16/actions/dialog-cancel.png000066400000000000000000000015201300750276700227510ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs»»:ìãâtEXtSoftwarewww.inkscape.org›î<ÍIDATxÚ¥“MHqÆŸÿ|:³3»~­ëÅji¥A † u ëDö v­‹‡Bº¥'!(I:D¥I*ЉiV~„Eá&º+®»éNëÎìÎL³–² ué¹¼§ßÃ󾊭ð&¼Ý=fþ…‹í “]ƒ +ö\[Û;wm MÃì‹—A^‹ß–X¶‡gÙ‰c_¡ì´ƒwåAÝ ay`P-in>Uf­CÁ’×ÚYÎÏâišÁÇÞ¾!ô±ÆXì.CQ1Ñ&ö¤TU8XAƆo 1-)ßÅ'˜Ý++>_6“‘Ž¥S £Ú&EYí–¤,Ùaã<®€ G¡|˜†á¨ÔÔmfÇ€Rü~)ÆÒØZ@à¸Îl·‰ã®ò“ñ©131e䪱ká[ZD‚I°Û â¾OOÃPЄ8m?. ¦[y må+ƦgŒô-ÕÃÏC‡n™Ä“Šb0ÙÙ kÆAAGšMeq Þ at5h8,¸Á4é6Û6!2 &Án'`srü-¬Ag#2ˆ‚ØY ¨†!j†çª?$WVªpKÿeþfvXTUU·¦ ªÎ!¾íäѯ qÜDJÊH§Ý~#/SüÌ…7Hã°bj‚ÙS¤‡V‘¼O7qr$3l4ÂÃ"6@#Xq°˜ hæÁK—Û=ÉEÚÑ}ËäKooc¯ò¹A&8B°¤é˜‹òêáššŽ†ýUNÖs«• VI¼££QI–K)ÚJ²±1{ ¢"¥ØŠ]»ï™þû.ÕF« 4öIEND®B`‚antimicro-2.23/src/icons/16x16/actions/dialog-close.png000066400000000000000000000014551300750276700226400ustar00rootroot00000000000000‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs × ×B(›xtIME× ÝºIDATxÚeÏ[hÕÇñÏÿÎÙÎήçlGËæjc‹Ú9-¤ƒ‚.ôEXJ£‡22ɱ(Ô |ë¡|¬H é¡ËÀ XZ‹õ’LÒœ­énív¶s¶s mŸ‡ßã~›}DC‚}1ˆÉ¸øþçŽÀqj¨ Ã7Zwï®M÷ôc1‹ãã2ÃÃål.w~·‘Ù`Kß·nßÞ××߯®­íŽúÆÊŠ+gθ622¿Æ3Gùx–èã\lK&÷>ÔX´..TJ”KK%®Ÿ=믱±Ù%úŽóOòj’½÷îé“ ³îzå€YË×–®›Ÿ¾aëþýòÕÕnßJG"é8§„ˆ$8œŒ„bMy…椚mÛu:fº´.37®ãÍ#ê;;Å{»-MNHÕ×Kðâ{4Gîà“t¼Ô·ÌÈÏŒÊÜZÒ¾÷i[Ù§içcš»º]ýá‚«ƒ5LO)Î,ËWDÊ\·qO5AôöëZ J¿ôÝéAñ†¤tW?úÑè©´·ÌªjÌŠÖR*ZÃuŠUJ”‹K,SzŸ|@û·Å;zU©j&RC 1 á9&BV×säŸOÙ30¤uÇ.™Ëç~uTm2å©ÓCfw)Ä)°ÆX8ÉZž‹Eæ&ÙúÄë¶>¸ËÍKçÝúú%ÕW?ví›#jSv¼vÂüü‚Ÿ@ü3Ûyw)¤’¤ænâ)bu¹Y²WH¬²ÁО_d%@Ã统·–‰­†”«ˆoЄe.|À¡Q¦Q‰`ý[~‰1|õÉŠt]Q"Q ®dµÌå?8ÈÉ›ü‹ 6 ‘@ª›–z¢#Ì”Y@%ø€ ÿ˜»Z[QIEND®B`‚antimicro-2.23/src/icons/16x16/actions/dialog-ok.png000066400000000000000000000011311300750276700221330ustar00rootroot00000000000000‰PNG  IHDR(-SsBITÛáOà pHYs»»:ìãâtEXtSoftwarewww.inkscape.org›î<PLTEÿÿÿ;7 5 9 #5>777 <;:: : 9 ; : ?"B!C"? = ; : 7 %K7Y'M1U2M5V5Z5\3Z0W4V9_5S1F0@1>4?/Mv*DS,Hi-F]3LW5LZ6R^;ToD_yD`ƒMjzOj‰Pm‰Qk‡Ro–Tp“Uq‡Vp”Zv—[v›[w”]z–_|¨`}šb}˜b~šb€¬bƒ¥c{“d€œe›fŸgƒŸg„hˆ¦i…ži‡¨o‹¨pŒ¨t‘©t”½}šµ~›²›²”²È«ÊÞÊïm†-tRNS !.38G2òsïCÛ2] î`IEND®B`‚antimicro-2.23/src/icons/16x16/actions/document-close.png000066400000000000000000000012461300750276700232150ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs»»:ìãâtEXtSoftwarewww.inkscape.org›î<#IDATxÚu“ÏkAÅßìÎJ~R1U©IsAˆxâÑ[[<´§ÒÞ¼+*B«¤V¯¼Eê%л? Š‚H5X"…B²ín²»ÙãwV6›øàñ…ÝyŸy³Ì2!c YüG‹Àù šöèÒÌÌt`¿+•÷?]÷Îm!* ×në5ÏóÀ c4Y8Û»»ø87‡âò2´T R^§ƒÓõ+J´‹ç{¡}߇ø‚>ùíê*NNÆäÝèúœº¶€ÉB!Ùžñ ÐΪªB‰Ðì9œߑʸøTZÁÕ[ Wxsë:Äþ¤.*€ØRiv¨ê ¦ «\OäÔSÒ´g `lBN$“ù<Ì#ŽË+%TŸÏã <âR -“ÃðQëÄ#èѹepöy{­¥E°”ãé<`T9Ìož½åâfÔ@Bdp¤IqvÚæxçpøõš; tõ³xìâÞK`§ßÀ4Íš Æá*%›5›MÔëuHår9d³ÙiÊÖx¿ üƒ…lÆ9—d2™¦iH$>°0šcI6¶l[†ƒaHñâ‘°eYh4à´ûërùöûDRŽé^¯'\×t­ÝJA•ÃgÕj•¦#¿“™ÈCÛ¶Ç Ã¿ööÄݵµ(< pg$,-ÕÖƒ‡›O_ÄÁØ£¿óxIRcô¿Žcû´ùQ›IEND®B`‚antimicro-2.23/src/icons/16x16/actions/document-open-folder.png000066400000000000000000000012231300750276700243150ustar00rootroot00000000000000‰PNG  IHDRóÿasRGB®ÎébKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEÛ)fr–øIDAT8Ë“ÁKQÆçÎ}óÒ]m¤m†í\Ô"4¤–³«þVÑ.üo"‚¨EFE¤šAI‚iÈ{šãó=gîÜ{ZÌÌó)D}›Ë=ð}ß9ß=þ‚dö)ÿIfçÞ{1“(€ 6޾<¼7uö_ädv™¹s_§¯Ì ÞaŒE–ç¯ÞhÇ‚D Æ "µIsåÁ݋㶳Ӣ×MYþÞÂ`8=:Ä¥É )(™A• ‚âTˆeqié €M·6øîâº)‘1|ý‘¢P@Dª±>0vê8ëß°E¶O{{‡ng1¡âÊ»Œ€*(ÊÖ¶P¸¬È]F»Ý¢Ûë”ój9o(Ahé,e¨*.ëà²^)à²ë„"/|–ÑZ_e¯“¢h?õZHkãòOL\Õ¼1BðÁŽ›×’ä=¨a V>-¿´fnߺA–åÔhPö÷3>|\£pígr ÒlóúÉ£)+f˜· «dyÞ°>£È "ýšZAaE„fÃöµ£*u[-Pí~¸®˜(Bì¯öÏ>£¡àˆÁ¡ÐŽÂÆC¬ýÜÄŽáÜÄ8¾pý6u€4X 9ÄÍ!Þm.`Ónþ"waºpŠH¹Ш޽†«>›@gÏécatò2ίlL¹ ªƒ¹)"UcR7džçÿ¿0,…1ÜIEND®B`‚antimicro-2.23/src/icons/16x16/actions/document-open.png000066400000000000000000000014201300750276700230430ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<tEXtTitleFolders!Tª`AtEXtAuthorLapo Calamandreiß‘*)tEXtDescriptionBased of Jakub Steiner design „sIDAT8•‘ËK”QÆßÌ7:ã%Ã$Ä6bm$ÉÀ&Ú ZÔ²Û¢þ‡¢–-„ˆA»VeѦM!™¶)*³lÑ¢RK%»x›ùf¾s}[̨£àïê<çwžó¼ˆpñö«öòLœÔˆN!@rbí±ûW¼cço·W$‚Áî¶µ u™‡¿óô¿þšU±ïy|ýDYHp¦÷yödGsM22;_ÀysžÆ­iŒ6 ¼ù¦cmâ/‚Nø[¡Rª¦¾6ÃØä_¬+^´¥ù³£©¾ŠÓ{+D<ÞKqDðÞ‡}ý®„ZòÅb¶€µžåŸŸXÂ{ÀU‘‰AS]ÝÄJ'C¥5Q¬Y\Îcgyüî=$•J•-Íù gÑö0JiB­4JY¢¼Æ‹ Þ“J¥( èé:ŽˆÇ‡V†P)ƒ±Ž‚6x/$KƶÖëmm])Öë‰UP]2ŒŽ¬›ÀX‡µ¶øm,eWZZZyúv†¡³(S„‹÷Üxò¿ý/ßO°¥®–àॻÒÐPuù¿&Ou:d_Ëvïj$S¹¶Ð\¤¸Ó7D˜Ng8zhU銘Ï*>O-)»°¿yQ."Ìå"fç–˜šËnXÚjMLûb‰Q® ßg~•ebn¤Éé9 0ŽãË#£_zÙ! 0AÀµ@D6õòjýŒiNxÈ ùIEND®B`‚antimicro-2.23/src/icons/16x16/actions/document-revert-small.png000066400000000000000000000016641300750276700245310ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<tEXtTitlePaper Sheets¹¯‘ùtEXtAuthorLapo Calamandreiß‘*'tEXtDescriptionwith a HUGE help from Jakub†T³½IDAT8m“KhTI†¿ª[·ÇV£1|¡I• FÇ…‘A4ƒ2>p¡ .Æm Å‚ Ýd¡ bP â 1¨ ˆ3£A‚("jƒ±Û¤_tk«÷Ö½U.º“õÀEÁªÎ÷W‰Î×V !N†¡™k-ÖX€O nÛ¸~Ó-~Tö§ÒIkŒùN¾ïÙXü­í¼ÑññÒ•ó-…æ£%=Ï«žTZƇü²¹ ©L‚ÁdœØ»7 $âä²YÖüº6Z>¥üÀ¹‹í{¾½€Ô: 5A†aAÆ Í`r)%¿,_ý)2æàí§–}Ó@|g6&ÄChB._½DWW æ×GK¹säÞY±ÿþ91@Z¶hŠÆ‚ÙXCåÔJêêj¨žQ…”R$¼…õåUS[#º´‹™Rk…0€@ ň¢Ñ(JÆS3§–ÏNÉ$¨˜^RîŽ3*X ‰g‡è¿»’|ì2J¹(å µ¦÷iŠ ¥ÑRºh-œm±Äµ‘ýÔ4l#Õ{W¹¸ÊÅÿœb¢è¾VàÎDkPCA"¥¡ïÿýŒuÓÌolåÉ?{Égcô\™€ã8Ì«®”ÓkI ¤ñ5w•ÖH)èí Ùwß~?ƒñz˜ÛÐÄ܆¦áñŒ HÆ_ñîÍ3ú^»U@)‡ªÚÍdbxø÷ 5®æñý¿xùäö!ɇ•vŒ<(¤¹°uŸ}]ŒG¡Üõ«Ž“÷«øïßëTL›MdÜ 6ìzÏú9¶´„<Ïm2=©æÖ­ûl輻äHå(\áç5mÈèbºoߤnÉ.”R¸_¥0 ”"žÉ¤§–•MçÒ¦V–6µŽÚËå²€Hë@{ÃcmßѼN¹ªMû~…µ`±PüÒ_¯Á⺑„ÖºùdÛékC ¾ŒÆIv²þIEND®B`‚antimicro-2.23/src/icons/16x16/actions/document-revert.png000066400000000000000000000016641300750276700234230ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<tEXtTitlePaper Sheets¹¯‘ùtEXtAuthorLapo Calamandreiß‘*'tEXtDescriptionwith a HUGE help from Jakub†T³½IDAT8m“KhTI†¿ª[·ÇV£1|¡I• FÇ…‘A4ƒ2>p¡ .Æm Å‚ Ýd¡ bP â 1¨ ˆ3£A‚("jƒ±Û¤_tk«÷Ö½U.º“õÀEÁªÎ÷W‰Î×V !N†¡™k-ÖX€O nÛ¸~Ó-~Tö§ÒIkŒùN¾ïÙXü­í¼ÑññÒ•ó-…æ£%=Ï«žTZƇü²¹ ©L‚ÁdœØ»7 $âä²YÖüº6Z>¥üÀ¹‹í{¾½€Ô: 5A†aAÆ Í`r)%¿,_ý)2æàí§–}Ó@|g6&ÄChB._½DWW æ×GK¹säÞY±ÿþ91@Z¶hŠÆ‚ÙXCåÔJêêj¨žQ…”R$¼…õåUS[#º´‹™Rk…0€@ ň¢Ñ(JÆS3§–ÏNÉ$¨˜^RîŽ3*X ‰g‡è¿»’|ì2J¹(å µ¦÷iŠ ¥ÑRºh-œm±Äµ‘ýÔ4l#Õ{W¹¸ÊÅÿœb¢è¾VàÎDkPCA"¥¡ïÿýŒuÓÌolåÉ?{Égcô\™€ã8Ì«®”ÓkI ¤ñ5w•ÖH)èí Ùwß~?ƒñz˜ÛÐÄ܆¦áñŒ HÆ_ñîÍ3ú^»U@)‡ªÚÍdbxø÷ 5®æñý¿xùäö!ɇ•vŒ<(¤¹°uŸ}]ŒG¡Üõ«Ž“÷«øïßëTL›MdÜ 6ìzÏú9¶´„<Ïm2=©æÖ­ûl輻äHå(\áç5mÈèbºoߤnÉ.”R¸_¥0 ”"žÉ¤§–•MçÒ¦V–6µŽÚËå²€Hë@{ÃcmßѼN¹ªMû~…µ`±PüÒ_¯Á⺑„ÖºùdÛékC ¾ŒÆIv²þIEND®B`‚antimicro-2.23/src/icons/16x16/actions/document-save-as.png000066400000000000000000000014051300750276700234440ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<tEXtTitleFile ManagerNsƒátEXtAuthorLapo Calamandreiß‘*tEXtCreation Time2009-11-22ÇÁÌ&IDAT8•‘ÍKTQÆgœ9×FIk%Ä0”›‚¨( A1¢¸í‚hQ-¤V-"uQ EôÜŒ6áBj‘ŠEƒÔB?ʦd&µîgDg¼óá=-ÂAíøÀÙ<ïûþž÷œ#ôÇZJuUlMY„¸%tC.÷œózdp³Î¦Ö6†ß­óJN!r±wW½¨Ü^½3øðÑ}×áë׺ðû«7–þꆴK+…ˆÚ¢J+…ˆnH[膼 Ü*7FÜ>÷œ¡ô=†ÇÝ–³»(¥\nH5ºØ§Ä+Ýj³>ïZäé'Ú¾ ‡¹qg -Œ %p:^´?®úëÏ.´u¨ÒjyZöu œ:r©!šùL¨÷pÜxRÅ(ùm~Î7w–ͦ£-ÄÕfaµkÖ¢³?Ô×·{O?˜¢Ö[ÀOûsÓI¦§Ìçª+à}è:”èæÝÈáƒ_IšãìÝ?À‰Y’aAòCƒ¿¸  ¿ p¢õ¤(¿æÄ—Q¥”R¹å¬Êæ–T±XPŽã¨|ÁVKÙE•Τ”•ø­f~ÅÔ«Á—å_ñ¬n06>Ff!Ãü|Šd"×ëCôiäí<Ñh„¼ÇƒÓ´þ½Bl&F©TÄqÒ™4áïa¾…'±mŸOÒÒÜ €”ËrXf)5¤Ô¨©ÙA ¤±ñn²Ì¸ À²¸|¥Ýuàú.C½(ý(ºIEND®B`‚antimicro-2.23/src/icons/16x16/actions/document-save.png000066400000000000000000000012661300750276700230500ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<tEXtTitleFile ManagerNsƒátEXtAuthorLapo Calamandreiß‘*tEXtCreation Time2009-11-22ÇÁÌ&ÎIDAT8Å’Ïka†Ÿï#»{‚­ (“T A´¡ZPô Bÿ½HíM½‰GÿÑž<z³±R‘šu…&%‰Ôl6?mRw›ºã¡XªnDO¾·Þ÷†%"„éÂ=ã„FßÅ‚`rz¼›óéÐ4 Ð÷/™LÚ3ŒÖ·{ùzP$;RìÚÛpìß©ÿˆl-Îß5SZ«‡(Ú¿/NYÀ%®o½ÈO­ÕÔå³7l³ú˜{ýh³ŸŒåTj,Vh.ÄfæÜFCÇ[¤ehÆŽO?2ÜMaý%‹+Y@Y=W@‚k³éÇ3±ÁÑZ|‰~sU?ǧ|…Rέ£˜̧ŸË‘Ú-^¼z†}8K-ißß`É^Æ}¡š>Ø÷­cdæO9=zNm ADx›}#""«_;ÒYmK·»&Aˆ¿æI»³"fM÷³”–‹òdvZ~ä6ϘYÈÐl5©×kT]—HÄ@)…iXøžO>ŸÃ÷|4šrÙù}…b©Èúz— h4Øm>Øïñ<Ã0992€iš8NÀ)W0M Ó´ˆF·044L˜œr%à8Œ_½ø“¾6ñÌ„Œ‹ÏIEND®B`‚antimicro-2.23/src/icons/16x16/actions/edit-clear-list.png000066400000000000000000000012351300750276700232540ustar00rootroot00000000000000‰PNG  IHDRóÿasRGB®ÎébKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEÛ9eIDAT8Ë’ÏKTQÇ?ç¾ûf4š ‚Àb¤1,²´`hQ2V`“¸Ì þŠ ]‹ ½-‚j§…©T(mªMµ3©H‚B°¤,f,ñÇ̼wZ¼çÌD¶¨/÷r/Îç|Ͻ‡t:íq ñ;ÞÞÞn Õ¬ÿ! `€ÅüŽ*‘à ïžç‹oe=¯bcä­âZ­É_'Tc KJg5RäZkŒHXP@LÕàùµÀ$I‚`Â{µ þÆ€á7e".¿Ù ACÐZÙ£¿cóŸ€ÞV×µˆ˜ÐIèȱˆ €~_+Ö*Ï.&è¤ÒŠXßXžŸícvhŒ‹q¢|ái63jkÜž.±>¨¢’cq¢})ŽŸ<×'÷¹9/ˆ_&3ó€ôác{Æ¿-L ЦªS+K¬ãbLPÝ6ÊÇáaò·®bÖ,nw0(Ÿ=­K6Ê£kƒÙš__1à@Ù•Ëaê똸„¶¨1ø¶É•Á 7`¼ÚÂÔ*®ë ªëÿ†ˆàlj`ñà ­ùï”_γ°e/+5Ö¦ªºü#¯ÅåŸZ^]R¿¸¬ê•TUõý½1}ÕѬs wºêÝ®Cú üw§2z²(ÔÇâl¤™‰1º'çôEO·<Û‘¤P(x;O'œý뾞—ijjªv-Ùm׳G_wÂy ¤ŽÀ¹‰Þži€_ÑëÖ¸¾õùIEND®B`‚antimicro-2.23/src/icons/16x16/actions/edit-clear.png000066400000000000000000000013431300750276700223030ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<`IDAT8ÒÏKTQðï½ïÇÌ›Ÿƒ$#bS)f…B`¢E¿‚ÚYA»‚j%­‚ $ü ŠÂM›ÁS*±)g¡ q!©™?rÌŸoÞ»÷´ûá Ì]ÏçÞsÏaD„bOO‡vA×ÕgŽm×*ªÖ}çEö/¶¸÷šÚé1\oŽÔ7Õ]ºÜÁ¥w ( ÷:3™¢ô´œi÷¾ÿ:µµe¨ª2Z4¦w…*ºrt^iÅdt<·œnP÷«›ùX6èØâµ¢³Ûµõ n"Bdl(-çù½>{t_ j>hç}fyëé1C£L}±óÉD|b#œ´“ÛðåâOï‡×üfCQ$ãQ„NNiŽ»ŽžËýÛ=Æã!#KÖK‚§ÝmÜÒû¢"„_é,t}±Õ>ÑÚ–ÄÓ`fØ p·ëƒ× U+Z<œ«H§!±~ –UP׫e»ÿf[9ÿ³‘€)) ÔT›þ°®»JÁ˜‚Lj_Ùvfz$ŸÉÏO´Å;—ògKÁ‡KüÕU¾’J=—]c ¤°2›û£ïkË #soEé»c+˜þ0ˆ$¶â àL•ýµ×_oDÎ)ÃSn,Í¿``eqV& Ew#¹9)mH’L”$Òcìllu"Æ%ç–†3ÙäÏI@Ó ¤¶æM¯Báêdc#ÙÀáæO¤Pöã¥ù¡åTrà:—dÃ)ä­-¤“K–”ÎÛÝ-ìLêðûŒèª„ðHâÔTÛ¼ùùßìoõ|xIEND®B`‚antimicro-2.23/src/icons/16x16/actions/edit-delete.png000066400000000000000000000020071300750276700224550ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<tEXtTitleAccessibility Preferences-ð³=tEXtAuthorAndreas Nilsson+ïä£tEXtSourcehttp://www.andreasn.se¡ëzÍIDAT8e“ÍO\eÅï½w>/2Ã%c`J@Lw5$þ ÝtÓ4í´XH šØº°© M[’XVþ¸2m´| müHe(I‡¹Sf`:÷}`%ñÙ>¿s6磪¾­\®×µö¤Uµa8,"¨È’ ëúeïÖÖo‡ysØàq.7æÆ¢Û—ºãš}Þ¥³T‘Òa±$Õ‡{¶ñôýWËå„Ï 6{{¿Š´gŽëð OPEm¡åm0miLöhñ©÷}­±±y/÷äÉ[¨ªPêå¸äú|»\À„Šyšôü>ã¹cPUÄ õÛ·Ø››Cº»ØþæÛºZ;èY‘“ñöLÔTwp^î!vaœ™›3„¡åÂ;ãˆ×?¹F[&ÃØù1š?ÜÃln;òbtç÷µÓžˆŒ’ˆ{¶R!vé8†Çå2kkðá•UŠÅ"ù| ÄÏž¡:9‰ç·xÀ¨cÃpØÄbP«ã  ªL^œ¢#ÛÁ_ëë‹Eººº8÷öªŠ“ÏÃN ×O"ÖzÖZÄ ˆ *ˆ 8®ó,^Ç@‘U4 ÷jíRÐ\) "Üþô¥R‰ÎÎN:²YÖ‹EnܼˆÐ\YA£šA§Ùl.<­V“ v¿¸‹Ø×óèééáòÔ4ïNMÓ×ׇŸL bÙýüÆOÒ¬VUÌ"ôi$²Ô><”4å2‘S§ˆŸ?Æá Eö»¦ì}6Kcvmo§|±&ÖŽUeј‹nªõJ:?àËæ#Üþ~âgÏà= €]]e÷Î]Âå%¼Î*ÖšAõêˆêµý*cîóu$•:ÖÒÿšo 4¨¢µú~•ý$NësH4ÊÎÏ¿Öl, «¾‰ªü7&cÌ0a\÷#ÿHWÔM§åä­CA:}4eˆX05…eIEND®B`‚antimicro-2.23/src/icons/16x16/actions/edit-table-delete-row.png000066400000000000000000000015371300750276700243560ustar00rootroot00000000000000‰PNG  IHDR(-SsRGB®Îé pHYs × ×B(›xtIMEÚ$*¼PLTE¨¸Èí <<<áäéãäçìêìðíïòðòôÈCC;;;ããæëäêïêÓ×íæéñàâ¼;;;³ããæëäêïêæêí¥§ñãå¹Ã߹櫮µ·ÚÜøüþ;;;³ããæëäêï유íßãðz{ùüý;;;ããæëäêï슋ñÝß·ÿÿÿÿÿÿþÿÿøþÿÿörr;;;ããæëäêïëÙÝò޶ø††þÿÿ脄݃ƒæŠŠýÿÿå––¸ºÊÊÓtt;;;<<<~€‚‚†ˆ…†ˆŒŒŒ‘’‚ƒ’’’—jj˜…†›žœ‹Œ¨«¬ªª«¯¯¯¯°°°³´´´´µ¸¿ÁÌØããæëääçìäêïåëðçééììëïîÁÄîìïïÕÙïÜßðÖÚñÝßñåèòdeò‘òÉËòõ÷ó‰‹ô”•ôãåöy{öÐÑ÷¦§÷úüø¹ºøúüùßàùüþúÌÌûûüüüýþÿÿ_ŒTtRNS@@@@@@@Gkkkkkkkksss||†††††††••••••••¥ÀÀÀÀÀÀÀÁÁÑÝååéêêêêêêêëìïðôøûýþþþþþ·V•bKGD:N Äú¼IDATÓ]Ž; ÂPDs_n *Z*þÑJ0¸×àÜ›°ÔBЂ D‹$ >ôÍ5‰øÁ§f`ÈúÐvÖèþðÄxSúVcàŽ÷? åú”e’Ä-±¸²ªn¤?áBOhî -ë‹m„ØÜ¡õCLt¡ÒIì& N¸)»ÖmÞÚå–®ˆd2"Šr¾#Ú½˜»¤0…ųÑÈ~A JWèrh ŽÛ;Q%P/Ó»øu*/Äúç âRuï8c‹.IEND®B`‚antimicro-2.23/src/icons/16x16/actions/edit-table-insert-row-below.png000066400000000000000000000015241300750276700255220ustar00rootroot00000000000000‰PNG  IHDRóÿasRGB®ÎébKGDÿÿÿ ½§“ pHYs × ×B(›xtIMEÚ  ,D¦_XÔIDAT8Ë¥Ž]ˆ”e†¯÷›ùföÏk£,OÕuÂÐÑd!Ð Ûé¤$¥¨!:‰P̃)Ë6ZÑ0—hj¥¨!° <w×]¦Ö X[pû˜™ÝùùþÞ»ƒÝ5Ϻàáá↛I›%–TÌŸoHRqÙ³¬P ¿÷j_iàǸ÷jßoèp–ãÁ8Ö& ¾]ŽâhÉ?ZJéÏíÌìÙ°}Ã¥]—œ==Û×çvæF8IÿJÁðsþŽSE¿§À{ßú=Ï÷wÃdœ«•T/€â‚™«•ăœ¸»PÒ±mÇkÁÖ£5»íx-tìnxÝÞ%6—¯‡òmk-=À¾Á:£¯uRš'áIÃ?VkÎ3™*Ì¿!Ö • ¢ÛÜâýb )”l()ÖØøÄR½ %Iߌ~¡Ñù/-Ÿ#s+IÎ,Wкï×=ï”X9ñ×ôÄòn Ä„A‹½™}æJîââCÙ®À\0¤6&ªû·<óÖÌî™QóúHSwjrÀ—¡+íÒ B$‘JœtBŸ(Jx™Dr|Mš±j©²±·ä7“·çÅ僖O³ÿñ˜ï®ÿÊìê­ÚØäȵ»½³xë_$5Éo1‰¾¡0ýënúϲ%»ÖÁiµ,ÿnç¥G›œ›N2Sš"÷˜áí_’¼³+àÓÖ³¼ð¤OyQ þd)Jpx8dí*¨Ô-Îì‚xº»ÉgåvÞÌ.Òܼ—Õn“lÈ7\>ð/írä)K‡kùøç˜ †é;])‹yâhS³•Ȱª½–ß"²¢ÓupÒDþ"~$Ï3Ùæ2¹àkÊÁLv¤t“OÎ)¨WÔ¨z ê>uBŠ÷óUïZ£ê 5ªÞ+ª×[){ÝÉFèÐP±B’rYÛh©¦ôŸÛ%¿—ÈF˜|>¯ „1†TÊeɹ×`_þŽãŒñù'Åð(&ÊIEND®B`‚antimicro-2.23/src/icons/16x16/actions/games-config-custom.png000066400000000000000000000021301300750276700241340ustar00rootroot00000000000000‰PNG  IHDRóÿa pHYs Ö ÖoyœbKGDÿÿÿ ½§“ÊIDATUÁ}P“ðïž½W€–xà¡t]tÁ]r‹êºNËÁ¨ ñ"/»Hк¤ñR‰€LÔÉêò¥±ž¹!ã“`Œ„â€-ÇËÅ‹!áyƒ_Eõùà_º*´*-Ô?«aª1mÖ¨4éæV³ljb*×ét¾£ªRù°zZŽ“ŸŸÒÒ2”••aCZj’““9‰)Ò”mI’¤Î™Æ Šþ¬R©iqq‘¦§¦&ÚÛÚ>Àc4‹Å‚ I’$ˆöŠ Ú+B¢8ÑgW䮀JE%RSÓy¹¹ÇËÝî úÇʨËEZ欵³ý½}̃¹9üÏÃE-¯Âf³ÃnïåÞèèËê.--QscÓJ¾,ßS^.÷X­ÝÕuuõ‘ÝÝ6l'¦àõ7ß‚Nø¥²Lî¡ÂÙ3Šàþ¾¾E›Íæ‹%oùúùùGGG³…d4Ö”›L&lh:´æ ^¾ʼ×@ô-‡ˆ0âjì³÷¬çÉd¯ÊÏœ——7vïÞ³5>>A·-..ÈûȈ”‡†ØÀŠàíhþ¨b|ÌM--­Ÿ ÜéÒe¯cééü¯öíã–Jan¾Î9Y\ÜQ °|ÃDUxlÝÁ½‹!í–ŸÚ‚È®aññ6¡ X‰‹J\“.8'œžÆ€c0ËŒh½áP?Žêƒ_Î ²çÛ‚èžþiRfã8…Íÿ>ÓÜXQQ\´?óh“âÜéñ»cuÓƒ3a÷û'€º“4•p½ ¨þqîZÏBëód(„£š½`4œy2õk÷*/ЭËÚå-ézµvzL<œÏ^ör±Å¡ÞìZ |ʈAü"±^Ï’X,^154¬Î>ò¬LÞnYÕ˜sžéù’~kn>ÇЃ`ôü°éÊCËvºËz“âsî5¢>ÜUÎÏÏÓàààŠµ«“jjj×ìfZš_uÜ¡ÚÚke°*€v9Þ›i  ¹ægÉP„Ù QÀΙI'úûoêH§Óý%‘HÜ111ÝÉÒÔÉ–ëæõ‘‘aR©TQÿvŽŸ™]²®w)8Tð!ö‘¸Ük0G éøwZZZ˲žŠŠŠƒ¸ò5÷¥[êׯ—6ÑÇ #¢^a¼‚ƒƒ}CBBü…B!¢¢¢xááႬ¬,˲ …/$$$pêcàßDyòœpÛ¹ ÂD2 #äóùQ<O À‹ýüü¶†††ò¤R)ço"åáÇ"zTXtSoftwarexÚ+//×ËÌË.NN,HÕË/J6ØXSÊ\IEND®B`‚antimicro-2.23/src/icons/16x16/actions/games-config-options.png000066400000000000000000000020551300750276700243230ustar00rootroot00000000000000‰PNG  IHDRóÿa pHYs Ö ÖoyœbKGDÿÿÿ ½§“ŸIDATxÚu“mlSUÇŸsϹ}o‡ƒÒ±ºÅ·µÆ²üF$™Ñ`DƒŽ9´~`(n1ÚLpÆGsT¶‡Àcˆ_ T]Z6M:Š5F6é&íÄaÛÑÚ·ÛÞ¾Þ{=‹Ÿ4òKžœ'çÃÉÿùÿŸwÃþÉlyl3H’¢ zÒ»=^ïÕèÌ÷Ó…S޾àRÜ…ÓŸMÀÜÜu`…Ãa‰°¤©{Ï5‹e9õéø×‹‹‹ö±QÇÿÃÌôx¡ãEÐjµ P(µFUUvJ ŽKò¹üS£é»ÉóçÃp:/\!‡óó "<ÑÖ™L‘44lü8êõ$™J(0ÁA¹\þþ—ì3ÀóßO <Ÿ-Ûl¶©ÎŽÎÄôädøš×15> ozúÙ‡IQÕŸÉñÔ{À†ôëôH.WŠKK7»0fíápD^*QKkË`³¥yë³³ÛÚ,±&z‡áëïÎÅ\Uô?ghߊýþy ªä‚XS©´ï«Uj£ +UŠÞ£ƒnÿÂBÿ7NgyãCfÑ´«C`¥°/̈3òˆ¡î¯µ7Ñ›¶7je2ö\:•Ù.‰Pª\[É‚úv·wÒDëõú÷B¡P1Ã¥e++1©z½ 5Þwo)ØÀ­… ŒR©<„1Þ§Ö¨Ç1A¬ _¿øÕÅA³Ù ÉdR”`0ˆGNØÿòùÈqËuõWÌÈDH§¹J²,Á˜1#TX§TܳÿðÈ1Öív—VVV~¤•±Ûío¹\®/ GK&” Ö={^¡†{ÐÛmFª ‹ÏòS›}äÊÑc*¿A(F£‘п 3™Lª”¡KÄ´¶¶®&%ù|>}EE‡ß¾ Íz¼RCÕòù¼ÿ BÊtß‹´ÇtVÏ-¡®®N´Z­9ú€ô7tð´r¶—ºÿ"zTXtSoftwarexÚ+//×ËÌË.NN,HÕË/J6ØXSÊ\IEND®B`‚antimicro-2.23/src/icons/16x16/actions/help-about.png000066400000000000000000000012351300750276700223320ustar00rootroot00000000000000‰PNG  IHDR(-SsBITÛáOà pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î</PLTEÿÿÿƜĢÁ¢Ç¢Ä Ãâß ŠŠơƣƣǤģƣƢƢƢȣȣǣǣţġġàÈ© Ë©Ȧ ɧ ̬̮ƢƤǤȧ ȧ ˬÌ­!Å¢ƤÄ çÕxçÕ{ϲ%в'аÖ½FÜÅDßÊUâÐYãÒ`éÜŒéÝ‹×À&ÙÀ)ÞÈBâÏWâÐ<äÑ=çÕDè×SèÙcéØOéÚiéÛrêÛjêÜoëÛXìÝbìßoìà|íàvïáoïâsïâwïã€ðå–ðæ’ñäwñäxñç–òçôéˆôëžôë¬õí¬öêöëŽùòÀúñ¢úôÇúöØú÷ßûò«û÷ÜüøÖýüðj9tRNS!)+/7@CKS    ²²³³ÈËËÌÌÒëëïóóôôõõööööööö÷÷úûûüüýýýýýýþþöÒk›IDATUÁƒÃÀ·mÛ¶mÛÞþÿ¶,MÖÞ?„™ƒ*©¸ûIÐÈóïœDè¶{ P8Wä||E]2¾XR_j~Ø^×}Ú+f¦x«[ï-O§ÕtÑŽÙàê¥á¨?žlÖe‡Ž‹/‘Á–4gY»AŠÀݨv<ü©‹•‚4BkÍ"6¡/̔˩¡êßrÐIEND®B`‚antimicro-2.23/src/icons/16x16/actions/text-field.png000066400000000000000000000005171300750276700223410ustar00rootroot00000000000000‰PNG  IHDR(-SsBITÛáOà pHYs»»:ìãâtEXtSoftwarewww.inkscape.org›î<HPLTEÿÿÿ fðz­õ gð hî hî/€òU—ôw¬÷gîiîhîiïhïgïhï‹‹‹‹‹‹LÐÎótRNS224Gxxxxxyz{|}~€‚„¹öZ“˜WIDAT…ÁY‚@°*òÄm¸ÿM%.ÉüѲ¯9W *z¯Gy¾¬=:ÅÁG‡ ø ‚‚u#mi}Q â¾þ ¢D%8Ý–å:ÏÓtÇí{,À ŽÍüIEND®B`‚antimicro-2.23/src/icons/16x16/actions/view-fullscreen.png000066400000000000000000000010571300750276700234060ustar00rootroot00000000000000‰PNG  IHDR(-SsBITÛáOà pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<tEXtTitleOptical Drive>gº ÀPLTEÿÿÿ€€Uª@@€33™M€F‹ P€GŽQ†"J†K‰Gˆ!LˆI‡L†ˆŒ…H†"J†"L‰ L‡ I†"L‰!Jˆ#LŠ"Jˆ#M‰#MŠ#N‰ J‡%OŠ!Kˆ J‡#MŠ!KˆŽŒ$NŠ!Kˆ!Kˆ#NŠ$NŠ%O‹(QŽ"L‰"Lˆ#M‰ Kˆ!Kˆ Jˆ#MŠ J‡ˆŠ…ÀüÆÈÂÈÊÅÌÏÉØÙ×ëíéìîëðòïñóðôõóüüüÿÿÿaxy2tRNS &)+/19IJL[hvy||‰ŒŒ§²¼ÌÎÓÞâåèêõõõõö÷ûýýþþ o¼ð„IDATuÁç`€áGÙ3›lÙ[¯UÈùŸ•ïJõÃ}Ð’DµºDäç« !úж§iþÑ0,Q,ƒ8J¦‡uó<ï|±h–!;Y#wÇqNWÁ<Ô¨o7ˆûR\Á<Ž :C/å!´ûI €<}B1†O|ÅRŠÎ6ØíÇ Br‹e‰ˆF‡7Z”àH{ÓIEND®B`‚antimicro-2.23/src/icons/16x16/actions/view-refresh.png000066400000000000000000000016321300750276700227010ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<tEXtTitleOptical Drive>gº øIDAT8•’ßoSeÇ?çíéÒvv3qÈ2ºvþ(ŒÁôFÒf`6Þ“AP¼4K0!3Är2Ôeq13†À«™ˆ vÈdŒÌ ȧ¸V9xÃø±–Óvç=ïëÅ,™îÊoòÜ=Ïçûäû<†Öš²úûûÍ@¥ùº¡]º@W€acÚøÌ†c(uŒJ;zôÃi³<<88øL T1ÖÚ²yÇæ–-ÔÔDB ¥»6—˵ý01¾7›Éäöï?^¸w³ã`› 0<üñó>¿/½wϱx¬‘R©ˆãäQJ!„  ±¯û¶}'\_¿žªp4¯˜ ñÅ[ߎ­©]ËââC®þ|•ùùÛäòyžª¬dãÆM$^L‰Dø¯Ì¡OvÆcñŽuÏ®ãþýΤOsǶ'A ­C…RqðÂÔdâöï¿ÑÕ¹“@ €Rj`(}øÕ‹Efo\Ƕís%Çí²,Kžþä\O÷D<Ö¸ÊYJ¹ ÐëƒÁ®[âæ­[Œ,Ë’®+Ã=äÁƒ…U×u)gP'„R ÇyŒ”\Òäyïžúæë/µÖ‰åkk´.×?HÏ+KÅj!Lª«ŸæqÎnÎ?vü2°a•ýÊ¥ç}ŸÉd5ÆiÚÐD&›µz¾ê™Û7æ­x°À’,žvk­&<—÷†††r¦Z’§¯\¹|¨!¥¹¹…ùÌ|»wÍ=ûÁÌû>íÝ”Ú׊ÆJ%Û_ÞÔÔÄ“ïÌÎÎ^N˜BøOÍÍýr~êâT{*™bÏîn¶´nÝ~qúÂö»wÿâ…h”ä¶$Ñhù|Óô#¥(ogh­éë뫦¾ÔÙñZCÛÖ6‚Á~¿!|(¥pÝ% ‡ôxšéŸ¦o˜¢â¥‘‘‘ÂÀ‘#½Ï)|Ÿ×Fj»R©$‘H-Uá*Çaî×9®ÍÌðÇŸÙoM£âÍÑÑÑÅm°R½‡{; -{•2ê5ºÈkÍ…þ®nM]Ú²,µ²àÿêo&þXþ<ŒPõIEND®B`‚antimicro-2.23/src/icons/16x16/actions/view-restore.png000066400000000000000000000006741300750276700227330ustar00rootroot00000000000000‰PNG  IHDR(-SsBITÛáOà pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<tEXtTitleOptical Drive>gº xPLTEÿÿÿÿ€€€+U•&MŒ!K†0\”ˆŒ…K‡Lˆ J† Lˆ JˆHp¥f½ J‡ŽŒHo£ J‡ K‡™ºÛ J‡!K‡&N‡Dk ˆŠ…Š«Ð—·Ùž½ÞÓ×ÏØÙ×ëíéìîëðòïñóðôõóööõüüüÿÿÿ€Š{tRNS =EIjknož¤ªßâãøùú@×/:uIDATÁQr‚0À yIÛñþÇôCMîä”VÊ–^Ë þ´º]G€ßö©õ=wÖ5­Î}\²öŽciu>ß'é÷ê<¯‰ôú%g ®6– b™n´1  Q„ˆð–¤$i=‘J[IEND®B`‚antimicro-2.23/src/icons/README.txt000066400000000000000000000014621300750276700170370ustar00rootroot00000000000000The icons bundled with this application are using icons bundled primarily with the Mist icon theme. These icons are licensed under the LGPL version 2.1. The assests for the Mist icon theme, bundled in with the full gnome-themes package, can be found at http://ftp.gnome.org/pub/GNOME/sources/gnome-themes/. The full text of the LGPL version 2.1 license can be read in the included lgpl-2.1.txt file. Any icons not bundled with Mist are from the Oxygen icon theme. Those icons are licensed under the LGPL version 3. The full text of the LGPL version 3 license can be read in the included lgpl-3.0.txt file. The full Oxygen icon theme can be downloaded from http://download.kde.org/stable/4.10.2/src/oxygen-icons-4.10.2.tar.xz. Additionally, you can got the Oxygen theme website located at http://www.oxygen-icons.org/.antimicro-2.23/src/icons/index.theme000066400000000000000000000001421300750276700174660ustar00rootroot00000000000000[Icon Theme] Directories=16x16/actions [16x16/actions] Size=16 Context=Actions Type=Fixed antimicro-2.23/src/icons/lgpl-2.1.txt000066400000000000000000000636421300750276700173460ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! antimicro-2.23/src/icons/lgpl-3.0.txt000066400000000000000000000167431300750276700173460ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. antimicro-2.23/src/images/000077500000000000000000000000001300750276700154705ustar00rootroot00000000000000antimicro-2.23/src/images/antimicro.ico000066400000000000000000000341321300750276700201540ustar00rootroot00000000000000=9 D8(=r CDE;<<:::899567556556]^_<=>?@@7>>?d;;<†9::677v445F445$556~€QRSsMNOÉMNNüLLMÿIIJÿDDEÿ<=>ÿ778ÿ556à556Ÿ667#445445vwxuvwÁtuvûuuvÿwxyÿyz{ÿuwxÿjklÿYZ[ÿHIIÿ;<<ÿ667ÿ445ð445Q445ÈÉË«¬® ¢£¿¡¢¤ÿ§¨©ÿ©«¬ÿ¬¯°ÿ®°±ÿ¬­¯ÿ ¡£ÿŠ‹ŒÿpqrÿVWXÿBCCÿ899ÿ556ó445@445ÀÂäÀÂÄÿÈÊÌÿËÍÎÿÎÐÑÿÐÒÔÿÒÔÕÿÑÓÔÿÍÏÐÿ¿ÁÃÿ¨©ªÿˆ‰ŠÿdeeÿGHHÿ889ÿ556Õ446 ÓÕ×ÎÐÒTÍÏÑÿÑÒÔÿÓÔÖÿÕÖÙÿ²³´ÿ–—˜ÿ‹Œÿ‘ÿ£¤¥ÿÊÌÍÿÍÏÐÿº¼½ÿ•–—ÿfggÿABBÿ566ÿ555gÓÕ×ÐÓÕ×ÿÔÕ×ÿÂÃÅÿz{|ÿ^_`ÿFFGÿDDEÿWXYÿmnoÿopqÿ¦¨©ÿÐÒÓÿÀÂÄÿŽÿUVWÿ89:ÿ555Í667ÔÖØ<ÔÖØïÓÕ×ÿ¾¿Áÿrrsÿÿÿÿÿÿ ÿ?@AÿijkÿœžŸÿÎÐÑÿ´µ·ÿrstÿCCDÿ556æ6:7ÖØÚÕ×ÙÿÓÕ×ÿŠ‹‹ÿ\\[ÿÿÿÿÿÿÿÿ !ÿkllÿ³µ¶ÿÈÊÌÿ“”–ÿVWXÿ9::ÿ233×ÙÛ ×ÙÛ°ØÚÜÿ³´µÿnnnÿ???ÿ444ÿÿÿÿÏÏÏÿ¥¥¥ÿÿÿ---ÿ‚ƒ„ÿÑÓÔÿ°²³ÿrstÿEEFÿ777899ØÚÜØÚÜÌÚÜÞÿÿHHHÿ555ÿ;;;ÿÿÿwwwÿùùùÿ°°°ÿ ÿ ÿ  ÿWXYÿÇÉÊÿÆÈÊÿ’“”ÿ\]^ÿ>??ë677/667ÙÛÝÛÝß×ËÍÎÿ…„„ÿ¨¨¨ÿƒƒƒÿ===ÿÿ$$$ÿÛÛÛÿáááÿBBBÿÿÿÿABBÿ³´¶ÿÒÓÕÿ³µ¶ÿ|}~ÿNOPÿ:;;Ä445667ÚÜÞÜÞàÒÆÇÇÿ………ÿÓÓÓÿØØØÿÄÄÄÿvvvÿ›››ÿãããÿœœœÿÿÿÿÿ+,+ÿ´µ·ÿÕÖ×ÿËÍÎÿ¤¥§ÿopqÿGHIÿ889Ð213 556ÛÝß Ýßá½ÊÌÍÿ{{{ÿzzzÿ¹¹¹ÿÒÒÒÿÓÓÓÿÐÐÐÿÝÝÝÿ ÿÿÿÿÿ++,ÿÈÉÊÿÔÕ×ÿÓÓÕÿÆÇÉÿœžÿijlÿEFFÿ899ì4455213667667445ÜÞàÞàá›Õ×ÙÿŒŒŒÿzzzÿqqqÿŽŽŽÿ´´´ÿ›››ÿÐÐÐÿŽŽŽÿ222ÿÿÿÿQQRÿÕ×ÙÿÓÔÖÿÓÔÖÿÑÓÕÿÄÅÇÿœžŸÿmnoÿLLMÿ;;<ü778Š5662344 465+5565467-445556556Þàálßáãþ®®®ÿƒƒƒÿ‚‚‚ÿ}}}ÿÊÊÊÿ   ÿÅÅÅÿáááÿÆÆÆÿ€€€ÿÿÿœžŸÿÔÖØÿÚÜÞÿáâãÿååæÿÝßàÿÅÇÉÿ§¨ªÿ|}ÿ[\]ÿFGFÿ<==è89:·667s44550.0*(*213555c677Á899â;<<ê::;ä677Ï445445)ßàâ3àáãëÔÕÖÿ˜˜˜ÿ}}}ÿºººÿÆÆÆÿ~~~ÿ ÿzzzÿÖÖÖÿÜÜÜÿQQQÿ;;<ÿÌÎÐÿÕ×Ùÿ””–ÿÿÿzzzÿÜÝÞÿÍÏÑÿ»»½ÿ™š›ÿz{|ÿabbÿPPQÿEEFý>??û;<=ú:;<ú<==úBBCýIIJÿSTTÿYYZÿRRSÿGGHÿ<==þ777õ566g2-0567ßáãÆßàâÿÆÇÈÿÿ¿¿¿ÿ©©©ÿÿqqqÿÿ777ÿˆˆˆÿ)))ÿ°±³ÿÛÝßÿ¿ÁÃÿ556ÿÿÿÿ222ÿ««¬ÿÎÏÑÿÎÑÒÿ¸¹ºÿ¢£¤ÿ‹Œÿwxyÿhijÿabcÿabcÿhijÿtuwÿ€‚ÿŽ‘ÿ˜š›ÿŽÿxyzÿabcÿJKKÿ;<<ÿ677{556ßáãáâäEàâäÿàáãÿÐÐÒÿ¾¾¾ÿ•••ÿ‹‹‹ÿ‡‡‡ÿÿhhhÿ‡ˆˆÿµ·¸ÿßáãÿÛÝßÿ¨©«ÿˆˆˆÿ‡‡‡ÿ111ÿ:::ÿJJJÿBBBÿHHHÿ¬­®ÿÞßáÿÌÍÏÿÃÄÆÿµ·¸ÿ©«¬ÿ§¨ªÿ˜šœÿqrsÿbcdÿabcÿhijÿuvwÿ”•–ÿ³µ·ÿŸ¡ÿxyyÿSTUÿ<==ÿ455{áãå¾áãåÿàâäÿÜÞàÿÒÔÕÿÈÉÊÿÄÅÅÿÈÉÉÿÔÖØÿÚÜÞÿÛÝßÿÙÛÝÿÙÛÝÿÑÓÕÿ~ÿ®®®ÿ‘‘‘ÿmmmÿpppÿaaaÿPPPÿ)))ÿYYYÿáâäÿÑÓÕÿÑÒÔÿÔÕ×ÿš›œÿSSTÿXYZÿVWVÿUUVÿUTUÿTUQÿHJEÿJJJÿ§¨ªÿµ¶·ÿ}~~ÿQQRÿ9;;í3458âäæâäæþáãåÿàâäÿàâäÿàáãÿàáãÿÞáâÿÝßàÿÜÞàÿÜÞàÿÛÝßÿÚÜÞÿÙÛÝÿÀÂÃÿ‹Œÿ©©©ÿ¤¤¤ÿ‘‘‘ÿRRRÿcccÿ~~~ÿ@@@ÿ`aaÿáâäÿÕÖØÿ‰Š‹ÿNNOÿ^__ÿ]^_ÿ_``ÿ^__ÿOOXÿ* jÿ)ÿA>]ÿ000ÿŽÿ«­¯ÿqrsÿGHIÿ789—454âäæèêìãåçyãåçÿâäæÿáãåÿàâäÿßáãÿßàâÿÞàâÿÝßàÿßáâÿàâäÿÞàâÿÚÜÞÿÝßáÿÔÖØÿ££¦ÿžžÿ™™™ÿƒƒƒÿZZZÿfffÿWWWÿ333ÿçèéÿ–—˜ÿLJYÿVUaÿ^__ÿXXYÿTUUÿNMXÿaÿ™ÿ¼ÿ™ÿKJZÿABAÿ“••ÿ“”•ÿ]]^ÿ=>?Ý798788äæè äæèÅäæèÿãåçÿâäæÿáãåÿàâäÿßáãÿàáãÿÅÆÈÿŽŽÿ³µ¶ÿâäæÿÜÞàÿÛÝßÿÝßáÿÉÊÌÿ¥§¨ÿ‡‡‡ÿ   ÿxxxÿ]]]ÿ^^_ÿÃÄËÿ2)qÿ Šÿ#œÿ$dÿÿÿ!8ÿ+!qÿŠÿ³ÿŽÿ0)_ÿWYUÿKLMÿ¯±²ÿxxyÿDDEÿ99:*åçéåçéõåçéÿãåçÿâäæÿâäæÿàâäÿäæèÿŒŒÿMMMÿdddÿ‚‚ÿÔÖ×ÿÜÞàÿÛÝßÿÚÜÞÿÛÝßÿÌÎÐÿƒ„…ÿ€€€ÿ|||ÿÇÉÌÿmg”ÿ uÿ¸ÿ¸ÿ‡ÿÿ ÿBARÿŠ…­ÿQIŒÿrÿ kÿ=9^ÿ\][ÿFGFÿŠŒÿœžÿPQQÿ;<ÿYXdÿA>Oÿ ÿÿ}}ÿghiÿDEFÿÈÊÌÿƒ„…ÿVWXIæèêèêì:çéëùçéëÿæèêÿåçéÿäæèÿãåçÿßáãÿÃÅÆÿŠ‹Œÿ¯°²ÿ???ÿlllÿyzzÿÉËÍÿßáãÿÛÝßÿÛÝßÿÆÈÊÿ—–Ÿÿ¶´Ëÿ¤¡¿ÿwqžÿJGZÿFFFÿ===ÿ444ÿ)))ÿ ÿÿ ÿÿcccÿnopÿQRRÿÅÇÈÿ™›œÿuww&èêìèêì$èêìåçéëÿæèêÿåçéÿäæèÿãåçÿäæèÿÝßáÿ¡¢¤ÿÿwwwÿpppÿYXXÿž ¡ÿàâäÿÜÞàÿÕרÿ«¬¬ÿffkÿ{y„ÿddhÿ`a_ÿWWWÿMMMÿDDDÿ;;;ÿ111ÿ&&(ÿ5ÿPÿE@cÿqqrÿVWWÿÑÓÕÿ¯°²ÔŽ‘YZZèêìéëíèêì®èêìÿçéëÿæèêÿåçéÿåçéÿäæèÿçéëÿÆÈÊÿ¢¤¥ÿ€ÿ[\[ÿyy{ÿßáâÿÝßàÿÝßáÿËÌÍÿlllÿ‚‚ÿ||zÿqrkÿhi`ÿ``]ÿTTTÿKKKÿ@@Aÿ Iÿˆÿ³ÿ«ÿWSsÿqrrÿרÚÿÁÃÅ‹xvzéëíêìîéëíféëíÿèêìÿçéëÿæèêÿäæèÿäæèÿäæèÿßáãÿÇÈÊÿ ¡£ÿÈÊËÿàâäÿßàâÿÞàâÿâããÿ|}~ÿ‡‡‡ÿfb|ÿ(€ÿ*™ÿNHrÿghbÿ[[ZÿNNRÿ hÿ‹ÿÁÿ£ÿ1'oÿ ¡¥ÿÕרïËÍÎ$éëíéëíéëíÀèêìÿçéëÿçéëÿåçéÿäæèÿäæèÿãåçÿâäæÿáãåÿàâäÿßáãÿßàâÿððñÿ¤¥¤ÿbaiÿ jÿ¡ÿ®ÿ›ÿ\YnÿmmkÿZYgÿy¦ÿ1%~ÿˆÿ}ÿ<4wÿÎÏÓÿÓÕ×`ÏÑÓéëíéëí`éëíÑèêìÿçéëÿæèêÿåçéÿåçéÿäæèÿâäæÿáãåÿáãåÿßáãÿåæèÿêëèÿSM}ÿnÿ¥ÿ¸ÿ‚ÿMFxÿ}~|ÿssuÿŸœ¸ÿš–·ÿbZ‘ÿ.#qÿ’­ÿÔÖØ’ÓÕ×éëíéëíéëíkéëíÞèêìÿçéëÿæèêÿåçéÿãåçÿãåçÿâäæÿáãåÿàâäÿñóñÿ”³ÿke™ÿ2%†ÿ yÿlÿ[Vvÿ~ÿnnnÿtt|ÿ¥¤¶ÿ”‘­ÿ Ÿ³ÿÐÑÖ™âåäÃÅÇÕ×ÙéëíéëíéëíéëíYèêìÛçéëÿæèêÿæèêÿäæèÿäæèÿãåçÿâäæÿäæçÿ¿¿Ðÿ­ªÅÿ‰®ÿg`•ÿ5-nÿkllÿklmÿtuvÿ±²³ÿÆÇÈÿÅÇÊÿÖØÛyÿÿùÕ×Ùéëíéëíèêì:èêì§çéëãæèêðåçéýäæèÿãåçÿâäæÿäæçÿËËØÿ³°Éÿ«©ÃÿÛÛÝÿÖ××ÿåååÿþÿÿýññòíßàâ¸âäæ#ØÚÜØÚÜçéë çéë@æèênåçé•åçé´äæèÌâäæÝäæççåççéçéèãçêëÕìíî¾ìíî›ãååmÖØÚ,ÚÜÞçéëêìîåçé äæèãåçâäæâäæáãåÞàâÛÜßËÌÏÜÞàÿÿÿÿÿÿÿøÿÿÿÿÿÿÿøÿÿÿÿÿÿÿøÿÿÿÿÿÿÿøÿÿÿÿÿÿÿøÿÿÿÿÿÿÿøÿÿóÿÿÿÿøÿÿ€?ÿÿÿøÿþÿÿÿøÿüÿÿÿøÿøÿÿÿøÿøÿÿÿøÿðÿÿÿøÿðÿÿÿøÿðÿÿÿøÿàÿÿÿøÿàÿÿÿøÿàÿÿÿøÿàÿÿøÿà?ÿÿøÿàÿÿøÿðð?øÿðøÿðøÿøøÿøøÿüøÿþøÿþøÿÿøÿÿ€øÿÿÀøÿÿàøÿÿðøÿÿøøÿÿþøÿÿÿøÿÿÿÀøÿÿÿðøÿÿÿü?øÿÿÿÿøÿÿÿÿðÿøÿÿÿÿÿÿÿøÿÿÿÿÿÿÿøÿÿÿÿÿÿÿøÿÿÿÿÿÿÿøÿÿÿÿÿÿÿøÿÿÿÿÿÿÿøÿÿÿÿÿÿÿøÿÿÿÿÿÿÿøÿÿÿÿÿÿÿøÿÿÿÿÿÿÿøÿÿÿÿÿÿÿøÿÿÿÿÿÿÿøÿÿÿÿÿÿÿøÿÿÿÿÿÿÿøÿÿÿÿÿÿÿøantimicro-2.23/src/images/antimicro.png000066400000000000000000000067051300750276700201730ustar00rootroot00000000000000‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs  šœtIMEÞh‘°AiTXtCommentCreated with GIMPd.e )IDAThÞí™kp\åyÇ眽i%Y²-˲.–/’|ÃÁ؆€ Ø0ñpIÝpïP¸”ò¡· ¡m2ÌdÚ¡i0¤Ò~JM¡…NSéJJ` 6¶¥]Ù²…î²´ò^´÷ûÙ=»çœ÷í[CB ™ú™93çÛùý÷yöyþïóŸã7:” ù±t2®˜¦Y+¥¬‘Rº¤” H)…mÛ¦mÙF6›-\¶ùrûs# ›õWH)¿ ¥\tJ)[„óUõ¢(ª¢ªUM!¯iÎp²l”Oè…Â[=«×¾÷™ HÆ£[€G¤”WK)ëÏ<ª”)%Šª’ Ï’ G©V Z7n j™Ì›×@këQȲÙLÚçph·¶/=ù© H%b àn“Rþ¥”²KJ €€÷ÃÇÆ&ÐibÓfGÆë?ŠØz PSSÃ5×\âE‹P‘ÌŸ?ÿÛKW­yÒ­(âÜï:~Mð‹€»€G¥”Ëç@¥”‚—RRßÐ@p`ˆÈð©ý‡)LL ïš½~?ÑH”M›7!äéÿB"‘äð‘^<55X^éULuµQô8ѳ9ŠÅ"…b=›ei¡J*h"×^FÄ(qùæÍž\.[mYÔòæwJÇ'h‹]RÊ·¥”­ç–†¢(T*8H2•d6§R©`[‚žUÝ¨Š‚’r¥Ât €¬VÑÊÒ‰eÛÂ(•)•J”ËeÊå3ïu.’ ]Ñ+,¼r K[ ‡Ã˜f•T*}ÓâÖæ'¤ã—íéRÊ·×¹ð–e …8tè0=ÝÝüã³ÿÄúõë™7¯žÇýš››1M€|.G!ždçïÜB1•fÚ°øÙð i…×uýì{Ø28*Jì\¹!lLÓ¤P,OÄ×EfgüRâÑÈuRÊý(›P8̉ã'ÌÌÍæhlläÖ[¾Bkk+—_¾UQÎÂÏ•˜L¥™Iç™9x„èÀ ZY'ß݆^©/è\²„žK7ˆDÙß߇†B{k+ñDœb¡€CÓˆÅâÌfVãŽ_¿ø±¢ñýðš¦røp/£ccäryò…†aкd Ý=ݸ].lÛFH‰Óé¤\*ãö¸©««#56ÉäÛGXL2pS¥?™"o[´4ÎçïßI“·Žðè85lÙH4£Z­ÐÐÐ@¡X$“Ng~l͆›¥”GïûÛ£UU995Í»‡³xñb–.íàÎ;n§Æã9[VŠ¢Ëåxý'ÿiÙX–Å-;¾LMmñà)–Òpú;Š X,’)—¸¢«R9|ÿù‘7°°Z¢ÐÖB±ËI"ç†í_bz:Àl4J©\ÊdŠFBµÀëÀŠóõs!$ 8œ®¹ú·¸ù¦Q)%ªª’J¥|o_ÿ1ZÛÚˆF£ƒA|>?·=pÇû(f›Á5¯êäóylÃÔù¸Üö X} Fó|°l¶oßÎñリ•êÁP(qÞ H)w[Î7ˆ@"¤ µ­•»î¸!†a i†ap´ÿ†YÅ4-,ËbïÞ½ÔÕÕQ­V™œœdiW«v=ÈÛ¯ýO­áõpC¥Še[hF•ìO±'5HjÑ0—·‘ŒÅ¹ãöÛC„ÃaªÕÊ”@¤Î›HèTðš”RùùT=ãû‰Þ7¼æÊ+³ÿÛ4.X€¢( Ž9B}}=­­­ ³zõ*¶^{-­­­ªƦ§ñÔxÐ4—ÛVãÁho&_©¬óp|ÃJ†’q~÷Î;éhoãø‰ÌÌÐuýß-Û~9‰È¹ÑppfpÝ\-륺^´, õu¸\.E9kÔ Ãॗ_áÒK7 ™œœDÓ4r¹™L†±±16lØÀSO~\.‹”§;Ò»‡ñÆÿƒËåÄÄé,[Ф¨q¢²ó¾¯R?o‡á½Á÷ˆÅ£éj¥úeŸ¿ÿȇìtèÔÌv{¥„L&K2fdd„R©„eY†A,cÙ²N6\úÖ­]‹eYøýýœœ ¥ä¥—^¢¦¦†ÆÆF ÃÀårñÐ>ȦI§Ó”Ëeò…<Åba òù#£cär9¤”¸Ýnêëëéììdù²Nâñ8£ãLNLÅ0 ãqŸÏÿWçu£RŠ¿"³³ °bÅ ššš%›ÍòÜsϱjÕ*–-[Æ×¿ñMvﯹä’u´´,æ©§¿ÏèØù|€7òío}‹î®•(*ŒljÅb$“Ir¹•J·ÛÍ ¨­«£aÞ<¼µ^t½Äƒï‹ÅˆÆbär9LÓüüœ Lo¥»¨8~‚p8LGG ±gÏyäî½÷^\.½½½<¹û)þáïÿŽææfvÞ?ç;¸œN¾ùØc<øPÈçH&SLMO133Cdv–L:ƒ®ë¢R­aÛrî€ãrº4·Û­zk½¸œ.*• º®£—tY­še)Å7ªeûy"› L}MU”g|ýÇ”¡¡!¤”˜¦ÉŽ;¦»»›öövÂá0{÷îåÙgŸE×u¾ÿôn®ºòJ\.N—MsP­Ä¢QffN144ÄÔô4±D‚r©³-ë˜m‹Ÿ !Þ1«ÖdµZ-×Ôx«íKªªÜ§ªêrMÓ¿ä|Ó˜št—–J%ejjê¬éèè cš&µµµ¼òÊ+¼øâ‹ „ÀãñðÚk¯³åª«0Œ †QAJA>_`tl”ãLMM“Édl˲þFHñþ>ß1@žÃ1<»yó¦R,·-Û«(Ò‚ˆÏïO}œ[pœéûEÊE]'“Épã7²dÉE¡½½úúzžyæÀéÔ)§“7>>N._ ¾®!$Å¢ÎÈè(GûûŸœ¤P(¤,ÓºIØÂßì¨ü8¿¿¿ }‹¯žà”R.ªš^¯—»ï¾›ÎÎNòùŸ—ËÅã?þá¡§@*™E¡R5˜ššbpp“SSò…ãU£Úéóû}¿þW¹ ¨RJ§ÛåDJbbb‚½{÷rðàAV®\ɶmÛØ¾};×_=ûöíCQlÛfqsói{aÛD£QFFG™žž&_(¼kYÖo÷;ªš{§¹ ضmë ÔÕÕòüóÏóꫯ"„ ±±‘ÉÉIöìÙCKK »ví¢¶¶–ÚÚZšƒÅÍÍ4-jB׋LMMÈd³I˲öùýÙO{q6' "¥ !èîZIOO^¯—J¥‚Ûí`÷îÝ £ë: , T*ÑÕÝźuëðz½ÄâqÑh èüKooßñ ±®tt¯ZS>&„øÊŠåËèèh'•Nóöþý¨ªŠÓéDÁŽ;Èçóäóy–/[ÆÖ­×²qãeå2ÁSAB¡E½ˆe™ß½PûÖ³[ !Ä›RÊ,À›7ÓÒÜL¥R!‰`š&¶m …0M“ë¶måæ›obÓÆËhkk#‘H25=M2™Â2­Ùþþ£© %àì$^½ö’ƒ#Cƒ3@css3·Ýz 55B¡³³Q„45-¤¹¹UU¹òÊ/²víZrÙ,cããƒAJ% ³rãý/dšæRÊišƒùóçóÕ{îaâäIB¡º®ãp8hjjbõêUhšF<g||‚‘ÑQÉ$–müà3½8ðÎþ¸Çãñ j𦡩*Šªž=.òyf£1““ƒArÙ¶m#åæ>¿¿ü™d Oü‘^ÒÛ”mN— MSq84EEاϯ±xœH$B$!‘LR*•°m»(¥|Øwá?r½þçö§ ¥”?–RnÅ¡i*ªªbÛÅâi»‘Îd( ˜U!Dø}ŸßÿŸ«+¦Ûo»õQ˲I ©ÙöéåR¥bP= >¼¥(ʽ}}'?—wd×^su“ªi+¥ëmÛ^!¤pÛ¶¶¦|~ÿäūƋq1.Æÿßø_~¢Få@sŸIEND®B`‚antimicro-2.23/src/images/antimicro_trayicon.png000066400000000000000000000067051300750276700221030ustar00rootroot00000000000000‰PNG  IHDR00Wù‡bKGDÿÿÿ ½§“ pHYs  šœtIMEÞ!NH€íiTXtCommentCreated with GIMPd.e )IDAThÞí™kp\åyÇ眽i%Y²-˲.–/’|ÃÁ؆€ Ø0ñpIÝpïP¸”ò¡· ¡m2ÌdÚ¡i0¤Ò~JM¡…NSéJJ` 6¶¥]Ù²…î²´ò^´÷ûÙ=»çœ÷í[CB ™ú™93çÛùý÷yöyþïóŸã7:” ù±t2®˜¦Y+¥¬‘Rº¤” H)…mÛ¦mÙF6›-\¶ùrûs# ›õWH)¿ ¥\tJ)[„óUõ¢(ª¢ªUM!¯iÎp²l”Oè…Â[=«×¾÷™ HÆ£[€G¤”WK)ëÏ<ª”)%Šª’ Ï’ G©V Z7n j™Ì›×@këQȲÙLÚçph·¶/=ù© H%b àn“Rþ¥”²KJ €€÷ÃÇÆ&ÐibÓfGÆë?ŠØz PSSÃ5×\âE‹P‘ÌŸ?ÿÛKW­yÒ­(âÜï:~Mð‹€»€G¥”Ëç@¥”‚—RRßÐ@p`ˆÈð©ý‡)LL ïš½~?ÑH”M›7!äéÿB"‘äð‘^<55X^éULuµQô8ѳ9ŠÅ"…b=›ei¡J*h"×^FÄ(qùæÍž\.[mYÔòæwJÇ'h‹]RÊ·¥”­ç–†¢(T*8H2•d6§R©`[‚žUÝ¨Š‚’r¥Ât €¬VÑÊÒ‰eÛÂ(•)•J”ËeÊå3ïu.’ ]Ñ+,¼r K[ ‡Ã˜f•T*}ÓâÖæ'¤ã—íéRÊ·×¹ð–e …8tè0=ÝÝüã³ÿÄúõë™7¯žÇýš››1M€|.G!ždçïÜB1•fÚ°øÙð i…×uýì{Ø28*Jì\¹!lLÓ¤P,OÄ×EfgüRâÑÈuRÊý(›P8̉ã'ÌÌÍæhlläÖ[¾Bkk+—_¾UQÎÂÏ•˜L¥™Iç™9x„èÀ ZY'ß݆^©/è\²„žK7ˆDÙß߇†B{k+ñDœb¡€CÓˆÅâÌfVãŽ_¿ø±¢ñýðš¦røp/£ccäryò…†aкd Ý=ݸ].lÛFH‰Óé¤\*ãö¸©««#56ÉäÛGXL2pS¥?™"o[´4ÎçïßI“·Žðè85lÙH4£Z­ÐÐÐ@¡X$“Ng~l͆›¥”GïûÛ£UU995Í»‡³xñb–.íàÎ;n§Æã9[VŠ¢Ëåxý'ÿiÙX–Å-;¾LMmñà)–Òpú;Š X,’)—¸¢«R9|ÿù‘7°°Z¢ÐÖB±ËI"ç†í_bz:Àl4J©\ÊdŠFBµÀëÀŠóõs!$ 8œ®¹ú·¸ù¦Q)%ªª’J¥|o_ÿ1ZÛÚˆF£ƒA|>?·=pÇû(f›Á5¯êäóylÃÔù¸Üö X} Fó|°l¶oßÎñリ•êÁP(qÞ H)w[Î7ˆ@"¤ µ­•»î¸!†a i†ap´ÿ†YÅ4-,ËbïÞ½ÔÕÕQ­V™œœdiW«v=ÈÛ¯ýO­áõpC¥Še[hF•ìO±'5HjÑ0—·‘ŒÅ¹ãöÛC„ÃaªÕÊ”@¤Î›HèTðš”RùùT=ãû‰Þ7¼æÊ+³ÿÛ4.X€¢( Ž9B}}=­­­ ³zõ*¶^{-­­­ªƦ§ñÔxÐ4—ÛVãÁho&_©¬óp|ÃJ†’q~÷Î;éhoãø‰ÌÌÐuýß-Û~9‰È¹ÑppfpÝ\-륺^´, õu¸\.E9kÔ Ãॗ_áÒK7 ™œœDÓ4r¹™L†±±16lØÀSO~\.‹”§;Ò»‡ñÆÿƒËåÄÄé,[Ф¨q¢²ó¾¯R?o‡á½Á÷ˆÅ£éj¥úeŸ¿ÿȇìtèÔÌv{¥„L&K2fdd„R©„eY†A,cÙ²N6\úÖ­]‹eYøýýœœ ¥ä¥—^¢¦¦†ÆÆF ÃÀårñÐ>ȦI§Ó”Ëeò…<Åba òù#£cär9¤”¸Ýnêëëéììdù²Nâñ8£ãLNLÅ0 ãqŸÏÿWçu£RŠ¿"³³ °bÅ ššš%›ÍòÜsϱjÕ*–-[Æ×¿ñMvﯹä’u´´,æ©§¿ÏèØù|€7òío}‹î®•(*ŒljÅb$“Ir¹•J·ÛÍ ¨­«£aÞ<¼µ^t½Äƒï‹ÅˆÆbär9LÓüüœ Lo¥»¨8~‚p8LGG ±gÏyäî½÷^\.½½½<¹û)þáïÿŽææfvÞ?ç;¸œN¾ùØc<øPÈçH&SLMO133Cdv–L:ƒ®ë¢R­aÛrî€ãrº4·Û­zk½¸œ.*• º®£—tY­še)Å7ªeûy"› L}MU”g|ýÇ”¡¡!¤”˜¦ÉŽ;¦»»›öövÂá0{÷îåÙgŸE×u¾ÿôn®ºòJ\.N—MsP­Ä¢QffN144ÄÔô4±D‚r©³-ë˜m‹Ÿ !Þ1«ÖdµZ-×Ôx«íKªªÜ§ªêrMÓ¿ä|Ó˜št—–J%ejjê¬éèè cš&µµµ¼òÊ+¼øâ‹ „ÀãñðÚk¯³åª«0Œ †QAJA>_`tl”ãLMM“Édl˲þFHñþ>ß1@žÃ1<»yó¦R,·-Û«(Ò‚ˆÏïO}œ[pœéûEÊE]'“Épã7²dÉE¡½½úúzžyæÀéÔ)§“7>>N._ ¾®!$Å¢ÎÈè(GûûŸœ¤P(¤,ÓºIØÂßì¨ü8¿¿¿ }‹¯žà”R.ªš^¯—»ï¾›ÎÎNòùŸ—ËÅã?þá¡§@*™E¡R5˜ššbpp“SSò…ãU£Úéóû}¿þW¹ ¨RJ§ÛåDJbbb‚½{÷rðàAV®\ɶmÛØ¾};×_=ûöíCQlÛfqsói{aÛD£QFFG™žž&_(¼kYÖo÷;ªš{§¹ ضmë ÔÕÕòüóÏóꫯ"„ ±±‘ÉÉIöìÙCKK »ví¢¶¶–ÚÚZšƒÅÍÍ4-jB׋LMMÈd³I˲öùýÙO{q6' "¥ !èîZIOO^¯—J¥‚Ûí`÷îÝ £ë: , T*ÑÕÝźuëðz½ÄâqÑh èüKooßñ ±®tt¯ZS>&„øÊŠåËèèh'•Nóöþý¨ªŠÓéDÁŽ;Èçóäóy–/[ÆÖ­×²qãeå2ÁSAB¡E½ˆe™ß½PûÖ³[ !Ä›RÊ,À›7ÓÒÜL¥R!‰`š&¶m …0M“ë¶måæ›obÓÆËhkk#‘H25=M2™Â2­Ùþþ£© %àì$^½ö’ƒ#Cƒ3@css3·Ýz 55B¡³³Q„45-¤¹¹UU¹òÊ/²víZrÙ,cããƒAJ% ³rãý/dšæRÊišƒùóçóÕ{îaâäIB¡º®ãp8hjjbõêUhšF<g||‚‘ÑQÉ$–müà3½8ðÎþ¸Çãñ j𦡩*Šªž=.òyf£1““ƒArÙ¶m#åæ>¿¿ü™d Oü‘^ÒÛ”mN— MSq84EEاϯ±xœH$B$!‘LR*•°m»(¥|Øwá?r½þçö§ ¥”?–RnÅ¡i*ªªbÛÅâi»‘Îd( ˜U!Dø}ŸßÿŸ«+¦Ûo»õQ˲I ©ÙöéåR¥bP= >¼¥(ʽ}}'?—wd×^su“ªi+¥ëmÛ^!¤pÛ¶¶¦|~ÿäūƋq1.Æÿßø_~¢Få@sŸIEND®B`‚antimicro-2.23/src/images/axis.png000066400000000000000000000034161300750276700171460ustar00rootroot00000000000000‰PNG  IHDRV“gbKGDÿÿÿ ½§“ pHYs  šœtIMEÞH4 }›IDATHÇÍ–klW€¿{gvv½ñ3ö:±IÚ8ë⤡QD^¦(Ä)U¥*PT )¥•ZåjÕ¨BBÐT¼þU ‘øÁ£ "U‰F &”¶6 !% 4Å%qµøÅzýصw×»3sïáÇ:Nƒ ©Š8Òü˜™£óÝó¸çøˆº‘BÏÈa¶¯¸€7þq¬npö‚ Ïõ1Vd<5Iæ<é¿çTï/ÇrÉ®©î̇¾6|HݵòóòDZ—O†ê³åLGÙ”˜ ¦É”Gúë8é søùÒ\ÐW˜ò³=™ÎUw6ª¡SSò ¿»üÂþBÛ3UJu¢¤‹#D´ÇÒX3®ö˜Íqq¸—³gÎ2ñ—yÄ(l ”ófíȹé‹ïzdð ;ÛãÅþï¥ Á\›oJÊs¢øRâÎeŸÂŸ.N¼Éð\?5ª‘u[H$k鉗Ÿÿ=‚X‘Ô@Ïd{ûŽf.½>qcO ô‡óý€ÆØrîhîd÷3»hߺœ®í³þ$£³CŒœ™æüK£(àKÏ}PüÊl((¥‚K¯Ox7ôôpê©tqxu),òɶÏñÃCˆx’›VÐ?ty'‹J)° Æ7Ì\.òÖáQ¼ˆÇ»ZèýÕ(¥Ù¥Ô@ª;“|OèÏ.>««Z÷åžÌYu÷ªÙ÷ü7I®_ɼ“ãÊäUÕ1Gãh­¬¬XÂÐ`CKè[ú§i ×°bí2Ž=J0ŠX9 ´z*Õ‘Eè·ÿü{·äǽßB㉠ûøÚ±/r¥ÐGÌ‹³¤&†§«pµ‡«ÁXC >-áû>AÙ²+ù÷¬y€ïZÏxf &ÕQW¯“ °wËA¾sf÷éÞé?ñÝm¯`Å¢•¦àNS]]M,#îVq¢hUñR¡*žj‹c4<”qcV,'qžÐ„4oôHv%N§º3@ pîJOýî9‰³õtvŒ¦Æ&ân5žS…«#8ÊÅÑ žŠÚp!Q  Ñ®Zü¯•æÂñQÚ¶}¨þ*Ë5Ö,¶i¥;Ì»€›V~‚úx1· ­\"Ê«x©®éˆXëZß„¶LclÙµ¢QŠÄÒe¤Ïæ:êªë<ÀWÆš‡€nbë}Dkäf7|}5J7‘ùu`¬I)¥V‹\ck¥žëÇÕ ¥tåÔÂY+‚ˆÁ"ˆXj½¥,‰Ô^g+4)ÏõÚ•±†å›â5gsqvEË-×)î>¾™¦X Q7ŽçĈ:1":†«´r±R6%ʦHÙ”)™Å0Ïí³­õ¾E[?ÿíOyö¹o1“™­<15§íP³¤Fo½§Îý­ô¢²1–PŒŒ ®l‰’ÉS ø¶„¿P½-#²ÐdïÞ½<½ÿ)¬6hq´£JœNLæâ±xßC{îcóg;Á¡o% 0%ʦ„oJ”Ã"óAžbP¨ œ'°eʦ„±!"‚¨J¤Þž~ƒïÚGck=å|Ø7tj*w]s@‘õœ(¹¹õk\¦ÿ`ü<0b°bðQ¸Ú­dS¤òÍ–0¶mþõ‚Œ¦¡¹€B¦œ½®á¯ÞÞÄ@Ï$É®„(­˜Ÿ§*aݽ­´¬oÀi´VDtE¥ D,‹±!váÝ/|)²£é |yçÓ¬ût 3CER=µrSÃggpf.Iv%”X©:—$¢j²¿€ãjb .±ÚJ)DÙJ~%DB 1Ö€ª¤QŒP‹lHvòÌÃû¹ec#ÚÑ2—.ˆ7xÇÆÎçÞ{ž&»)Yízã½96?ºŠ–Ûëñj5ާq"ú_Ú  F0Ösâ|¬q'O>úU«¨nöÈ^™èu"yÃÍ!Ù•ðˆëiÆÞÊqÛÝÍÜûøVrÅiÊEAЮF)јG[Ýí Œ÷ñ“G^#¹=A¬>Âtª œ˜¼ñæpuæµïh¾$"IíhÂRH>S&Ò±õVÖ=˜ µ¥•Ùù}GÒ¼ýÊÙÙib5‰×–ä'üÁþWÓÉÕÛš81ùþ·ÁÛîZ¶ÆZ{A)…·ÄÁ„B!S&?QÂ/…8®¦¦¹Š†[ãT'¢X#Ì JæÀåÓÓ{þ]÷?A­µ} ÿ´_0õNTwÔ¶DYÚ¯äV+Ä‚R)öÍ¥KÙ±7sË?R§þ« ÿÝ{ûŽæ:Ñžª¬– bE ž¬\üë9—åÿNþ ÄgªÆži3IEND®B`‚antimicro-2.23/src/images/button.png000066400000000000000000000035471300750276700175220ustar00rootroot00000000000000‰PNG  IHDRV“gbKGDÿÿÿ ½§“ pHYs  šœtIMEÞ4ÁyïiTXtCommentCreated with GIMPd.eËIDATHÇå–[ŒUW€¿uÙ—sf†`†ÛJ & 4´ÚXBIÚ ñRI›T|Ð'M«AMÚD_4Z-ú &åA#R[bej Z0Vä`€™3Ìå0çÌ™sæ\öÙ{¯µ|ØsaJlŸLÜ;ÿÛZëûïÿÿ/Ÿøo9çÔ/ ¯ìM\z OïkM0Òcxj„Ú¹2Í‘:­ñÆ€i¤‡Z¥øXílѼgèá¡#^N…Ç£Ûϯ^âî÷Ó¶1—kW˜Š§©4ªÌ\ŸfæZ…Ú¥ 2P˜zBÚL_(Ÿžxî]Azýeñ̆'ÝîJQ™çßÕK<´üC|lÍ#¤Êpµ~ƒ„”µý,ózøã…“<ä;4ÿ\AÖñVéäØÃ½¬¥“cî®Ð—!ÖäV®nÜoš•¸Ê¶e›‘SðÆðŸ8[>’4¡Z­R*Lb¬á[ùÄŽ}Œw–8ú⯩Õ@€Örµ1®8ybÔÝÕÒï]ù‰‹ŠL¶K|{ÓWùÔo¿@ÐòÄæýüaô$ãå ¤!pÆu4 u ‡¯`Ç£ßÿ8ÿøáiZ…:“'FÅ;Zzdä˜w»]Чã*Wë7øòÖ/²ÿàçxæÓOó—ÊߘjV¾Dz !Ä\’áŒÃ%Y¦Ï—ùÕ «ö¬£5Ö ofÊYë—N'úNèpóÖÁb4 À ›žeÇ7ç3O=Á+×_G EØ’S9´ÔH Hl‚õ,m?¦­Û,p%AoŽë/] óþ%è¼ÆD¡äAàë‹,Ý|üaµgÕ£©š{·ñµß}“§¶žW‹Ç ½€Ž°ƒœÊáI'¼yES—bœ!± MÑN"LÛ2s¥ÂðËWð{‚Y 'OŒ9wym×Ú½gn¼ÍÕúuZ…KM7§Šg´O.ÈÓ¡ó„*$§Bå“Ó9Bª_ú*$¯B/D’®=t½¯‡æh•Ó¸Œº`zûÜø¸ñXïN~ö÷Ãì{l/5;ƒøäU˜=,=¨O*|é‘S9r*À-5žÔ(­¾¤ÿ“ð—ÔoTçràÀ"h³0³Û&–¬þ —Î^à÷7ÞD ð• %4¾ô„ONåÉÉL_h©PB!‘RKt^³äK1­*€Ý‹)*6!u¼ZÀŽ&ÐrоÐ(¡QBâIOzx2»šØk̬R b¤Á9ȯëBå<¤’8‘uÇyh\i#•àÔ[§ÐJ#•D™3´Ð!<©ñ…‡C;²j¡Wã@€‚`ei€³v>mçÝkš)q#åöåq„óÜ쟺tQ™:—Õªu6{Ç™ þ²•×à˜¯íh”âbC{ª‰†„±cSŒsk°X›Ò4-š¦Elc—’Þ!s à {M7I-Fú f¡z¡5 Ò™!#ll°mƒ ‰3øÎº”ØÆ!0ΠeV©K‰LDÛ$$&Áá0΀g¹…ù{:çMÔ q`À´ÍnW‰Hg¢rDG^ë-ÔB´œ#‘ i%nÖ±m“¸Ìâ¶M¬±H_2Uœ‚PgÝÀ"÷âÜ!!*¯±±aâø06¶˜4%²m—›˜¦mÑ0-i“fÚ¤a4Ó‘iÓ¶1ÎÙ,ƱÁ¥Ž™×'éÙºœ°/Ä4ÒC‹cŠ;`ê *Ð$å6Í[ulbILBdÚ³°4eà-Ñ2‰M2`Û€û·ïãâÀ9ÂÕÔk”OO¼0ŸçQ¡î:Ö/ñpìTyMýZ›ò뺲¦--‹q™Ä.ɬ·1©3›Õ%Æb„eË’Mü`ÿw麷ÝåQ»\Ù—£‰ÅßÂe е±›Ú…2Óÿ*M´°-ƒIÍ|sOgÅXƒ³æ€Æ°µg3o¼6€ßã®í$*6­îÐï:Äûvõ»¹YY»0Åöw’¶R‚¾0«a—eÞ\ )²ý¨•òô‡Ÿä+{¾„5Ý[—ÓªS<^w]Wúvõ `%0.¤ÀKãf{v¬gÕgïcËý›±QÊX½ˆ!eEnkzV1X½ÉØÑ›¼}ô ]ýÝäîí$oÒ.6Wë%~ñÎ=é,“'F]ß®þ¿•žÄ¦–é– +_Ë}m ôB†‡(ü涜г¥—üú.„ƒh¢EñÍ1÷Ö»Ú{ûvõ?<«²) B‚‰-Î8t‡F…Y· –ç¨^œ¢9TÝôå åÓÉ{^¶{wö+)Ù‹„»…jà›…×Ú´šü¸4[ÿsßýÙ´ù¿„IEND®B`‚antimicro-2.23/src/images/controllermap.png000066400000000000000000001011071300750276700210570ustar00rootroot00000000000000‰PNG  IHDR,º5pŸbKGDÿÿÿ ½§“ pHYs  šœtIMEÞ#pœM IDATxÚì]wT×Û~f{céU, "H‰ý+ˆ±a¯DÅ؉cAÅ4Fc‰ "bA!Šb#j¬ ’¨ RƒJ—ËöùþHf>5Ê‚ ûœÃ9–evæÎ{Ÿûö—Àg ??¿1<o®¾¾¾9òmŸa0¬k×®LJJú#>>þ,A2h¡…†qöìY 8Ož<éegg§©T*?ø{eeeésæÌ±nÕª’““µ ù)¢¬¬Œ! W^¾|™T©TUú©¬¬$œœÈ£GžÕ® š„‡‡ 22’ôóó#I’$år9)•J?ø#‘HÈ&Mš$I2µ+ù ‚$I4mÚôffff•…‚úQ«Õdbb"ÉçóïhWR MbòäÉÅ™™™¤B¡¨–LJ¥RR&“‘£G&I’\«]ÉO Æ û!''‡¬¬¬¬¶`PÂQVVFúùùý¢]M-j‹xzzž‹‹‹S×T&¥R)I’$9hР„ÏaÍŸ“€ddd,111A5ÖÐØl6Μ9ã£ÝnZÔS§N…™™™cûö퉚Ê$( 4¨–°>!Ü¿¿o§N R©ju‚ о}{ínÓB#hÖ¬Y’$ku µZ ]]ÝÏb½>Â:tè¯oß¾¨­p$ cccíNÓB#`2™µ–I°°° åSKXŸ¢££ñÕW_A­V×úZFFFÚ¦…FÀb±4B2M›6%ÉÚ˜–ZÂj@())јÚü/a1´ÛM‹†¢a™™™»víªÐš„ŸœUšºÖ¿&¡Žv»iQ[p¹\—ËÅ‘#G>ùõúlËÕÕurmî qåÊ•ÅÚí¦EC!,ƒââb-a}*P(£4EXÈËËÓš„Z4Âú÷Pæææ:k ëÀƒ4v-äææjw›µ†¦|XjµîîîHJJRÊëõÙ–\.רIVVVFš˜˜ð´ÛM‹ÚB*•‚Á¨ý6T*•4h®]»¦5 ?ØÚÚjìZqqqÄ×_=O»Ý´¨-Š‹‹5BXÿÖÉ"**JKXŸtúõë§±‹Ý¿Û·o߀€£GjwžÕÂÆI‘HTš˜˜&S3Í îÝ»'MKKûd“±>iÂ"IR§[·n‡’]\\4b»wïÂÕÕuáæÍ›ÕAAAäôéÓLœ8q¹vjñ*:DÿyÙ²e§"øá288˜œ0a¬#‘H ©dO’$•lmmM=z”оF‚çÏŸ·™3gΩɓ'“7nÜ GŒA’$Yãjø7;6888ŽŽŽäêÕ«ÉÔÔT²¸¸˜Ü»w/9eʲOŸ>þ'Nœ°€«W¯j_ÆgŒo¿ý¶¯¯ïoS§N%#""ÔEEEdjj*™M:99‘Èž={jL6% éìì¬^¹r%Ù´iÓžÿÞƒöE4d¸ºº÷ë×ÌÊÊ"“’’Èääd²_¿~ ©TJ:88È/¾ø‚LII!“’’蟌Œ rܸqä­[· ´¤õy¢¨¨ˆiaaqhÑ¢Eÿ‘¤¤$255•üñÇI¤­­­FSWWW277—üã?H___ÜÜÜ>™µe}b²â6lذKC† Ayy9mÂiÒE’$Ýñ¡ÿþÿ‰<Êd2àÏ?ÿ48þ|¼««k;íþ|@’$ѱcÇ’èèh¡X,ÆÛZ+•JtéÒA ''G£ßonn&“ sssL™2)))…ÑÑÑZVÁÌ™3©?Z¿~ý¥Áƒ¿&$<ŽŽŽÉ4׎º¾¯¯ï[S%”J%œœœpîܹ¶þ§ÝÆŸtttv;vLÈçóñ®¾ìAÀØØ¥¥¥=L]\\ððáC$ ¡Pˆ€€=ww÷<033ÓÖÇÄÕ«WÈ5jÔÄœ9räú]ñx|øÐG¡P|БÎårÁår5~...¯åb‰D"bûöíÆVVVä­[·L´„õáêêŠÈçÍ›·¿K—.ÿÑv‚@||r¹ví¬¬¬>HB, ‡VÕ©‡6› ‹ƒµZÊÊJ :´Êù3J¥}ûöÅÕ«Wû§¤¤„yyy‘ƒ ê'NœÐîþF†K—.qÙlvGÒÙÙyú„ À`0ªO%“É`llŒÔÔT°X,°Ùl°ÙlZ98X,V•“K©Œw6›ýŸÿ+..ƦM›0xðà€ðððáqí]”0003gÎ$===?è â?ŽFƒ&“IOyy9âââpùòe$%%áÉ“'(//§·uëÖ011‘‘ºví gçŠáy<¤R)X,ª2ô’˜ &€$IH$’›>|¸6Á¯ 44“'OFxxøš &,}ôèëß’¢:6› …B¹\ŽÊÊJ´iÓ'OžÄßÿ‚‚””” 11%%%‰DhÑ¢š5kgggôïß\.B¡J¥ò?t þþûoôéÓ%%%ÿùþÒÒRìÙ³ß|óÍñC‡ÍzôèÑ®õë×7š÷Ðh6KÛ¶mñçŸbèСY+V¬0‹ÅÄûˆŠÒŠŽ9+++œ8ql6vvvÐÕÕ‹Å‚©©),,,`ff###0™Lú¤$I$IB­Vƒ$IÈd2””” ¸¸R©YYY(..ÆóçÏÑ¡CX[[Wû„e2™ä¹s爥K—ž?qâ„ïÞ½µ3®]»F¸¸¸âããÝ:wîÌìØ±#¤Riµ®ÃçóáïïÌÌLŒ?ººº022‚‰‰ ttth"L&“–AµZ µZ’’äææ"77YYY(++“ÉDRRþþûotîÜžžž°´´ÄòåËáããóÞÈ8ŸÏÇþýûñìٳ‚üµ„¥A4iÒ™™™pww/X·n>ŸÏÿÏX$6› ‚ ðôéSÄÅÅ¡¬¬Œ~©ÝºuÃ!ChL¥RA¥RÕª{I’`0øûï¿áíí_ýµF!j‚ `bb???˜ššf|ùå—úöíûXK]ºtÁ­[· }@@@ròäÉDM#Ή‰‰ÈÉɵµ5­µ×¤$‡$IšÔX¬ÿ7îÞ½‹'N //044Ä—_~‰:@$½•`utt„S§NyÆÅÅ…i Kƒ033#oܸñ𣛠¨ÕjÈår„……!00.\@çΡV««lªÕL&­[·ÆîÝ»qÿþ}Œ9²V$Èãñ°jÕ*œ>}zÆüùóøùùUj©£þpõêU¸ººœœœ¸l6[êïï''§Z‡ãr¹ˆˆˆ€¯¯/rrrššŠnݺÕÙsP>Y¥R‰#F !!çÏŸ‡\.ÿOÃ@ƒ¸¸8|óÍ7crrr|£pºÿïÿ+ýã?h¡a0055ÅO?ý„%K–@"‘`áÂ…(,,D»ví —Ë뜬 ²²³gÏFïÞ½¡¯¯Y³fáÖ­[066®qI¥R,[¶ .\ØÍår%íÛ·@’$WK%u’$ WWWŸððp„††",, ………5¾6•Ü´i ¯)•ÊàˆˆˆCZjÑÎ;Gôïߟ€Î;¯˜4iÒšÌÌLøúú¢¬¬¬VÚò‘#G P(0xð`tîÜ™vˆD",Z´ëÖ­«÷‚”lÕªU I\.>>>(**‹ÅÂÍ›7áéé¹ÀÆ/^––– nÈaƒ†‡‡œ6mZTXXJKKñòåK ]»v ¥;ˆj’¬(ŸÂ«!j¥R …BñšvG…“’’Ð¥KÿDg ÜÝÝ‘ýÖ°ru@iˆsçÎ…H$r‰‰‰qyþüùÁÞ½{ÏÈÉɹ¼gÏžd-åÔ=2qqqa=zôÅîÝ»±aÃÒØØR©T#å2ÅÅÅØ¼y3JKK_»žR©DóæÍÁáph-ˆr/Pü¨€Ehš"6¹\Xºt)¸\.222Ð¥KìÙ³ÆÆÆèÚµ+îÞ½»!%%eC“&MÉÉɬèøì ëàÁƒ„………ïO?ý´5$$Åo¿ýV8iÒ$޵µõˆiÓ¦ý®¥ ªÁÓÓÓ¥¤¤äøôéÓE§OŸæèèè`÷îÝ I’¨näï=æå;ó¦¤R)ŠŠŠÐ¦M$ ‡•J¹\‰D333XYYÁÑÑݺuƒ¥¥%,--!‰ü0Ò„»C&“ÁÌÌ =‚T*ÅСCѳgOÌš5 |>Ë–-S¯[·®ÁY` î†Nž<é÷àÁƒµfffHOO‡••¼¼¼jÜ“ êô*--ÅÁƒqýúu´iÓŽŽŽÈÊÊ‚D" è…7Ó(-Œrj^¾|íÛ·ÿO‹Û°°0ôèÑ£NjÅ(-ËåB"‘ &&ÐÑÑ…… žDFFÆ^¿~d¿~ý0uêTÞÀÇkèë™8ÑÑÑCx<ž1ò ²æ&''Ç2™Ì’)S¦$üûù·A¥éu9tèÐÎðþøã$ÉèÖ­ÜÝÝÍÌÌ:fff¢²²ŽŽŽèÔ©‚€¦êm2·oß>üðÃo=¸T*tuu_Ó¢Þ”·ÊÊJddd -- ©©©H$077‡®®.ÒÒÒð×_A,cÀ€4hÐkGÊ"¨N’Ëå"!!ÑÑѸví|||0tèÐ5Vj 눉‰àååݾ}{Œ7¬–6E…z  ‘’’ÄÅÅ!11J¥666pssC×®]üã8W*•õ';vŒ]×Û‹üWà)s•Ïç#??©©©HNN&322ˆ—/_‚ èëëÃÀÀFFFxúôixhhè¯G%ÌfÍšõËßÿÒÒRAWðù|‚ײþßµ!¨zK*üþV¶úWSËåP(J¥ô¡¤V«Áb± ¯¯–-[bÑ¢E¹\®œ$I¡ƒƒCë &ü˜ÂÂBÒݬ­­akk +++èééA&“A*•B¡P¼Fõýû÷# @cš6õ~Y,]›““ƒøøx\½zÙÙÙP*•°µµ…““ÌÌÌ`hhSSSèéé ˆ*úL&*• ÞÞÞÈÍÍ…®®î°£Gž\·náççGj ë_tïÞ}jNNÎÞÄÄÄÿdïVUŽuëV­Z…`ÕªU˜7oär945°ª8þ<¸\.­ö7tPÄÓPïõMí£1¬ç°jÕ*º/[}?›ÍF^^Ö¬Yƒ}ûöÁÃÃ055›Í®Ò:2™LDFFâÈ‘#8yò$C‡ÅÉ“'?oš8q¢lÉ’%{{û÷jTTdƒ œ>}û÷ïG‡`ff4kÖ tÙB}Õ+~8 0à£}¿;wîÄÖ­[5êˬV*•";;ÉÉÉHKKÕ+W“÷î9&“ …BA†††'Ožüýüùó}?K ËÁÁ †“&MzJJ¥Râm&I’tÝÞ¯¿þŠÜÜ\äççÃÙÙžžžP(ÉdÕ¶Ùë L&ÇG¯^½ªÔ~F‹OG…»»;¬­­ܽq8ðx<,[¶ zzzÐÕÕÅ„ ÀçóßI^\.ׯ_‡§§ç®gÏžÍú,5¬¾}û’§Nz§„2IÕE…††‚ÍfC*•Ö9½ïºUQ£)GèöíÛ…ù¢EÝ€ÏçcêÔ©8vìX­ä®®eˆª[6l¬­­±víZ‚wN¤NKK#§OŸ~ðúõë“>ƺ~´´‚ öœ?þ5Fg0`³Ù¸yó&ЬY3|óÍ7øùçŸÁçó¡R© “ÉjMVT¤ÏçÓ¾´´4üý÷ßÈÌÌD~~>JJJ@’$Øl6ôôô`dd„fÍšÁÆÆ¦¦¦P«Õ¨¨¨øÏKMKKCß¾}µdõ™ƒ tëÖö½½IB¡™™‰¤¤$äææ"// …J¥zzz066F“&M`eeE§6h2PD¹-¢¢¢PQQ‚‚L˜0Ý»w‡ŸŸ Åk>åV­Zýû÷ŸxýúõIÀĉ?m k÷îݘ1cöíÛGŽ?l6ùùùذaš7oŽ’’4mÚ'N„\.¯Uè™R} ??ÑÑѸqã¾øâ °Ùl¤¦¦¢¨¨FFFhÑ¢š4i}}}èèè€Á`@©T¢¼¼/_¾¤ÃÌjµvvvÈÏÏGrr2üüüТE ”––bÚ´iرcÇG÷]hññ ëâÅ‹;v,Øl6¢££(•J$&&B,£U«V033ƒ±±1UU*•(..F~~>^¼xììl@Ë–-¡§§GEagg‡~ýú¡]»vôïI¥ÒZ¹Httt€ððp:[¿{÷î´rQ^^Nzyy•GEE‰? “022rMzzúŠ6mÚÀßߣG†··7ôôôPVVV#á ^ôË—/QVV•J…S§NáìÙ³Ð××ÇW_}…=z eË–‰DH$J¥5>¥‚€ŽŽÊË˱cÇ\¸pÛ·oǦM›°eËTTThwígŽÌÌL0 $&&"((pssCeee­bŠ™L&ÒÓÓñðáCœ:u >„³³3&L˜KKK°X,A Ô(‘’ñ'N`ãÆØ»w/}˜‹D¢|&ÁÁÁðòòúä}X/®\¹ÒÄÙÙùµÕU&“––†Í›7#223gÎÄœ9s R©è|ž·©åš>MÕj5 ÜÜÜpâÄ …Â¥ghñi€Ífãúõë AXXX„^-%£¢éW¯^Å÷߇ƒõë×£sçÎàñx5ª¡öÏÎ;¡§§‡7báÂ…˜3gN½rH½–¿¿ÿ¥ÌÌL·… ¢FŒŸ’’‚ ÀÉÉ b±ÖÖÖèÞ½;ø|>íøX …ˆŠŠBBB:uê„îÝ»ÓI˜Z|¦ ÇÃÒ¥K1jÔ(ôèÑã£çS:ðoõÆàr¹ˆG«V­ðí·ß¢²² …¢ÊפW׬Y&“‰„„„‘Ç?9ÂÚ³gáíím6~üø¬ÂÂBœ8q¢Ê/’Çã!''W®\Á¥K—`llŒE‹AGG¥¥¥ ÒÁ-‹„ÇÃÃÃ-[¶¬–`hÑøÀáppùòeœ;wÁÁÁ(++kp‹Å‚®®.þøã8p666èÝ»7:tè@7¶ü˜L&îܹ[[[Œ5*"66öëúrÀ×ëjúùù‘3gÎÄØ±cqýúõ:¦U* Ý¢cùòåµò;},¹ténß¾9sæhÍÄOþþþX¹r%tuu•|–——ÃÁÁgΜ¡ƒQBqq1Š‹‹ñðáC¨Õê{&LèTä\Ÿ üv}õÕWt×ÃwA @*•ÂÓÓ[¶lÁ_ý…ððp,Z´•••.]@©T¢W¯^˜3gqäÈ‘:+ŠÖâãhUغu+Ö®] ==½F'Ÿ<033É'ðõ×_#** b±ø?…ýär9º‘Ý‘ :t¨Î«Î¿€êAJöèÑ*• þþþ8tèI …(**B`` tuuñüùs¬X±‚λúT ‰ðûï¿ãÚµk˜ª¿M‹Zlœ‹‰·oß###,X°•••uf¾ÙÕáÕï¡´vj¯ÕJƒa0`llŒÃ‡#!!*•ŠNkH$´É˜ÒÒRèé顼¼¡¡¡Ø¶m[ó «>^ì–-[ÈWmdê¢ÆõïßX·nÍúš/ÿêK~5¢Gu  R¼*Tç&“ 6›Mgþ¾Ù\­:(//Ç—_~ 777̘1ÎÎÎ2dx<ž6Ñ´•J¥Brr2BCC±ÿ~”––Öªú‚Jd&‚.5“J¥ôÄ&ª“ÉDee%òòò^;èôõõimèÕDO*@ÍØ|u Ô» V«‘››‹Þ½{£wïÞ‰Dˆ‰‰¥¥%‚ƒƒagg}}}0™L”••A__zzzàp8ˆwo×®]t£Ö°nß¾ÝsõêÕ×vìØ¥R ‹…¯¾ú FFF9r$FMÔ„‡zù, ÉÉÉHHH@LL ““™L…BèééÑõT …%%%(--Eaa!***›› 066F»víУG8;;ÃÆÆ‰¤F¦*Õ4ÐÛÛ¾¾¾hݺµÖ)ßÀÁd2ñèÑ#àðáÉD5:h(ùd³Ùxøð!îܹƒóçÏ#99, Í›7GÇŽajj úU«ÕtŠÎ«äøê=0™L0™Ldgg#%%ñññHMMEII ¬¬¬0|øpôìÙ­ZµByyy•ò³¨ïª¨¨@ff&üýýÁb±Hÿ?‡ÃA‹-ÜüÖ¨ K(NMM=UZZ ¡PˆÉ“'cÕªUhÛ¶-*** P(j<îˆÉdB €Ëåâþýû E^^œÁåréΠvvvhÙ²%ÝŸŠ$É×´ª75¦752ªÞŠ äææÒWe2lmm‘’’‚ââb,]º-[¶¤Ëzªò B¡!!!ˆÇÂ… !´ÚVôSåääàäÉ“°µµÅ˜1cÞ:¤ô}D§««‹»wïbûöí033C“&M’’}}}´k×î5b¢4JNß$Žª˜Ž ƒLýÀ_ý…¸¸8Èår4oÞ=—ËÅ’%KФI”••Ñþ©w‘U&çç燑#G¢yóæ ßÿ=}:V¬X‚ ððáC2===ÒÅÅet§NaýüóÏû 'wîÜþþþðöö†½½}}Pqqqðöö†™™vìØñVõ¸!@ ÀÏÏÍš5ÃêÕ««åXg³ÙèС"##UxüS$«ððpäççcÅŠÕþ0™LŒ9;wÆØ±cMp…j)îãã.—‹}ûöÁÀÀà÷¯££WWW„‡‡C(bãÆØ²eKmÈ:Ýé­Zµ:3žjå:pàÀ*ûi„B!är9f̘}}}˜ššÂÑѶ¶¶ I²Áû{X,JJJpþüy<~ü‘‘‘(((¨Òïòù|\¾|áááøá‡hG¯uSSS|÷ÝwhÑ¢† SSÓ*Ëe†;={öDŸ>}Àb±å»c³ÙP*•¸~ý:222ðüùsDFF¢¨¨è5“‘ê?ïííƒâôéÓ˜9s&áïï5kÖ4¢´ž;v...ðññÁÙ³g?XðÉårQ^^Ž3gÎ >>%%%˜>}:ÌÍÍk='îc¾øòòrlܸãÇÇ€ªlëëëãÛo¿…X,Ƙ1c «««%®º8µÿí•~êÔ)Ü¿3g΄­­mµ ”)'t\\6lØPe?fcŸÏGQQ6lØ;;;xxxÀÎÎŽŽä3 <}úÏŸ?‡““¹råJ"**ªN¸¥Î4¬M›6Uº¹¹ñ‚ƒƒ±råÊ÷ªÄÔ|A<}úÁÁÁtÑOiS<~ü!!!8xðàF†È¿5kÖ,¸¹¹¡S§NUîÉ­Å‡ß 3f ž>}Šâââj_§¢¢:uÂ7>ù¶B\.‡BG IDATLL > ¡PHËâ¨Q£päÈüüóÏäܹs­JKK3¾øâ‹†OX·oßn¾|ùò´N:1zöì ggç·~ŽÇãáöíÛX»v-<==ѦMðx¼OV‹ J¥»wïÆ°aÃЫW¯*ûF˜L&Š‹‹NGD ´¥>5|ÆÆÆX¾|9T*|||`aaQm¹322¨Q£0pà@´mÛö³y r¹'Nœ€ŽŽæÍ›‡ÊÊJˆD"xyyaÉ’%øë¯¿6N™2eQƒ×°f̘AìÞ½Û$999'((Ë–-ûO(A(((Àš5k`aa///”——ZÕú#<<EEEؾ};ŠŠŠªüû%%%ؽ{7òóó1zôh´k×î£Lgil‰DxöìÑ´iS 8öööÕŽZ³Ùlœ?§N‚§§'LLL>K—Íf#&&<À–-[PVV†¤¤$ܼyYYY $~ü‹/†±±1 GGGXYYAGGJ¥’.CúÔLn*?Ë墲²éééHJJÂ… ðèÑ#,X°¤“€kJâ …ýúõCDD„FKÇ>9Þ¼y3BBBPXXˆœ9sfqÏž=7nÞ¼™l°„edd´¦uëÖË=úÚµ“’’°iÓ&,^¼,Kë4~, wîÜÁõë׊ÂÂÂo\jnãóçÏñèÑ#<{ö ```@·t.,,¤‡¼|ù‰\., b±zzz‰D …àóùt|.— ‡C· y_ð€ÇãA(B$A$Ëå¾³úÿUPµt(**BAA²³³‘ŒŒ äççC&“ÁÔÔ­Zµ‚••Ý3M&“ÁÒÒöööhÙ²%‚¨U‡$IaÚ´i‹Åðññ¡§Z7$-‡ªwþ©T*•t)O}áÅ‹ˆŒŒÄ®]»…àà`ܸqƒ(**‚¾¾~Ã"¬ãÇcĈèÓ§¹gϺÓ!eîÝ»Ÿ­ X¡c±XðööÆÆѱcÇZõý~›‰DM¦ÆÍS?*•Š®¨¬¬DEEd2är9d2 Åk?¯©}3G‰*cþ™î"‘H ‘Hèº5JÃ{›ƒšZG“žžÄb1Äb1tuuaddº€žTRãè™L&²²²°téRÌœ9æææ F;¥r¾222››‹””äää@­VCOO-Z´€¹¹9Z¶lIwâ­NMMÅýû÷±fÍŒ5Š\²dIf¯^½š6H ë÷ßO kóÃ?йX¿ýöJJJеkWmD«Š¸xñ"±yóf­&úMœßÿ111˜>}zµMõº¾·»wïbîܹXºt)ÜÝÝ!“É^ë6Âb±PXXˆÉ“'cܸq˜4©þÆ€ ˜ššÂÍÍ­èÉ“'fY@6ðëÓ§ÂÏÏ$IB$aÁ‚ %«j¢oß¾?~ŸooïCV\.÷îÝC@@x<®\¹‚Þ½{Óþ4ª%Õ«K$áäÉ“puuŶmÛK[>u ###A.—cüøñúòóçÏkD9ÒÈEbbbˆîÝ»“+W®$}}}¡R©àëë‹aÆ¡yóæu¾@”™CU·S¨ÓæÕþV*•Šî…ÕÐMD‘H„Í›7CGGÔA EÝ‘Ann.¶o߃o¿ý–n+Ô  ±sçNÈårL:•ö;–——ã?þ@vv6 ÀårQPPƒ{{{tèÐr¹l6û÷ï‡ÆŒSç „±±1|}}ˆ'N`þüù ‡°àèÑ£¤ƒƒ 1yòdºèWÓN?Š€(Ÿˆ\.Gtt4Î;‡¼¼¼×>CmüW[n|ùå—pww§Ûyðx<ðùü66û˜Äehhwww„‡‡ÃÔÔT›é®AP ¹AAAˆÇæÍ›kÜM¤.MÀ+V ÿþptt“É„L&î]» ««‹7‚ÉdÒŽvJË*,,D¯^½°~ýzXZZ‚$IDEEÑÝêC[8q"D"îÞ½Û°ËÈȈÌÏÏG¿~ý°råÊ*Eƒª‡©TŠ={öàØ±cpuuÅ!Cð¿ÿýïµ® ”3òÍMO5@S*•P((..ƹsçpᤧ§cÚ´iðôô„R©l¹5I¯\¹ýû÷ÇâÅ‹QPP %®®¥¾¾>bccA EquumUL&gΜ‘‘ìííA¶mÛ777 0<ï½ÚAÈËËÃðáñoß>p8`ÅŠun¤¤$ðù|Œ=zðï¿ÿ~¶OŸ>äG%¬ÐÐPÂ××wð_ýuröìÙ˜={6ôõõ5¢Y1™LˆD"¬^½pttDÇŽ1dÈ:’U“‘ÜT@€ÊÝQ«Õ8vì’““ñôéSðx<,[¶ ,«Nût×DÛÒÕÕÅÍ›7‘’’‚´´4LŸ>]»v¥§ kç¾ý°£ˆîÛ··nÝ‚ƒƒd2&Mš„òòòé" I………†¯¯/ÝhoÅŠppp¨–oMGG“'O†˜L&bbb0|øð:n‹…•+WB(âÍT§¦a-Y²„¼pávìØA3km²¸¸/^Dpp0"##ñÅ_T«„¥¦‹ÅHOOÇĉaeeooo4mÚ”îÙ´¡Pˆ³gÏ"((C† ÁÈ‘#Áf³all ===:¡TÓáþ†¦-Q‡Õ½¬¬ ÅÅÅ4EGG#** ÖÖÖ˜;w.Z´h²²²âp8عs'ƃݻwcË–-5¶LLL0vìXÌ›7cÇŽÅ¥K—PVVVçÏ¡££ƒŽ;âï¿ÿ>iff6죖‘‘­¶ær¹8xð Nž<‰+W®Ô‰¬:Ž… "::††† VÈU*ž2}õš¯j(//‡D"Aaa! påÊܾ}=‚¹¹9† ‚áǃÅbA¡PÐI• ºººðððÀ¦M›¹\OOÏZ]óæÍ› I‘‘‘ðññ©·±døú믣._¾<ÜÍÍíã–““Ó¹­[·öµº“ÉDEEæÏŸ???ôìÙ³A”?P‚~øða„„„`ß¾}˜QW›ÍƒÁ€R©Dzz:^¼xââbÈd2…BèêêB&“¡°°ðµR‰DòZ€B ЦȂÃá€ÏçCGG‡î=N™æ”Ó÷U¢~ïUÒ¡´¡W}ŽoŽ®¢ˆŒº¦\.§“VÕj58¸\.tuuall SSSˆÅâ×J•{ ÒÙ³gAzôè   Õ:ñZ$¡U«Vðõõ…¹¹9Ú¶m[/ÏÂårqúôi¬\¹²V®…šDÛ¶mqùòej,¯‘Ò²©®õ ¥R‰~ýúÁÁÁõKX—.]”)SšìÝ»—Y“:+ƒeË–aüøñppph4#ÞTq¥R)fÍš…®]»bÆŒO–ÕâóÆèÑ£qñâE´mÛVcæ;—ËEpp0úöíûQ”.—‹^½z¨WÂêÝ»7F}¿¦ ’’téÒ¥Ñ Atæ¹——W½—jñy   ½{÷ÆÒ¥K5V×Èf³qüøqÔÔ2ÒÎ;‡/^¬ªÑ~«é—6Œ\¼xqµš5øûï¿×[üÛœ½švì³X,ܺu ‡ºuë>›ë|>\.Ïž=ÃÅ‹‘””D§P) ÆÆÆèÞ½;ºví ¹\ŽÊÊJm÷Žj˜Qøî»ï0bĈZ­I’ ƒ››ÛGµx<FŽèß¿²Î «_¿~»}}}} ˆênê'NÀÃÃ"‘¨N¢ <ÅÅÅ())D"¡ÇQDÅf³Áãñ ££CCC:ßGQ¬ÐÐPdggÃËËë“Ý”l6………HOOGpp0þüóO0 4iÒ:::t~•!•J‘““ƒ¢¢"XZZbòäÉèСš6mÚàâ6°X,têÔ µ’)•J…µk×ÂÇÇç£>—ËÅÉ“'±zõêj@£{÷îA»víò®®!“É0fÌܹsGã›™Á`@&“!66³fÍ‚D"H$Ç£ûIQ5„jµ2™ %%%P«Õ˜2e =°µ¶vý¿dѧOŸOrÔx< ­5WVVÖØ­SVV†Í›7çž;wάZÚfu>ܺukìß¿¿„Éd’Õ%;äååiD ©°û÷ïǦM›h’`³Ù044D³fÍ`ccssó×Ê4H’¤ý*l6r¹ÏŸ?GJJ ]¾ggg >ß}÷š7o^íbS•J…ÈÈHlذóæÍkÔ£   0zôhðxÔ9àmŸ—Éd¸rå RSS!Àd2qýúõj«ÓB¡ãÆÃÆ¥–•˜˜ˆ  uëÖôà×ÌÌL„……Ñ}Äj‹åË—#++ |>A ¸¸666X¿~=***Ýš1™Lèêê"00±±±(,,A´iemmiÓ¦¡eË–µníÂd2éqh …‚î6Êår!‰hó­ªàñxˆˆˆ@hh(ôõõéq|, R©´óx<˜˜˜€ÉdB¥R¡¬¬ nnn˜?~•ß›D"Ann.ÆGÔ aï´¶¶žU“ŽiÓ¦áÎ;tãê:éø|>æÎ‹³gÏBWW|>„H$¢O0ªupff&RSSQVVöšƒ’Éd‚Ëå¢yóæ°±±¡ûm‡ÃAJJ N:(•J8p666Õ"­Ÿþ]ºtitZ‹ÅBÿþýaccCûªX,V­Z¥1'9Õ·~Ïž=8{ö, è÷7{ölôîÝ»ÑDZ rrr°gÏܸqÆÆÆtõì¡ÜÏŸ?‡­­-¾üòKLš4I#ÅþÔw¼ú]Õžž–-[†ëׯÃÜÜœž›› °ÙlÐA™LF˜D"™™²³³1qâÄ*—Ù1™L̘1qqq_ñ@ã„Õ¼ys2""¢F*mHH¾ÿþû•°X,øøøàîÝ»t‹J f0())Ann.bbb “Éàè舮]»ÂÐÐîo ü“Ó"•JqïÞ=\¿~jµ:t€­­-Äb1­²¿)AAA‰D(--Ž{÷Þ;<ôm‚ôÕW_áðáÆ¬Øl6:v숎;Òk—••… .Ô‰ÖÃ`0pèÐ!œ={–6+îÞ½‹ .4Š’'‹…k×®aõêÕ°µµ}-…æ}ä¢V«Áf³±e˰X¬J¶‹-ÂóçÏé–B`±X¬D¡*>þúë/4oÞ9998þ|•-Š””DFFúLœ8qψ#4GXSŠŠŠBÚ¶m[#ºxñ"&NœXm›ÍƦM›’$aff†¾}ûÒDggg 6Œv6feeáÅ‹HIIA^^¤R)X,tuuÑ¢E X[[ÂîuuïÞ==zƒ Â_|ñV'fPP„B!òóóqïÞ½*£r8lÛ¶ C† i4Mäþøã„‡‡ƒÅbÁ` 33u:nŒ ¬_¿YYYP*•`±X(++Cpppƒögñx<¬Zµ IIIàr¹´æ ‘H——Gk§”/‹ÉdÂÔÔ”îO5¢¢¢468·ºfåo¿ý†½{÷ÒýÄRRRн{÷j¯{||<Œa``€-[¶TI;ضmÛ–½{÷.д†57>>~[MU¥RáÖ­[=ztµT|ª3âŠ+```ccc <G§NгgOTTTàðáË۵µ‡ÃžžLLL ‹Áb± V«QYY‰‚‚äååA"‘   IIIhÛ¶- €˜˜ܾ}æææèÚµëkéjµ¿üò ttt`nnŽsçÎU9›ýáÇP©T°°°Ðøæ#‚NÂÍÏϓɄ@ ‹Å¢8 E•5[333tìØÖÖÖ€¼¼<øûûÃÙٹΉC(¢GhÙ²%­Õ…††B$Uy-ø|>Øl6m½úþ¤R)är¹Æ– ‚@ll,é5ONN†­­-x<ÌÌÌþ#ïA ''R©)))hÙ²%T*JKK±ÿþzÕ´H’Dyy9ÆŒƒ¦M›B­V#33;v¬Ñõ$ ÒÒÒ ‘Hðûï¿Wy¯ïرaaaDUÌÙ¾¹-[¶`þüùظq#Ù£G ­B¡@\\†^-Ââr¹èÒ¥ ”J%ŠŠŠ0gÎÄÅÅáÙ³g˜3g’’’põêUèèè`ܸq022BEEE•û»yó&.\¸€Ž;¢S§N¸yó&’’’àîîNkE$I¢  ‘‘‘`0Xºt)F]åç>|8ÂÂÂ4zŠ’$‰+W® 66mÛ¶EÓ¦Mé±ó”o.==¥¥¥pssC»ví>¨á^¹r[·nEóæÍiuëÖ­õRFE’$ž?Žõë×¿Ö ùÈ‘#ï5K $ þüóOÄÆÆ¢²²’{Å`0è 899ÁÙÙY#• r¹½zõ‚³³3är9ÊÊÊèÍþ¡kSyh÷î݃¾¾>¸\.úõëW/ƒ!^•ÿ~øOŸ>AÈÎÎF§Njü® ž}:¼½½©YÌž=›>J}ÎÎ΋ÅBBBB•²†Y,Z·nK—.iìtW«Õ;v,222PZZúÁgDDD¼÷V®\I?I’pqqAMß{M •J1bÄX[[ƒÁ`àÁƒ¸xñâ{ï9##k׮Ž{÷Þ›ÖB‘—µµ5"""ª¬¹}h­är9¤R)j=g2™HHH€@ @bb"îÞ½[ou¨b±pttDQQŒaddT«kæææ¢¼¼!!!UNš‰Dprrº1iÒ¤îû÷ï?)Vå‚k×®]:eÊ”ZÙÉ2™¬Z›õåË—8sæ ]\{àÀ,X°IIIˆÇO?ýggç ‡Ã©Ó“$ ©TŠ;w‚Ífãûï¿ÇŠ+pñâEÚ4T©Tèׯ­J¯ZµªÊÏô¿ÿý3¦L™‚„„„’õl$IâñãÇøé§ŸÞy‚2™LÚÙ ü“ÖP² Mm" Ú)mii‰ìììw~¾¼¼œÞèR©ô½š MÎÊÊB\\âââjåhÏÌÌ„R©DNNÚ´iS£ƒS¥R¡M›6xüø1lllèŒÿú@hh(Z´hA?©©i­¯Éår!“ɪյD"‘`ß¾}Ý,--?¸™>HX«W¯F¯^½¬kÛ³*''§Ê*"AÈÌÌ„P(¤K–-[†cÇŽÁÖÖC† ykDïm*û©S§pìØ±*û”J%ìììàïï|õÕW§O=*IGGG­’ªÕjL˜0/_¾Ôˆ ]ºt §Nª¶I£R©pìØ1\¸pá­6›âââ×LÊ—U_P*•èÑ£­)q¹Ü÷’²ŸŸV¯^]­<7™L†Å‹#99¹Æ©TŠ¢¢"tíÚµVæ¥Z­Æ€胺¾Z„§§§ÓþOj¨ˆ&PYYY-_utèÐan­ kåÊ•œ/¿üÒ¢¶‰·nݪ² .‰àããC'.\¸¿üò ƇöíÛW¹Q"‘ÀÒÒ²Ú5T²ÜêÕ«qäÈÌ™3QQQôKøúë¯QTT‰DR% G­V£G(--­µß„Á` ??6665ºVYY²³³ßš.À`0^+‹111©·@¯ÂÌÌŒ~ÇTéÉÛދŶmÛªôÞDii)\\\j¬õ2™Lú°ÒD0B­V#77·^û©QQJ¹\^kóøÕu­ªo÷U888`çÎ?ך°ÜÝÝŸW7Yò]ŽçgÏžU™¡srr —Ë1nÜ8œ={ß}÷]µSÿõôôкukŒ5ªF×¥¥¥ð÷÷ÇO?ý„I“&áàÁƒþéEe—””TimŒ5ÒY• ˜ššÖª€ü]' õL¯~îcôMª¨¨xí{ßuÔÀÝš¢eË–ˆ­Ñ3R$¥É J}¯5EºT‰&®W^^ŽY³fUÛ<&Ivvvøõ×_»Ö˜°rrr¬òóóM¨ü’ÚÀÃçNªÒg³³³Ád2Áb±PXXˆöíÛ×xAÙlv­òŸÔj5¶oߎӧOÓ)*• ¦¦¦`08uêT•ÌŠ7Ãì5I’¨¨¨¨Õ3½k®¢Z­~­OY~~~½÷ýf0¸ÿ>í°U*•u2:L.—£¦²­P(Àáp4J2à½ãÓ4 {{{ÓµEyy9ÜÝÝkT¼®R©0aÂŒ3FyåÊ¢Ú„õàÁtéÒ¥iPPF4ƒqãÆáæÍ›U°ÔÔTp¹\Ì›7йsg|LH$ >Ïž=Å044ƒÁÀ¥K—>HXT2ž&ZͨÕjTTTÐ>µ· ý!˜šš¾5c].—ÃÀÀ€&Ö-[âܹsõ¾Þ7nÜ »jÃÐÐð¤Q›©Î/^¼@=jä,—Édïã•™™‰>}úÔÛ:{zzâÅ‹`±Xµ®` iiiøöÛokuÿôÓO·{õêEV›°œ1kÖ¬kšRy_¾|I'5VÅÏÂårgÿ IDAT±k×.|õÕW ¢+¥••LLL0|øpäååËåÒYà:e ‚ÀåË—¡«««‡êèÑ£áèèH|WõDf0ˆEûöíßé¤677§§ !11±^×955•®_€¢¢¢w†ÚU*æÏŸ_£5‹Åøõ×_kLvjµƒ ¢“s5q™šš¢}ûöõ¶ÖÅÅÅð÷÷“ÉDIIIŸƒ ¤¦¦â矮•‰§N‚\.ßX#“°6aß7¡T*1|øp,_¾üƒ C’$ºuë''§ÓR©T¢M›6(**Baa!]¯££óAÂ`0 ­U§Š7}Pû÷ïÇСC!‹?øý$IB,ãàÁƒ¸sçIþ6,X°?¦Ÿùüùó‹Åõ²ÆB¡[·n¥Ï………ðòòz¯¹‰ñãÇWù©µ˜8q"¾þúëZ™_ƒ†¥¥% ju1 ddd`Ë–-õÚ¡B­VÃÝÝyyyP*•Uö1¿é^HIIÁŠ+è‰Úà§Ÿ~BçΉ‰‰DµËËËë×ÁƒkÔ˜nÛ¶-.]ºô^¤Êìíí1lذÕóÛÖÖ7nÜ@ll,ÊÊÊ@’$¾üòË*™ÌOž†Šü Aà›o¾AQQM´r¹]»vŬY³>XSU­êòåËð÷÷‡ ýï<ÀÙ³g!”†]3=..—/_Fll,‚€®®.ôõõiŸ\ii)ÌÌÌйsgŒ7r¹¼VÚÕïU§©wOÂãp8(..‹Å‚P(DEEEÛWg=<< ªDX:::/cbb ë*‡$I>|M›6ýOV¬±±1úõëtëÖ^À²²2$&&Ö*'«&Ä à?§ÈéÓ§qéÒ%ôìÙ»wï~ïË»ÿ>öíÛ‡åË—£±AOO'N„L&£µƒÛ·oãÈ‘#°²²zgkê÷mƒÜÜ\|ÿý÷ø¿ö¾;*ª«ýzßé3ôŽ"¢/* ˆ BQ”ˆ5öˆ "ö±Ä^ƒ%¢ÆJìÆ^QD#Æ®€Š‚ Dzg†aæÎýþÈïÞ”"(˜Ùk±Lhs9sÎsžºwff&tuu™}ñìÙ3\¿~½Æ³§ "‘ …ïß¿G\\ÔÔÔÐ¥Kf½j£ÈD{f999‹ÅJ¥¸wïŠŠŠ ««‹Ž;‚ÅbASSZZZ_ýrÿƒùòåKìÞ½Û""""IÉ üð›ÃÃÃ[öë×O¯>]T‚ 0vìX<{ö¬¯5M R>~æñxؼy3†úÅú‚6lØ€­[·VøZnn.$ 8ðÉÃÊápŠ 64Ê“ŸŸ­[·¢U«VÈÊÊb8°nÝ:|ÿý÷8yò$ÔÕÕ•˜]?nhjjâÍ›7?~<¦OŸ™LÆ+…B¤¤$DEEÕ)gÕׂX,Fii)tttðÝwß¡cÇŽÉd(--­•1¦Õµ===1cÆ œ:u ·o߆\.‡P(„D"Á7pìØ1øùùaìØ±U¾' EÁÈȼ*=¬Áƒ›ýôÓOÉ_ª”=a„††ÂØØ˜!`ó÷÷GII‰RÙ™$IDEEÁÝÝý‹¬½{÷‚ %z‚ °nÝ:ØÚÚ~2ÇF®]»†„„„js\7Tp8\½z¿þú+,-- 6›ÂÂB ]»v ( l6Í›7‡¦¦&H’ÄëׯQXX>Ÿ””äææ2D†ô÷?|øÆ øqãí!«Ï¼’D"Á´iÓ §§[[[†&‡&i¤×‹^SŠ¢PXXˆû÷ïCOO!!!u6xÿ¥@Ó™÷êÕ‹ø¨Áºzõ*ÜÝÝ›ÆÄļûRa—šš „S§NA(‚ÍfcÖ¬YˆŠŠÂ²e˾ZÒ~].—«äZ¤¥¥}2!,“Éàåå…“'O6Jõ—ÊÖC ÀßßïÞ½ƒŽŽ30K3EÒ ï²²2&ŒæóùŒú ý9‹…ÒÒRFQfãÆ011ùbÄu|>W®\ÁªU«0aÂH¥Rp¹\dee¡  /_¾DII‰’çóù077‡®®.ôõõñæÍ$$$`ß¾}_eýs¢° 6àèÑ£J6JÉ*¹»»ãÔ©Sïêj²:())ÁÅ‹áî˜Èd2XYYáÞ½{ íÄ×Z0ÚÒ—¿íbbbСC‡Oö%©©©¡wïÞØºuë7a¬èõJ¥Ø¼y3„B!-Z„3gΠU«VÐÖÖV*ˆp8¥ýC+=Ó¡RRRš5k†?ÿü“É©ŒUEìÙ³±±±ðõõeŒÍн{wøúú~T&LCC{öìÁßÿ~ýúA[[ÞÞÞ8}út£Êk=^Q®°²š6mÚ§ÝØY³faýúõÐÖÖF›6m°k×®µÀ"‘“&M¡C‡`mmýÑÍâçç‡Ñ£G£Y³fµòËÿLywÿÃÏ}MÐûÉ“'HKKÃÇqùòef4£üs³ÙltîÜ={ö„‘‘Ú¶m MMÍÕÜÐPRR‚éÓ§ÃÓÓ2™ ±±±ÐÕÕÅðáÃÁår«4ðl6%%%øí·ßЭ[7dee¡OŸ>h×®]£¹ 8€¾}û.èÓ§Ïò¬=zPëׯÿ*zp3f Ž= >Ÿ~ø¡Álì´´4,Y²=ª”OJ(bΜ9hÑ¢¼¼¼ª(,,DNNÒÒÒP\\Œ²²2&´¢=—ˇÃP(„ ¡¯¯ÏèÄ}­ð™¦—‰D(++CAAãU©««CSS¥¥¥‹ÅFgðkB¡P G˜={6H’Äýû÷accww÷{ìZZZX¼x1\]];w~¶€ë—Ìß­Y³fîñãÇWW`’§_¥¥¥Ø¸q#Ž9‚ׯ_ãõë×ðòòª–ƒÏ‡ÃAll, ­­]á†#AAAðööƧú×hÏ£¨¨2™ qqq ––ƇáÇ3â°•yVôÇíÛ·±sçNœ>}ðóóc*q<LOçôØl6ã•••}õ„/½æ4í2Ýõ_þ=¤Û-8NÕ/}222™L†ôôttèÐ]ºt©Uz¡  S¦LŸŸ„BáW‘«-455qóæM*** ...=¬Y³fͳ··_QCŒŸkYóóó1lØ0ØÚÚb̘1_=aøöí[„††"..NinŒNF;;;cýúõ066®tƒ³ÙlF]7''#GŽ„½½=444^%…BQíÃQ¾«$I#-- 8uêV®\ ++«Fs›ÖµÐÔÔDdd$.\¸€øøx¢I“&hݺ5455!˜¾(’$!‹‘››‹ääd¤§§£°°;w†··7ìì쟟όÒÔø|>fÏž6mÚ@WWGÅÂ… ?ë5龦­[·â×_EÛ¶mÅûÈçóqùòerîܹœJ=¬µk×R·oßþê P…BMMM\¾|=zô@ë֭ѱcǯ–»QWWÇòåËÆ+Š¢ ¦¦†íÛ·ãúõëØ¸q#ôôô”6=gvõêU<~üfff˜1c¬­­Q\\Ì„MµŸ)O+Csr[[[£}ûöX°`öíÛ‡„„âããÑ®];\»v  ølIQZ¶l‰ÌÌÌFõžÊårdgg+U·” –†††@MM­N‡?÷—,Y‚¹sç2³K_Ú=g±X D@@ÜÜÜ–ÊwïÞÁßßݺuÆ *°,²Ùl¤¦¦"00!!!5jãÒÓ|SåCºY–æØ.--…\.gx·Ùl6x<„B!cÔ?d§¤sYR©”Qšæñx=z4йsg}3y$º,;;{÷îI’ ®®.Äb±Ru²ºCür¹\ɃnÙ²%C›ÂãñÀçóñæÍŒ1=zô€§§'ŒŒŒÀãñêä¢'b±˜aqpuuEVVV¬—L&ûh±¨¡¬Ï»’Áúý÷߃ZŒëââ‚7bÚ´iX½zu¹™Ê«×K—.…¥¥%‚ƒƒ™pÀÅÅöööX³f ÊÊÊ*«¢¢"üüóϸ|ù2Nž< ‚ *Í?p8ˆD"<|ø¸|ù2Þ½{@}}}hjj2ƒ§åU«544йsgxxxÀÅÅêêêH$Þ\úçþøãp¹\lß¾ðóókT=9•ÇãaéÒ¥ I6l€­­-ÞÑap]{ät!DWWgÏž…B¡@qq1üüüàêꊱcÇ~v I’000EQ077¯Sç¡}ûöÐÖÖn0IuŒ7]ÜJJJBëÖ­•sX«V­¢êz¿.ÀápŽ  :uªV»CYYnݺpvv®q8qâDtîÜ.\ÀÌ™3 www8;;Wª(£££ƒÀÀ@øúúÂËË«BþˆËåB[[»wïÆ¾}ûàææuuu°ÙlX[[£eË–àr¹ ( …BÉ*ï…ѲôÏž=CZZ444píÚ5ðù|„„„@CC£R1N.—‹7oÞ`÷îÝhݺ5\\\•·E455áç燑#GÂÑÑø\E§Ï…@ @||<þùç\¾|;v쨵*‡ÃÁ®]» ššŠaÆÕÉåB’$’““áééÙ¨ÞóäädJOOï…§§§ðAÒ}̘1T@@@ƒÝ¬7oÞÄÌ™3áää„¡C‡2ÞǧradÚ#ªóFq8>sæÌAQQlll6› ©T ’$«u°¹\.444púôiDFF"-- «V­‚‹‹ 3`ZÕÏûûûcÙ²e°µµeòd|>Ÿá¹5jlmm+•oâóùt¯ Ž=ŠôôtH$&WB÷ Ñ•+:é+ ££ƒÀËË ùùù•zjÙÙÙˆŽŽÆ£Gpúôi¤¤¤(­ A Ä¢E‹\QMM 7n„•• Ô¨Æw‚€\.Ç¡C‡Ð¤ItìØ±FÏÏårñóÏ?£¤¤ä³ØHiVÜ9sæ|šëúØÓ§OO ieccC2;·_¿~W¬XÑ¡1;ijj"""gΜÁÕ«W¡­­ {{{´lÙ&&&Ð×ׇÃadíI’d”SSS‡¤¤$˜››cÈ!6l¤Riµ¼1¡Pˆß~û AAA066f6#I’†ŽŽ*ä2„B!222påÊܸq?†T*…ŽŽ8 ¤R)S!¤½+z>Ïçƒ $‰üü|P…:ÀÑѽzõ‚™™Y/ŽËå"%%Û·oÇÀѯ_?¥¼––‚‚‚0nܸѤKoÔ•+WÂÛÛ]»vm´-<û÷ïGNNF]£|‹Åœ9s`jjŠï¿ÿ¾Æk °ÿ~ØÙÙ¡gÏžrý8Ý$ruu•0ËÜÜüá™3g:4– ‡o¬H$ÂÓ§O1oÞ<B*•2¥íò·-J 0nÜ8 6 ‰¤F›Íf#44 ,`†|Y,Þ¿ÁƒãúõëÈÈȨÐa››‹É“'ãíÛ·Ð××I’Ëå`³ÙÌëkii¡}ûö033ƒø|>Äb1ÒÓÓ‘˜˜ˆ„„”––2ÕOzl‡Íf3Ìaaa000`øåM{;yòd%¦T.—‹.]º`ÿþýÕ†­oøùùáüùó¾šI‡d÷ïßÇõë×1vìØµæp¹\DEEáéÓ§pqqa˜/ª:¥¥¥8xð úöíûÕu=?©©©8tèèĉÿß`uêÔ)nçÎ6µQmmhÆ‹®°Ñãå,Ë÷;U–/ª¶nÝŠ#F0ÃX¾|9Z´h®]»*yhB¡wïÞÅÌ™3™ÐN&“!;;:uBï޽ѤI†ª²açsW嫈ϟ?Ç™3gðêÕ+ø·Ø ‘H0kÖ, 0@Éã¢g@@nܸ¡46Ãb±àçç‡ÔµøHM.ƒ~ø¡úV@÷U…††"((¨FžA(((ÀäÉ“1hÐ 8::2ïé‡{[SS«W¯†@ À¼yóÀçóœ.BM‘˜˜ˆ€€¡D")%`×®]ÂgÏž‰ëª„ú-#''ÉÉÉ:t(ÊÊÊ ¥¥ÅTííícE 1wî\<~üÈÊÊ‚‘‘úô郎;B (u]—’(ïÑŠþ÷ßÏg<°ãǃ$Ihii!??VVVøå—_`ffƼ·t˜¹~ýzÌž=†††Ì¦–Ëå˜5kæÌ™óÅËßjjjX´h.\uuõz9hôßÎãñ˜tmÄiW&“ÕK% ܽ{<ÀÀkü÷‰D"œ?yyy¸wï ƒTZZ [[[èèèÀÑÑÖÖÖ ²’Z¼zõ ¦¦¦‡œœœFàéé)ôòòwîÜY5Mÿ $‰€€\¹rR©, ?üðæÎ CCC¥M~ãÆ Ì™3‡‘…çóùð÷÷GëÖ­•äl6ïß¿g6]qq1JKK™0U.—C @[[ZZZ‰DÉd000€H$‚\.W”VSSCDDΟ?…B@€ÌÌLŒ?ãÆ«=z4¶oߎ-Z0†399Ož<ƒƒÃ½OŸ> '''XXXÔyD¡P 55ÅÅÅÈÍÍÅõë×ôôtÈd2¨««£U«Vppp@§NÀçóFŒºd ( aaa°··¯T5ªºQ­XC·Ððx<†‚ù[x{{ÿ{ÂÌÌÌ„!!!b}}}=í'B•+W® EEEPSSCPPüýý!‰”nÁI“&áùóç øñÇáèèXá÷ ""ððð`FÊ5“$É(!Ó·ô“'O°fÍÀÇÇ.>Ÿ#GŽ ** ZZZLÈpöìY¥|‹ÅÂ/¿ü‚;v0¯Ëáp˜dme4:õuuu9rcÆŒ©SF&“!44¡¡¡PSSc˜0H’Td¦ÇŸèÐ\¡P ''ÆÆÆX½z5œëÌcQSSÃìÙ³Ð(+w_r¹×®]ÃÂ… ÿÝ¡öööÂE‹‰ Të#ÈÌÌÄýû÷1nÜ8M›6¡[·n IEQ000€§§'rssÁb± ££hjjB¡P0…6l€ ´µµ‰D'''¦2H¨ò!!=+ ñâÅ p¹\tîÜéééÈÉÉÁ«W¯ ¥¥äää0 Ûääd¬Zµ P(àñxسgÔÕÕ™<ÍpðàA3{`áÂ…˜1cF½³¦²X,L:û÷ïÿìÖŠ¢ ­­}ûöáèÑ£xòä „B!rss¡««‹nݺ1á MÉM_¥¥¥L+ÉÝ»w‘šš ”••A  uëÖØµkWµôª‚X,ÆÊ•+1{ölU¦ p¹\,Y²gÏže¬“î… rhý4*ÞÔÁÁÁ8uê²³³ñøñc\¼x?þø#sH 3p,‘H`ii‰ÀÀ@†‡;%%‘‘‘ËåðòòbÈøÖ¯_Ÿþ¹FVeee¸víºví uuu¦úùöí[\ºt èÖ­ ñù|,\¸%%%àñxH$8qâÔÔÔ˜ç§( ?ÿü3.]ºÄ }ûö¡I“&U6çÖE^ÃáÀÌÌì³~P(D\\f̘·oß2Zz–––Œ·X=E:/XZZŠøøxÄÇÇ#??êêêHOOÇĉ1eÊ%άÚxìëׯGß¾}å >ÒûûûãÁƒ ÂÂÂrʇ*(ƒ_ÈÊÊEQX·n•Êĉ™  ƒƒüýý™ƒñâE\¹rßÿ=ÃD*“ÉÀf³‘––Ƽš„IIIÌ-OQÄb1ôõõ1jÔ(ØÙÙaÚ´iL“¨T*ÅÚµk™pHMM £Fb¼ :\ ÅÎ;kúôéxúôi½zÝ"‘óçÏG]4,/Z´ @NN FÍ0Up8œJÄ?æ¥Ñ¹  >AAAH$Ð××lj'`ii‰wïÞÕšJœ$IÌš5 ª°°–Ö¿…)8~ü8# BEëNç‰D"&OžŒ 0 ¡A`îܹxÿþ= ÜÜÜÅêììllÚ´ VVVðòòªÍÍÍeHäjÓ{{{#22²R±±XŒE‹!;;‹/ŸÏG^^,X ÔA?hÐ %cÄáppùòeÆÐæää€Åb¡>/³„„øûûö†vuuÅùóç!“ÉЫW/A(ÖI‰¢(Èd2L˜0ÞÞÞHOOGÓ¦Mñý÷ßcÛ¶mµ6è2™Œ ;Uøôú›™™!<<| nÝºÕ š"JJJ0zôhðù|“Çã15Q–Éd%JOO………L’ZOO¯Z3lµÉjkk×8Üd±X8qâJKK‘žžŽ#F|ÒX±X,dggãÌ™38zô(nß¾gÏž!%%ïß¿g’£££qøða\¹r$IB |ôùär9ÜÜÜPXXMMM,Y²¤Æ}kR©”!qTáÓ^‹Å+$$D×ÂÂBe°>²™Þ¼yà 6——f¿rå ŒQRRdeeáÈ‘#ppp¨’sˆV1IOOG³fÍjýÒÒG‡®Ö¡W(˜6mŽ9uuuøûû3”¼+W®d~‡T*Å–-[ðòåKægïÞ½[ç‡*%%…™¬i8ÔÄÓ„}*ƒUõ…«©© –‘‘‘K›6mTë#ÊÉÉ jjjððð`r=ÿ'?ÄÌ þïÿõk×0eÊ”*ÚÔÏÄÄ"‘vvvŸRI$x{{#99¹ZaMeöíÛ£¬¬ ·nݪ`hÿùç†wžþïºD~~>Ó VLŸ>M›6…B¡@“&M*]c±XŒÐÐPðx<¸ººÂÞÞû÷ïÇ_ý±X GGG899ÁÃÃ^^^èÕ«ºwïŽvíÚ!##þù'._¾ ggg¸ººâÕ«W8uêT¥¹<…BÁxI ÈËË«q.NÕ°]õ5kÖŒ`ÅÆÆ2êÁ*(#++ ;wÆû÷ï•x¢¸\.îÝ»¹\ŽéÓ§#11999•+6› >Ÿ555`ß¾}hÙ²%bbbàââòٟׯ_×yžE[[»Æ]ô†††¸{÷.JJJàëë«´~EÏç#,, $IÂÓÓáááHMMEÇŽ±}ûvÌš5 ¶¶¶(++ƒX,fT†hej‹''',Y²[·nE‹-ððáC>>HMMÅ_ýU¡ª>räHddd€ÍfcË–-Õn¢{àTç¯jküøñÛ9‰‰‰*wô#H$033ßþ©ä ÑØr¹&&&8pà––†¢¢"äååA"‘@*•2ÉjÚp¹ººâĉuÆ )“Éàææ† .ÀØØýû÷‡B¡@QQîܹð<Ð3‰"‘FFF°²²Bff&<==qôèQp8¤¤¤ÀÔÔ”É$''C$¡¸¸˜‘žªK4kÖ ááá5ÊÛ………A"‘@KKK)¯FÞ¾}‹äädŒ1W¯^…V¬XÁäâª{9”iÖ¬Z´hWWW>|yyyèׯNŸ> 777æ"£( ¶¶¶HOOGXX/^\í¿K$5*6Õ¯ÿS(Òc½|ùRU¡¨â„‡‡C__ŸùÜñãÇ™Y<†±sïÞ½HJJ‚™™Ñ£GãéÓ§ˆˆˆ‹Å‚ |||êtƒ* ôéÓ:u‚¹¹9¬­­Ñ¡C$‰èèhܽ{†††øî»ïЭ[7ddd 22‹-B‡ ‘HÀáppèÐ!¥ž, Æ8×GÈB’$òòòªí]°ÙlüñÇÐÐÐP*VÔÔTPSSS\»v S§NE×®]!‹?Û{!IR©>>>˜:u*N:œ;wN‰iÖÐÐ$IBGGñññÕë ×ú—EQÿŽp¥¥¥© Ö'n¾ŒŒ äçç3Œ A 66<eeexþü9rss1{öl$&&BCCYYYŒhÙ²%30  ^¥ã?Üô]»vE×®]£–››‹ââb¼zõ £GƪU« ££Ã„%·oßVÚ FFFxÿþ=ôõõ륿‰žë£U–«ó÷½~ýl6›Q^€øøx˜ššâСC˜5k¼¼¼jÔ†¡©© ™L†ªÈ+éœepp0^½z###ÜR©B¡b±]»v­—°ÅÆÆ»wï®Ö,++c(°é>¶äädbÙ²e5îi£( &&&xòä 222jd)ŠBëÖ­áîîKKKDGG+^úR« §OŸfX?T¨Æû¯Z†ƒÇãÁÜÜzzzL5‹výiÞ*6› @Ðèèh-,,åhÚ û°5==Mš4EQ°³³«—Äp›6mpøðáj³(І•Íf3žM÷îÝkjËårŒ=C‡­Õecaaccc´mÛ·oßVÊ+Vg™šš2üe*Tí³Êo”QRR‚Þ½{ÃÃÃYYYÌç{ôè¡DGK—ÃÊÓ­äåå$I899)¥ââb 55UIͺ®×xùòåxñâE•ßK«Ñ¡\Ë–-aiiY­É‚ªBm¡P(`gg‡ÈÈH†±@•œôl6 ,@Ïž=UÂìY–¦¦¦Ê`}$I‚Ãáàûï¿WR—ñññAqq1éÝ;• ‚` –X,I’2döQsss   z¥˜ÑÓÓÃâÅ‹«lLUWW‡\.‡H$‹/““ƒÎ;uÍB…B¹sçâÆLÿ•‰‰É'Cè‚‚ˆD"µL  ¦¦–¹¹¹ÊÂt~¢ü©©©1Í~´ÂocËÒ‹fû …ÐÓÓS2Ö:uBjj*ú÷ï_¯¤B¡ÀÁƒúÉuÐÕÕ…P(ÄãÇ Ölu uuu¸¹¹¡¬¬ $IÂÚÚú£Ž€P(Äúõë1f̘F+û5ö«žžXöööªO@(bÿþý8~ü8Ó.•Jáææ.—Ëp~7FƒUZZÊ”á?¬b²X,8::bÓ¦M7n\½{áÙÙÙPWWÇ­[·>iØúö틼¼|x=kРAG£££UÍ£UÜž¦¦¦˜?>³ñz÷äää€ 9r¤Á®!Ý@+^ÄÄDœ?ž\ d¼¨ììl˜˜˜`ëÖ­hÓ¦Í3 b±“'O†§§çGdII \]]‘Ðà VóæÍ!‘H°wïÞ M¨, ©©©ˆŒŒÄàÁƒUyã‚æcÀ¥K—Të ( ³gÏÆ?ÿüÃÜœ2™ ›6m‚ŽŽ²³³áçç‡õë×3Í¢_Ëce±Xàóù‰DŒJÌÓ§OqöìYlÛ¶ ;wîÄñãÇñüùsFz¬|.…Åb!<<{öìÁ«W¯*è)Ö7ÊÊÊpòäIŒ3¦Òp¯²ö‹sI_kíår9ÔÕÕ+<7EQ¸wï<ÿ/æ±~k‘p€›ÜT‰÷OC[[C‡Åï¿ÿ___Èår8::B,C$áôéÓ˜6m=z„ììldgg+ Ó —zzz°°°€¹¹¹’ççB  ::ùùù°´´dÔ£¹\.444àââmmm†ÁaÞ¼y‰DÈÌÌ„¯¯/ó</^¼ÀâÅ‹1lذ¯r¸ °fÍtëÖ îîîJyÖÊ.‚ pþüy´k×ÑÑÑ9rd½{­III°¶¶fŒ==fTþ=åñxX¿~=ôõõXåø •¯uLL <<<þ5X“&M‚X,V¢PQ¡bXøÓO?¡W¯^4h3[xìØ1 4<@ÿþýaee†n·üæU(ËåÈÏÏÇæÍ›áììŒvíÚÕIÑcëÖ­ðññ‘‘ÑG =_wîÜ9C[[›áŒ¢+žS§NÅÌ™3qçÎhhh|µ°«¨¨AAA8yò$Ž;†(yQ•]°tÏX} “Ù³gcÈ!xðà£ÛX¾U„®oÚ´ °²²R«Ïˆ.^¼ˆß~û-ƒ÷îÝÑ e>½Q/]º„_~ùB¡ ££ƒ!C†@CCK—.e8Ê% #ú@H¥R$ üôÓOhÕªBCC?û™ž«:@II †ú¯ñþÕrû矠R®ºuë†ââb¼|ù’qý§M›†–-[âþýû¸xñbµÖ’xØ´iS­×žÇãáÝ»wUv‰S…mÛ¶1$~»víbB'‡%K– mÛ¶ ¶‚EQ<<<°mÛ6LŸ>ÅÅÅÈÍÍýjÏC‡÷呜œ ìÛ·vvvn¾´¡"-- –––˃$9pàÀ}U«zËå˜7ovî܉¼¼<&Wµ{÷nØÛÛ#22/^¬–×D·ÔÖÃÍÈÈŸÏÿd•—¢(„††"//ýõ㑱ÙlÌŸ?ÖÖÖ˜2e ÃÕ¡P(@’$¦Nн{÷bëÖ­ FOS àìÙ³X·nT镺ß×®]ûÿ Lž>:uªô5‚I’X¾|9²²²Ð½{w„‡‡3ÆŠÅbaÚ´iÈÉÉÁ€ê…¹¾`aa—/_6˜†Ýû÷ïÃÖÖVÕ½^Ç …8~üxRÇŽ¥@”Ë4 Ló÷÷W­R  ££ƒ¹sçâ»ï¾C= P(  …Ù³g3ÒOmÚ´ùhõŠÅbáÎ;ppp¨ñ뇇‡£C‡Yù|>.]º„«W¯‚ÍfcÑ¢EV®\‰eË–}Õ ǃ¯¯/.\¸Õ¡¨C°Ùl¸»»ÇµSò°D"ÑûvíÚ•©Hk†¼¼<,Y²¯_¿Æ?ÿüÔ¶:`Ïž=صkŠŠŠ*MÓº‡5½ ‚@QQš7oÎü?dffbîܹˆŽŽFÛ¶mqÿþ}ôîÝEEEÌó5 <!!!PSS—ˇéôƒËå*}|ì{*ûÞêü\UßC°Ùl°Ùl†ÄÏÖÖFFF8}úôWk|f³Ùظq#–.]ª4<®BÝàæÍ›øûï¿1{þƒ¯ÇÅÅýªŠÁk‚ 9sæà¯¿þBaa!ó5‰D‚   ÄÅÅÁÈÈãLJ†††RhöçŸ"  Fù¡PˆM›6!00pçΜ:u eeehÑ¢~ÿýw¥™5.—‹ÈÈHã÷ßǹsçPRR´\мôßCç‡èqúóV‹©T ‡S¡*Æf³9ùóMtÁ‚gËW,Ë p¹\F.M `ùòåÈË˃††0qâDXYY}Ñ‚‹ÅBLL âãã±}ûv‰@=œ©`óæÍÄ¥K—ЧOeƒåèèhÙ¿ÿD777Õ¬S-QTT„ƒB&“aþüùŒW#‰ØØXlÚ´ ÚÚÚhÞ¼9ÜÝÝÑ´iSœ>}...LCjuÌêÕ«ahhˆ/^@¡P`Ô¨QpqqAçΙ0‰Ãá 33S¦L¿¿?âââйsçGêêê?þøcfc[ã“'Ov ¹iÓ¦@SSSˆÅb¸ººböìÙJçÕ9™™™Ø±cfÏž]£6 ‡“'OâÑ£G8qâD½7«þ¡¥¥…Ù³gÿuîܹ!ó°àââB­\¹RµZŸ™Óxóæ V®\‰ñãÇÃÁÁѺ£)•cbb°k×.¼{÷ïß¿—Ë…™™C™ò± ƒb–ÉdX³f 444ФI <}ûöEYYs`…B!’““§OŸbÊ”)8qâ=zduûöíç}ÇŽ{ÞÂÂÂËÑÑ‘RWW'<==áââ‚~ýúUËÛáñxX¶l-Z„={ö`ذaÕ6tÛ·o‡B¡À¡C‡j¬ô¬BõGeff.\°`Á²,cccûÇß«®r­ ŸÆëׯ1yòd,[¶ ööö:žY,444³gÏ"""]ºtA«V­ “É@’$H’d Qii)ÒÒÒðöí[œ9s†a=ý‰Ë—/‹ÅÂÚµk1kÖ,ÒÆÆ&fýúõ®çÎC¿~ý¾™5aaaQ-Ï,??sæÌÁäÉ“1vìXÕ s=†ƒãÆÃ“'O”lTƒµiÓ¦Ö/|||T1y-<›ÍFBB^¿~mÛ¶!88(..f6<ÝÅb±••…ôôt&ÑÌår!˜¤³††x<3<Íf³! A’$&Ož ‚ 0fÌAíØ±ƒH$£·oßž;iÒ$lÙ²å›Yß%K–`Ñ¢E;v¬£››[ÌöíÛ¹S¦LÁСCѼysƒÃá|2dûpæ³<(Š‚H$Bnn.Ö­[MMM,]ºÍš5SÛÔ#¤R)þøã ØñIƒ=zôlܸ‘_VV¦bõ«CÐU°˜˜\½zeee°µµ…¾¾>Z·n ccchjjB.—3M’>‡¹\Žììl¼yóÉÉÉÈÌÌDFFZ´hÁäp&L˜:hРë;wîõ_^ëƒbĈ€!C†”¤¦¦8S3gÎÄ7>i“ª4X—/_Æ–-[Þ.[¶Ì´<ì …/^¼ÀæÍ›qïÞ=UAB…cÔ¨Q‹ãããgnذAÖø¯#..þþþDLL œœœjo°ÀÚÚº•§§çKšWù¿,X°Ý»wÇÑ£GÿóäìÙ³ðööVí6jŒÓ§Osú÷ïoãááñÀ××—²´´$þ«Ôššš”““Óóœœëª8Ùªí! 6ìFppp÷ò´)ß:ø|> pþüyÄÄÄœZ±bÅww÷¿H’T1KªPg˜Ÿ?×ÐÐÿ9.ø°°0„††VËUÛ`¥¦¦6›4iRʼyó¾ù*6›÷ïßãÖ­[ùgΜÉLHH°R+ê !!!ÄÔ©S©§OŸžèÞ½ûÿvìØaÙ¤Ip8œoú¬ŒŒ ôïßßÛÁÁáü;wªlý©QæÂ… –ÁÁÁ‰ø&)5hô   (Š´µµOEEE©ˆŽT¨w\½zîîî€V­ZôìÙ3Ïçs¦L™‚ìììoîïe±XxõêFŽéN’ddµÏhM_(==½·““Ó²ãÇw,))iôIgŠ¢ ¡¡ˆˆ¤¥¥áøñã?¼|ùò¨ê©ðµÐååË—C„Báô3fPjjjÄ·@g# qâÄ üú믞.ÕÈ©¨í‹¶hÑâùæÍ›-èé÷ƇƒÂÂB¤¥¥aÅŠOCCC¯¸¸¸LY±b1þ|UWº ÖÖÖƒvoÕªìììPVVÖ(‡­¹\.Ž9‚ÈÈÈá………G^¼xQ£?â³<¤þýû‹ÇŒ#lÚ´i£3V{÷îEii)ÓU»{÷nŒ7Nu2Th¸pá¼¼¼`iiÙU(Þ †©©i£r8fΜ‰~ýúÙggg?X½zuG­ –N:…ƒÆGEEý¦öm¨aŸššÒÒÒ°jÕ*¼~ýÚ=((¨hæÌ™wè¦>ThL077ï6dȵqqqÝÖ¬YC•”” üüQžžžÏ<8ÞÅÅåïÚþ®º:©ösçν7pàÀe´x< ñèÑ#ܽ{7«iÓ¦G׬Y3IµÝUhì8zô(1tèP ËÐÐpÛ”)S~ÒÓÓC×®]!‘HL¸Èáp‹sçÎÝ»|ùr§Ïý}ub°†ŽC‡ÁÆÆ&7$$DG]]ý«-í-åççãÆŠÈÈÈ‚¿ÿþ»AEªm®Â·:JˆŠŠÊþñÇå«V­2211a˜S¿æs?^Ñ«W¯b­:9ßuýk×®ÝzòäÉ€mÛ¶áKŽò°X,hkkcÆ I;wî´ÉÛÛ{Q—.]`kk ‰DRçŒ|> …W¯^Eff&öîÝ;mÏž=òï¿ÿ~‹j « 0xðày%%%æææÜÜÜ`ii‰¢¢º 6‚€ºº:²²²¨k×®yyy Iò—­[·®ˆŒŒ$Üu¼OѤIDATÜÜêÌÍ«w“rlêÔ©¿ýö[›Í†±±1444@Q Eµø°i=>ZÖ=;; Û¶mË...¶€²²2‚Çã©ZTP¡øøøì‹ˆˆh¿oß>[‰D‚–-[B €$É*«A0, $I"==999PSSÃüùóã[µj%Šˆˆ0€€€„††Ö}ʧ>¨üpðÉ“'ùÁÁÁT³fÍœúõëqòäIäååÁÒÒ;w† Z´hÁ,EQŒDzYYnܸ³gÏB,câĉyÇo¶~ýú²3f¨È…TP¡˜9s¦`ݺuF ,x}üøqF|¶uëÖJÆ‹VjÊÏÏdzgÏððáC<~üyyyèÒ¥ ˆ^½zñçÎËZµjU)ÖgèùÕëùÿý·Ïñãlj›7o"%%$I2â 2™ b±šššprr‚³³sÔØ±cU2»*¨P‡ óùã?ˆ¤¤$ðx<°X,I’())‘‘Ú¶m‹>}ú`üøñ—‚Ð?û¥Û‚þ×õÜ>ògÎIEND®B`‚antimicro-2.23/src/images/profile.jpg000066400000000000000000000254651300750276700176460ustar00rootroot00000000000000ÿØÿàJFIFÿþ*ÿâICC_PROFILE lcmsmntrRGB XYZ Ü)9acspAPPLöÖÓ-lcms descü^cprt\ wtpthbkpt|rXYZgXYZ¤bXYZ¸rTRCÌ@gTRCÌ@bTRCÌ@descc2textFBXYZ öÖÓ-XYZ 3¤XYZ o¢8õXYZ b™·…ÚXYZ $ „¶ÏcurvËÉc’k ö?Q4!ñ)2;’FQw]íkpz‰±š|¬i¿}ÓÃé0ÿÿÿÛC    !%0)!#-$*9*-13666 (;?:4>0563ÿÛC 3""33333333333333333333333333333333333333333333333333ÿÂÜ´"ÿÄÿÄÿÄÿÚ ꎡGh.ÏÎËgÑ0×Yð‘ô÷~e§¿ÎèTP©B€ƒÓ‘W×cÍô¹¿«·ýOhÎê]£bWæ'§è9\o¥§²/&y®çÚŠîiôTŸÑ$)Ó¥‰ôth<»ÛüÀÉ„x[¬„‘ø®ŸZbôó|úIª¾ ?jQ±F{ªÖ/~‡LN§8Ü_ÒmçòÚѕգ/ŽÆ6¶U£¿¸rµ²ØýŠkÅ*+,Óg³©—Z»8ÏVÂò/$ämÕl`lìÂÒæY”ÜÆï*·ciÓ˜£=ð6sžJèh«yÝ£pÃõuädèíÃF¶hÒu½i£7gÐü»»•6UÓ^tKäß[ù_ ¾Kë*Ý„㑲àTã®>~•…¯RéÏ3é D™©[ù7Ô“ö,o«Ãw|yNhl€[B©Zt#!|¤¢î;%kêZ2Ä`×´*SsФ.z˜»`}2Œæ«_åÿUã¥\ …0ŸÑ,Jí-UZEÏëñUñæ'N]Ëæ73¢à L Dô¸}’[wj+亾=„ýŽu‹]6X”xš…‘Ô‰÷ ò{Ú³¹ ° !ÜÃÅòí…¯Gƒ«›gdl…!Vù]|EôËç x¸¨ß”§S€UÐE× ´·¡LÒÍÏ#>e³k1&² cÝÓ)‡tcëf³`Ír è­JL•J· »¯“©D@´&ìþ¥`+úYeÄ·]K¹æz›>^!rcjªs®F­\ÜÛDxæ.|Ž¥Ô°1Ïô<•Ñ UÍШ-$[Þ—Yµn…÷ÂO+ÒÔÎØç™m³ÏA–óí5l+[¹ê­n>asñS›è9ýI3hªØ‚£«[Üy¦ú-Ö2ßk$Æç OZ” ° r¨œK°rëNjYº×Z_Š÷umYî!‚uíÕŒôi¤B­°\GAn¦¿ÿÄ(!"2#13 5A4ÿÚÊÕ©7­GH¬TÝO1ü1GÞ™·ØÊ»drê®Å‹Ä‘ËfnX Üî–7³×¸ Se"ØFŒ{¥oTµ_ÖØO¬L—››•ÒígIà¢Ã>šØht÷àÿWc>,Ê‚ÏTÄHþ¯I‹êiÔ)´ué™y&ûÁ•×e’ʬÇl;ÕÍL_Öë ÕÜ5^öX•&O¬“,±íojþ3$ýŠëSŒ„Ö¼WÔ¶¦Y»=±Ï7<@ìa5†¸O¶^jb®E×ä¿ð¥9¤½ySUœkƸ½–Û–¶ÙM—âãrZ-ˆÓæñ?¼žßÓìÌÖ? Æ]{ã¸Yn@çÔ,+@%|+±î[12¡S±+TëVf¦C2¾1b™¿7ÿ˜ö'°ói¨€¯Ýަ=¶pGn(ÜG·¦V¸B¸£©w鲦2û²…³eçd b¢Ù#E×Ê ¹„ÿpÔµHS¼eã‘Ö(àƒ= ’¹5R »s¬dÀ£ÔÑ¢ùöúšÔblnbÒ~¢Ü^¹·Ô¯°ŒÜ¢@4ÈÞ6n4Á|g¥ßR›Í»ÆRÕw>£ý\U~.Ç}|åk³x튌µcîd*}/²ì=F†[.^;#änSÓ²:Øê õ }Kúâƒ-G`äÞBŠç=JòjY™™[ãñb®Ûˆ1—P~öq‚`²ê€J[ê_Ö¥øí†Ì¥¶ œkPÖ¾ºbÇh`ª=ˆü‘c’O’3Rè~óöb”+l§‡Î“[˜¢“'äÜÌrG‘4Ë’èŒÛ|ŠÄ¬ôân%*T7JÙ<­ªC´¦ÑHdbìFñÊ Jù3u£FÎàÛJމ„V˜Wà‡Ù89Hφ8ý¿gdqÅ’ï‚=i Õ†Ûlb,Y\E+dL~4eË3B0t´]k.†XÙĺ0{O+ÜXŽtÈøû¦(Þ+0ty-9'FâÉR!“ðÚ95ÐÛe—¬´Ú¨TC²Cþ$ès½?ÿÄ$!12A "QaÿÚ?$¬j¶‘(8ˆÄºc¹Þq•1;àÉŠN»ßÃ㦢úµyæÙÕèÄ—#‘5q²YÔªËBÒR½{m«DKqž¨p^Ù.• ø£Ò…­¶GI -¢Qk‘/ÍdR»Gv_Í#°ÞÂnèéD¢ÌiîtÅòJ -´zQ{‰^Äq$í‘+ö/'¤¸Òž˜yÒ,îïdrÑܶ1¤çB¢O}!$‘‹+›ßOz-‰M‘Û“7'èqÜØØUe"Æš²Q¤z2|™GdBržïI=Ë,Çä„5èKÑ•ÔYvŒþF'¶’«6Ó˜…¤ÕÅ‘u’‘äbN´uÉΘ9±;ÖNÕÎɤŷVŒÅ㢛;Œ›t'ì—ÑFÆŒ~?GÁÀ÷×ÿÄ2!1AQ"a 2qr‘#R¡±B03b‚áÿÚ?8 #Ärx˜‘”Œµáü/ÆCÛɉîe“c<,'0b8‰/4+ÁÖXZF×ÎFZ™Gp å©æý¤rWë²FÅ«SLBÑ+ÐW¥z•¨Û<½;r±^Úc ÷ )gPä)>ž‘Rµ:¥juÊ÷BxNs^ÑeâK\ÑrÕÊì‹T©Ø'ü—P]4Z €{¶;• (ê¼òVÀ°XßfT1ò´6ùVÜ* ¥×(ÆŸe‰Ó¢—n`¢ˆíµ#†×K§lù_9õä’¨ƒ¨öXßjc¿vS Q¶ÊiÜ.¯uþVŒ½Tªå ™|"º,n™?¹5³:D!Šg§½?Ú†+aì. ò<ÅPnèFÊUWb»e>@½êî˜AƒÊ.™ê)í ’ ±µ[NËG ñ*àñÈU¾O O¨åp|ݲ øQÝ0b a0´°ij ÑSºÆ‘.;Ùi8 wr¬¬œó—aR‰ßÊ:DÅåjĤeb¹ÿõG[ ìÞaN|°ÏW²"¢Éã²²0,<®ï“?ÄÊŒêÒæáD û â4’ÐW‰á‡â†u"Ü6ák4rú—=Žn#7šHpsP …«ð'•ˆÖµÄ“Âw²¢°ò†•¨š&Õ5ÍäÎTTt{×<µ ?LqX¬»u¯é_,%À‹/¨Ã êÅt«QB…¥­V$ð/²ª±ÎêbQå1J"™H)ø~­Bèx­!§p£<·º‡5ÃÝ;Åi€MkUwZQ/‰®‘)íÓLû!º9oã3œ‡~W ¡”²ê$ûå*{"ÉÙŠ-•\ ç.2'á)Ê]hÙ4¶h7Ä£ñUDDi´+(ÊÊߌ‡r‹V“çÄûPC"»­þn¨TB¢ÙQz“T© Iº®U¶Tá2Ћ8(TPþ•“9!Yë# ^l…6ËIËþJʹµ1íùGÝJu¾QÀCL#+±WTÉÄmœ‹©ßÊ»Š  õ)満é%]^ÊÕ B%VÈÚÈ Úêr‘•‚ã8A TËXç•QÂ<#(•£§çËaäº êS²+dWu…/éiýÙNʪÞVɲbêöTRVý”·ð¨Ñòò£:"‡”y©þ“ À%F’ÅWáB‹+ÊoºkŽëå3º.áFÅ4¢Q+ئ¨M=á—ÿÄ&!1AQaq‘¡±Á ÑáðÿÚ?!Iv’õY̾@¡^ ¾÷rKõ ?â\^“ø¦)q›EeâÔËs“¨Bœ”ް5züVæ0ð¨û5Nžçóä=KÑ |‡hˆœ?Š©þH½=[_jüÇ>‹lƒ#hÅCN&ZËêhÙïÀŒ8StËfbÈÐìâ$k[—ƒ3ÎrU-BÞ®ý•ê#èOUÊ û…`2×§q³ó3áæbáê¶«ñ“ˆœ£eblZ ‹eS ‡•µê]Kü #µ.¼"ÏÁ<¸g—û~(òâÅÙ±\E Á:\Sô?4ã-“\W¨`ψm(Ž%LÏÝë?òd[§ôFÍÿƒr†»ƒ*Ü…Fì<=Ó$ÑFþbÒ4ùcÖÁ°u‰ª½3| 4†òËvE¨ c0U’¥ˆ&ã߯#¨®ŒÈÑ/Šá_J|%;Œ¹ò% õ•±ë,4U³#ˆ^+¶ÓÌts¥¸QŽæ±Œù7¨ W<½ÂóÇhtD¡‹¥ú†|yÑç²^UžÚnb9'§ %8µ^îZ¹²¦A|“—‚DnÐâg»ßp›¾WûCv±ñø™]ç„ø%<Õfkà–¯'}Ï$I?á/®yx¨§ w*íÉÄØ´Ø»YwØÑpäüO&¸BÕ¹UN­Ã)Äž.2sõkŒ •N a@- ›ÜMÚðÌ+ä…¶³ÈƒÉ¨4Æh³F²ÑüÇX ’¸ÑÔT•ç…Ô°¥šÛ‰tdŽo1´kzU§ä†þ ’9+·~çŠ}ÄÉLÆXùàŽ ¹’¸3Ð)ƒˆæÈå–Qw˜¶²ÔÔp‹€£.¦›5¸Tû(<Ä'[½@•L79}4Á6 Éž`Ü^‹àŒ¯É¶;§ˆ¸cŸq‹™y`̰ËKŸ ÀЮ.4eè:š:4”Ö­ù•{–M4¬@+žžÿ+æ¥04D¹ºP™Wଙks¸ñgÕ0f·ü£Ün_1ñ- Ö×CÛ2Båó‘Ž—G3Ê¾ŠŠ\ê¶Kà§/cêË©Îrìaä·¨Êʇ§¸êóFØY`ù¶³7{•0<ËÑÿ›™ˆ.# *ÈrL•Æ]LÒ~ˆ‡Ô€•„bDÊ.oIAîlƒD{nǸ–1M~4 ¦z “¤niEc¸ÓCûJŒ¡ÓPÕ’–žºšfñmw2å›¶¥LAÖ®bwop@£.gŠaÚV–3V›#MÈ4l ÚejÊ­qAHÀ%:Ä/‘w13q¾-=ÆÜbË‹q™—u9‡Ô¤«ŒšÍA”ãÃ>;g$«¯'|Í(N-©VV]–PäðŸpDT ƒïö0Ì žc2Mc¯€nXÚù¯ÅW,°ù—·¸œô9ĬãÜ æý˜§“Ü{lY™Jša~10ØX˜ëRà›ž'Ì»;ws‡áX›¤iç#„áBXÊZ¡> ìpÆØ‡†qjúÔªjƒ‹™¸Yâž‘`ðø¸CÃæ2Nu5‰æý@?Æd¾%ˆ]¡>®c»Š'˜»š mj_&tž]¡n§]L‡Ù*=btºCtF ËVï,|ˆ(j`Üø±À‡À‡«Òp…ú»‡°þ¢rX¿¨zbÄËTVdÛ*8$å*Ér‚·åîPR6\«_UUU2Qc¹K¿—¸‘àŸi¡–10¸§î ªÜLŽ÷üDXÜ̸aÅ£xŒ ¼Ÿ¸•-îÔDX Îq-X^eTp‚Æq*ÙÜj+pî‰ÈÅ^Ýîi@ÔVŽeÎjÔÙ:|™pÆYÚXÀ§À„yµ-iÓNa€õ&CFi£\LsW4Ü6ãNL1(9¼K|¥µ B•Ì>|{‰Eb IÑœÀZiq숸ûþ!u=–x•³§Z&VQNŸ€¼ø˜ç]ž!¯ RËÂ|ÅrÉEG5-iPUÂT¯™€oߘ„™æ7fÑq£s+k ÇàÜ Ùcâ‡?„A*~‰·×îi5¶¥P{æ ÞC€êaøÎ3û©‹\xÜ)Ãa¾#MææÃÿ˜<˜q|Ïâa0¨á•ÛžØUy8@*ÚEñpÅÚ2—+#†ÚZž# FgYæâˆ«¸ûˆ šFºÕ´J/ÔJ4ºŸ»»Lµ5ŠLŒ³p}ɨªÛYä³!B8&XÒÔµ_⥙MjÊó(Ó,üà÷-–>f é/)„aîcmaIêE„<­`KÐG8ö]@ yþÐr´æ k¤à-æÅuF½A kØ1uêî\uøžÓg™vë‰{ÂüG‹¿'™`nÑi3P¯gÿÚ L„QYJ9ÍH–F¬¼åŠ/Ñ—Ô˜]›ïeæÎ5Ûà¶Dµm>»ïk.—É žéSV¢h®Ð%wƒJÐ7ïrYˆFW‘©2Ã4èìëêë3ÎîFùòé¬p6 hTrOŠú :bápq.÷©S 3"F4ÿÄ%!1AQaq¡ Ñð‘±ÁÿÚ?éjûãñ(Ç¿E²ŒƒŒÐ>lyþöÔÐ?í¤ á¯›£ªÁÙºXCaÙålà–|— [v¼ü¯¾ú"x’¡ X|Jò›.¤ã²ƒÊK!åím)ÀĺûÚ8µ5€"á) ×;.ÛcæÛ§å.æþÇó` %1Ó2#¯9pË,ÐÍw1ì’¡'…‡. <ÄÌp* ¹%Ä‚N{ï÷-e<ÉAO¥Ÿ›¢9ûZ5>9¶°L/™@z½ãjhJïƒóè =˜À[Ë/k„‡–ž™éc'´¦ÞJJ7PÎl’Ê;ó,áuhòÒ=µ»^×=‘vìÙ çùµ¢ñŸKRrÉÓ͆eÃdÏ´¶k`üYØ|z0ZñËyý.ûO-³’M^bÕÓ 2òôZ(†D" 9Ë~– nrV|þƒÍºéÛE·ÿÄ !1AQaq ±ÁÿÚ?„ã~¥~àû‚¸K‡¨G¾/"Õ§Öʯü¹lnÆÐ?ç=¾›÷bá›ø°Û&þdüp‰Ø%Žª†éVñòVÙmák7âAä2üF…ÞOÄý%…‘þ£‘ T=¼fÝ>HgYe»}­Q! v²ÈòvF†9 FåŸ%Ã,m—¶,¤ãÈ¥ŽD´RË䑽»o‰[ógÜ~ ²2ÉïØw)ÇýæœGêV*!HºÛ¼À¥—S1˘j‚î&”ýE™xÓ[×õ ›Z³¦óóqï q+áÔDégÜh÷Å2#„cyCXiÙß®aX»½¦‚<2Šö³D.¤)øðïít°Âá¡KôFÜ×^ƒ‘îR•³èæRïÙ:Wj 7Ô+ _ˆ™V´^9^[Í_%* V—s—ÞTh·gY5Pc¶‡@æõˆœµ˜¸gl¹ä~züËó²|f˜;ÂüC_œä™A*ÕÀö—:ãÑÛ¹fó c›ÌLRÝ™+yáŒ9MÅaƒQ©Éâ`8R°í…6’ýWîYG!¾`Ê–;î%OtõdEAÔÔד_}D8Ë1~ŸoÔp£É§£GĹrŠ:´E`¥…R¢Ë€”÷uÙ~c¤’è&”/RŸù¢ŒvÏáÿœA¸·)ˆ-dª¦ø 3 º27‹cÀh®HxK=ç|¯^_QíY¡CÐþw PG¤—ÿ._¼$† ˆ#Ã({мf%2Ašrí†R,ÜÍ‹#W™L¨îX´Í)õ/»¶ ?qàå7òG‹w‘ð鉑 òÍÛ€ ¹¾e…JÚ*™9Äv{/æV¥!w^Yöôè52r÷k—Áðiôÿqøzą̊ 4ôGeq~‰u9ÛØvÎ$½T2ËGê21j_K‡ãPe¶Ž ´¦ «ÖuÉ[ÔòxÓ'€˜•‰S¦x É.¨±z1µ 2°(† Ü*Ê9ŒKßê$€è‡Ž£—“ý~ÄÚÁL´ø\©Š›º‰Î ¹hj–S?h20¾˜qb H¼ÖÛ ÀPŠÉUñ¦ V)Ë’ªíX_q¾Ð™–x‡ž¸ñ:øJ²Üß3¦ä.h·_r€*Ey–6µ‹]ç¨q SˆìK¹VP6¼DŠŽgÒàÊ­!Úó ê%B¾‹ê>€”d<œÁ‡]ðUi÷ݰán;ˆY0D7L€ Ü7•P¥ÉµáÔª1­Ê}²ÁØ™2¼f`XN±Å:|C |¨ìÑM à “Ef½ÄÐÝDÄX°ÈÍà… :ÃMœ8`¥¦*|­Ÿ %o©á&qf]öcP¡×´îeÁÁj˜ÅÑÀx…¨eJÿqu|›!0Fä–úˆ+ÓÈŽ~¥DÓÝT ܶ ©º¾Ef9f –C=ñþbŪñâ+PD¦M*怶OžæDÛe„À눵Ô^Åùb:f¢=Û/dCGh¬³ÕöCU莋®;ù¡ŽAiêÏ'µƈ¶þQ•¥/CñÆîtÔ³‰¾ÿu¡°c‘°ëÒEƹ•Kû:”6‘R-¿Ä1%œ—¨[‰Ž>¾P0 ÷n.‡º¦5¯Cñ7\Ø{X~F¦Í—’’bFˆßµÆØ¡E’Ý[¢êi¶+_*E\ V#e-|@€– ,ìäþÙÆŠÉàÔÆ-¡´¬’›‘°1èæ eùo0³¢ì²?"f£2¹Šù¨¶¸KÒq¸)v1fÿ?,éƒCkÒÆ¬*ý@ÑÙà–jRží1âÜÓê¾&ù†ý™¯˜‰2,©Tk,l|^½GÂ|O$¼Ô7­HÜ0àë(¤Kjž˜W.%aSEþ?pt— èå‚.YˆQ®‡þE –o°xeæB£(Y_ý%®acj4æ‹^c$+\²ƒ£µ¼qP :÷ ™ÊžœëÍ˸:Ñm¦ZQÊñË/ŸÁš° ¼±È5t³W TøÖ•æ ¦U:z{‚i"¯¡þnUB†pÑõ"kp_ÄOYóÊÐLŸxK’Ú+û„¼º{” ­GÓ½ž`*¡ø.tÜbâ°Ùªjª"5XªÐVˆ%&hùÄ ¨8½“'¸·hѱÀlé¨y+NuåyfAˆH)Ðye‚Z¢c#îcj¨ª>£¤j­áïÜ@48Äßç¦F ³ÏR…®\ÔÛ °‘rÁàªDK==3“†æõMuêš¡˜ ¡ ¬—¼iýÁè 6Hú+0ysÄÒÕ¤îN(3Uªqaêʬ›—/c}èf¯Þq5Ȧ*Z%Bn‡‹rêS@ŽMǶjÞ£ÑÒÝ_ó‰cZÿ€×m{”lÌÀÕS;n(Á—ÉÉ C“OClD@äÜÎÍó*]“Ô(ƒœ«˜«‘@=Z˜~$\(Û߈ª˜ÂWߢ KÙ¥Òk7/Š_,vµú˜ðé=ù•D9·ôEd»G… 4 c-¯ÛqE¥©ã-[FHC žâ*uâ=‚‹¬P@¢¤.×̤y¢Þ.4+‘6­î%‘õh[\í«·7ÆJ‘öâîÙ¯+†¬LŽËÏ4Z\¯ê±FÛîP4n¬ÜGrt%&a\mx‰2Å™«¡cq„Š­÷ELGnIxÐÕyƒQDÝË-Û”qõ9ûò\é€%\4°©ˆ–;LPŠ) /æTcC;³Ìé-Z"¨<´IºÃÕq0²)Ö2®ž>¢QÍaà­C„ù‰÷Rç¢ÊylcB^Aî·Z"‚õ¿˜p¥ç¨-`+29ÅËžè û–渫ÙaAÅ“âZ݆–’Öµ]Áviª­z<õV%ØØê¦žQuîiM…çÌ[%Å­÷ܬ'+6KSF〪µÜ°êÚ¾b¡]‚ý/õ/¸€U›3]ù…2‰Ã7mâ2¹ª%äçR÷L ŒEj·,T <¨Tgeó`×+bèBlÙÀ>ˆê-A}Ôb–D²›kÝE”3ëK1,Bޝ¤` ÐãGÖã˜ö)oÔtq ƒÔ/¦ ·¡~˜s>œLÈbýK1X¶/©TWm :EÔJlôWê+/¦„eI7U7;HA€©DÌÄ¢ÛüÂsક«wË2ÙT˨ÁÂ.ëxÜT¢ý *X4µt‘id Ù}$\vyì÷Ašé¬ñâ]À[Á×ÌÄÛ!“°ðÁÂJ~£Ê¯¨¦˜ÝæVÔUâÈW¢ ‰Ç˜Ý%”eEü#XÓ!’ÚŠW‰"éËsQk‹€dZ®ÁRBNát ¹K/ Zï,ÉãÄâ Pá%¶–µßs6Õð˜âãµîÓ0ÂÜì T`|jNc½üƒ3šR—Œ€ñæè1è3üM”,œä7=êl¼¾J˜¬¥!v¯Äµ”±« áš}ýċĦêªb‡ƒ¦  ­]ø1Ô±9ð‰.0ì×ëÌ¢p¯_1Já]•ªßñʦ“·úyŽÄÀ[n]ÌBa }©…‰cÕ©á05:«ÁÄ"ÖFº@K£¬Ä¼Âq¬0ÖH¸m4ýLiæºæ¥–VcJyÛz#»ž¸“Û7/E)U[}…²ä@=öܪ…¥³fï©„ARéháóU÷,¨V¿Ú–´7Vö_}FiÊ«(L–A2mÃf7^.çX†Ñ5ƒ‚¤‹+ØHvP²ZèÍmê ì¾;ƒ%Œeñ/RÖ®8ö!äM¿˜ÊiÙÇ=ÆšB…׿[AVÊ ®`5q  ‚÷)J€Â«ƒ™¾¦+C?ù¨(&)E$R¡]^uj•P¹\J‰*ô³aîXð7ÍyWÆæébf…c•”¦B-s*&¼â­ôKæ£{0þñÝ,×Q;-Az±ú. {¬å¿¸E,o ê3Ê“§r¤²œ ÇÌH6„VwÏõÕ`Ò¼‰_D#JdñÄ낃ªÅµßaMgòDEk¸rÝ~&œ“FLêôüË&܉T¥9HMÕ»i©¶ÅËÃýÊbå³YR­Ë›4º€ íuãýÌi  hKóä1® 1ã x²ÿ¨¥&–›¿Ôs’;ÿn$s‰bëÜ6¼º¯¨…Ku\sýÂi἞âYÅg0ó¶-¨ô¢p #s'2ñhzJ‚Àµá ÁŸäx|M§ÀŒl2.q½sçiYº<ÇvšÓ²†kmkæXLVPWê ¡t Í"CÆá•ùƒ%ÛÏÇR´ Ž|ÅŠ @+VlÄɪ Ú´Ì'˜œ‰a«8¹RŽWëMÝqý™‘¶ ™ có´íÆR_‘è¯'~à¥)…ÐYóµWCOÄx*ßsÿÙantimicro-2.23/src/inputdaemon.cpp000066400000000000000000001264671300750276700172720ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include #include #include "inputdaemon.h" #include "logger.h" #include "common.h" //#define USE_NEW_ADD #define USE_NEW_REFRESH const int InputDaemon::GAMECONTROLLERTRIGGERRELEASE = 16384; InputDaemon::InputDaemon(QMap *joysticks, AntiMicroSettings *settings, bool graphical, QObject *parent) : QObject(parent), pollResetTimer(this) { this->joysticks = joysticks; this->stopped = false; this->graphical = graphical; this->settings = settings; eventWorker = new SDLEventReader(joysticks, settings); refreshJoysticks(); sdlWorkerThread = 0; if (graphical) { sdlWorkerThread = new QThread(); eventWorker->moveToThread(sdlWorkerThread); } if (graphical) { connect(sdlWorkerThread, SIGNAL(started()), eventWorker, SLOT(performWork())); connect(eventWorker, SIGNAL(eventRaised()), this, SLOT(run())); connect(JoyButton::getMouseHelper(), SIGNAL(gamepadRefreshRateUpdated(uint)), eventWorker, SLOT(updatePollRate(uint))); connect(JoyButton::getMouseHelper(), SIGNAL(gamepadRefreshRateUpdated(uint)), this, SLOT(updatePollResetRate(uint))); connect(JoyButton::getMouseHelper(), SIGNAL(mouseRefreshRateUpdated(uint)), this, SLOT(updatePollResetRate(uint))); // Timer in case SDL does not produce an axis event during a joystick // poll. pollResetTimer.setSingleShot(true); pollResetTimer.setInterval( qMax(JoyButton::getMouseRefreshRate(), JoyButton::getGamepadRefreshRate()) + 1); connect(&pollResetTimer, SIGNAL(timeout()), this, SLOT(resetActiveButtonMouseDistances())); //sdlWorkerThread->start(QThread::HighPriority); //QMetaObject::invokeMethod(eventWorker, "performWork", Qt::QueuedConnection); } } InputDaemon::~InputDaemon() { if (eventWorker) { quit(); } if (sdlWorkerThread) { sdlWorkerThread->quit(); sdlWorkerThread->wait(); delete sdlWorkerThread; sdlWorkerThread = 0; } } void InputDaemon::startWorker() { if (!sdlWorkerThread->isRunning()) { sdlWorkerThread->start(QThread::HighPriority); //pollResetTimer.start(); } } void InputDaemon::run () { PadderCommon::inputDaemonMutex.lock(); // SDL has found events. The timeout is not necessary. pollResetTimer.stop(); if (!stopped) { //Logger::LogInfo(QString("Gamepad Poll %1").arg(QTime::currentTime().toString("hh:mm:ss.zzz"))); JoyButton::resetActiveButtonMouseDistances(); QQueue sdlEventQueue; firstInputPass(&sdlEventQueue); #ifdef USE_SDL_2 modifyUnplugEvents(&sdlEventQueue); #endif secondInputPass(&sdlEventQueue); clearBitArrayStatusInstances(); } if (stopped) { if (joysticks->size() > 0) { emit complete(joysticks->value(0)); } emit complete(); stopped = false; } else { QTimer::singleShot(0, eventWorker, SLOT(performWork())); pollResetTimer.start(); } PadderCommon::inputDaemonMutex.unlock(); } void InputDaemon::refreshJoysticks() { QMapIterator iter(*joysticks); while (iter.hasNext()) { InputDevice *joystick = iter.next().value(); if (joystick) { delete joystick; joystick = 0; } } joysticks->clear(); #ifdef USE_SDL_2 trackjoysticks.clear(); trackcontrollers.clear(); settings->getLock()->lock(); settings->beginGroup("Mappings"); #endif for (int i=0; i < SDL_NumJoysticks(); i++) { #ifdef USE_SDL_2 #ifdef USE_NEW_REFRESH int index = i; // Check if device is considered a Game Controller at the start. if (SDL_IsGameController(index)) { SDL_GameController *controller = SDL_GameControllerOpen(index); if (controller) { SDL_Joystick *sdlStick = SDL_GameControllerGetJoystick(controller); SDL_JoystickID tempJoystickID = SDL_JoystickInstanceID(sdlStick); // Check if device has already been grabbed. if (!joysticks->contains(tempJoystickID)) { //settings->getLock()->lock(); //settings->beginGroup("Mappings"); QString temp; SDL_JoystickGUID tempGUID = SDL_JoystickGetGUID(sdlStick); char guidString[65] = {'0'}; SDL_JoystickGetGUIDString(tempGUID, guidString, sizeof(guidString)); temp = QString(guidString); bool disableGameController = settings->value(QString("%1Disable").arg(temp), false).toBool(); //settings->endGroup(); //settings->getLock()->unlock(); // Check if user has designated device Joystick mode. if (!disableGameController) { GameController *damncontroller = new GameController(controller, index, settings, this); connect(damncontroller, SIGNAL(requestWait()), eventWorker, SLOT(haltServices())); joysticks->insert(tempJoystickID, damncontroller); trackcontrollers.insert(tempJoystickID, damncontroller); emit deviceAdded(damncontroller); } else { // Check if joystick is considered connected. /*SDL_Joystick *joystick = SDL_JoystickOpen(index); if (joystick) { SDL_JoystickID tempJoystickID = SDL_JoystickInstanceID(joystick); Joystick *curJoystick = new Joystick(joystick, index, settings, this); joysticks->insert(tempJoystickID, curJoystick); trackjoysticks.insert(tempJoystickID, curJoystick); emit deviceAdded(curJoystick); } */ Joystick *joystick = openJoystickDevice(index); if (joystick) { emit deviceAdded(joystick); } } } else { // Make sure to decrement reference count SDL_GameControllerClose(controller); } } } else { // Check if joystick is considered connected. /*SDL_Joystick *joystick = SDL_JoystickOpen(index); if (joystick) { SDL_JoystickID tempJoystickID = SDL_JoystickInstanceID(joystick); Joystick *curJoystick = new Joystick(joystick, index, settings, this); joysticks->insert(tempJoystickID, curJoystick); trackjoysticks.insert(tempJoystickID, curJoystick); emit deviceAdded(curJoystick); } */ Joystick *joystick = openJoystickDevice(index); if (joystick) { emit deviceAdded(joystick); } } #else SDL_Joystick *joystick = SDL_JoystickOpen(i); if (joystick) { QString temp; SDL_JoystickGUID tempGUID = SDL_JoystickGetGUID(joystick); char guidString[65] = {'0'}; SDL_JoystickGetGUIDString(tempGUID, guidString, sizeof(guidString)); temp = QString(guidString); bool disableGameController = settings->value(QString("%1Disable").arg(temp), false).toBool(); if (SDL_IsGameController(i) && !disableGameController) { SDL_GameController *controller = SDL_GameControllerOpen(i); GameController *damncontroller = new GameController(controller, i, settings, this); connect(damncontroller, SIGNAL(requestWait()), eventWorker, SLOT(haltServices())); SDL_Joystick *sdlStick = SDL_GameControllerGetJoystick(controller); SDL_JoystickID joystickID = SDL_JoystickInstanceID(sdlStick); joysticks->insert(joystickID, damncontroller); trackcontrollers.insert(joystickID, damncontroller); } else { Joystick *curJoystick = new Joystick(joystick, i, settings, this); connect(curJoystick, SIGNAL(requestWait()), eventWorker, SLOT(haltServices())); SDL_JoystickID joystickID = SDL_JoystickInstanceID(joystick); joysticks->insert(joystickID, curJoystick); trackjoysticks.insert(joystickID, curJoystick); } } #endif #else SDL_Joystick *joystick = SDL_JoystickOpen(i); if (joystick) { Joystick *curJoystick = new Joystick(joystick, i, settings, this); connect(curJoystick, SIGNAL(requestWait()), eventWorker, SLOT(haltServices())); joysticks->insert(i, curJoystick); } #endif } #ifdef USE_SDL_2 settings->endGroup(); settings->getLock()->unlock(); #endif emit joysticksRefreshed(joysticks); } void InputDaemon::deleteJoysticks() { QMapIterator iter(*joysticks); while (iter.hasNext()) { InputDevice *joystick = iter.next().value(); if (joystick) { delete joystick; joystick = 0; } } joysticks->clear(); #ifdef USE_SDL_2 trackjoysticks.clear(); trackcontrollers.clear(); #endif } void InputDaemon::stop() { stopped = true; pollResetTimer.stop(); } void InputDaemon::refresh() { stop(); Logger::LogInfo("Refreshing joystick list"); QEventLoop q; connect(eventWorker, SIGNAL(sdlStarted()), &q, SLOT(quit())); QMetaObject::invokeMethod(eventWorker, "refresh", Qt::BlockingQueuedConnection); if (eventWorker->isSDLOpen()) { q.exec(); } disconnect(eventWorker, SIGNAL(sdlStarted()), &q, SLOT(quit())); pollResetTimer.stop(); // Put in an extra delay before refreshing the joysticks QTimer temp; connect(&temp, SIGNAL(timeout()), &q, SLOT(quit())); temp.start(100); q.exec(); refreshJoysticks(); QTimer::singleShot(100, eventWorker, SLOT(performWork())); stopped = false; } void InputDaemon::refreshJoystick(InputDevice *joystick) { joystick->reset(); emit joystickRefreshed(joystick); } void InputDaemon::quit() { stopped = true; pollResetTimer.stop(); disconnect(eventWorker, SIGNAL(eventRaised()), this, 0); // Wait for SDL to finish. Let worker destructor close SDL. // Let InputDaemon destructor close thread instance. if (graphical) { QMetaObject::invokeMethod(eventWorker, "stop"); QMetaObject::invokeMethod(eventWorker, "quit"); QMetaObject::invokeMethod(eventWorker, "deleteLater", Qt::BlockingQueuedConnection); //QMetaObject::invokeMethod(eventWorker, "deleteLater"); } else { eventWorker->stop(); eventWorker->quit(); delete eventWorker; } eventWorker = 0; } #ifdef USE_SDL_2 void InputDaemon::refreshMapping(QString mapping, InputDevice *device) { bool found = false; for (int i=0; i < SDL_NumJoysticks() && !found; i++) { SDL_Joystick *joystick = SDL_JoystickOpen(i); SDL_JoystickID joystickID = SDL_JoystickInstanceID(joystick); if (device->getSDLJoystickID() == joystickID) { found = true; if (SDL_IsGameController(i)) { // Mapping string updated. Perform basic refresh QByteArray tempbarray = mapping.toUtf8(); SDL_GameControllerAddMapping(tempbarray.data()); } else { // Previously registered as a plain joystick. Add // mapping and check for validity. If SDL accepts it, // close current device and re-open as // a game controller. SDL_GameControllerAddMapping(mapping.toUtf8().constData()); if (SDL_IsGameController(i)) { device->closeSDLDevice(); trackjoysticks.remove(joystickID); joysticks->remove(joystickID); SDL_GameController *controller = SDL_GameControllerOpen(i); GameController *damncontroller = new GameController(controller, i, settings, this); connect(damncontroller, SIGNAL(requestWait()), eventWorker, SLOT(haltServices())); SDL_Joystick *sdlStick = SDL_GameControllerGetJoystick(controller); joystickID = SDL_JoystickInstanceID(sdlStick); joysticks->insert(joystickID, damncontroller); trackcontrollers.insert(joystickID, damncontroller); emit deviceUpdated(i, damncontroller); } } } // Make sure to decrement reference count SDL_JoystickClose(joystick); } } void InputDaemon::removeDevice(InputDevice *device) { if (device) { SDL_JoystickID deviceID = device->getSDLJoystickID(); joysticks->remove(deviceID); trackjoysticks.remove(deviceID); trackcontrollers.remove(deviceID); refreshIndexes(); emit deviceRemoved(deviceID); } } void InputDaemon::refreshIndexes() { for (int i = 0; i < SDL_NumJoysticks(); i++) { SDL_Joystick *joystick = SDL_JoystickOpen(i); SDL_JoystickID joystickID = SDL_JoystickInstanceID(joystick); // Make sure to decrement reference count SDL_JoystickClose(joystick); InputDevice *tempdevice = joysticks->value(joystickID); if (tempdevice) { tempdevice->setIndex(i); } } } void InputDaemon::addInputDevice(int index) { #ifdef USE_NEW_ADD // Check if device is considered a Game Controller at the start. if (SDL_IsGameController(index)) { SDL_GameController *controller = SDL_GameControllerOpen(index); if (controller) { SDL_Joystick *sdlStick = SDL_GameControllerGetJoystick(controller); SDL_JoystickID tempJoystickID = SDL_JoystickInstanceID(sdlStick); // Check if device has already been grabbed. if (!joysticks->contains(tempJoystickID)) { settings->getLock()->lock(); settings->beginGroup("Mappings"); QString temp; SDL_JoystickGUID tempGUID = SDL_JoystickGetGUID(sdlStick); char guidString[65] = {'0'}; SDL_JoystickGetGUIDString(tempGUID, guidString, sizeof(guidString)); temp = QString(guidString); bool disableGameController = settings->value(QString("%1Disable").arg(temp), false).toBool(); settings->endGroup(); settings->getLock()->unlock(); // Check if user has designated device Joystick mode. if (!disableGameController) { GameController *damncontroller = new GameController(controller, index, settings, this); connect(damncontroller, SIGNAL(requestWait()), eventWorker, SLOT(haltServices())); joysticks->insert(tempJoystickID, damncontroller); trackcontrollers.insert(tempJoystickID, damncontroller); Logger::LogInfo(QString("New game controller found - #%1 [%2]") .arg(index+1) .arg(QTime::currentTime().toString("hh:mm:ss.zzz"))); emit deviceAdded(damncontroller); } else { // Check if joystick is considered connected. /*SDL_Joystick *joystick = SDL_JoystickOpen(index); if (joystick) { SDL_JoystickID tempJoystickID = SDL_JoystickInstanceID(joystick); Joystick *curJoystick = new Joystick(joystick, index, settings, this); joysticks->insert(tempJoystickID, curJoystick); trackjoysticks.insert(tempJoystickID, curJoystick); emit deviceAdded(curJoystick); } */ Joystick *joystick = openJoystickDevice(index); if (joystick) { Logger::LogInfo(QString("New joystick found - #%1 [%2]") .arg(index+1) .arg(QTime::currentTime().toString("hh:mm:ss.zzz"))); emit deviceAdded(joystick); } } } else { // Make sure to decrement reference count SDL_GameControllerClose(controller); } } } else { // Check if joystick is considered connected. /*SDL_Joystick *joystick = SDL_JoystickOpen(index); if (joystick) { SDL_JoystickID tempJoystickID = SDL_JoystickInstanceID(joystick); Joystick *curJoystick = new Joystick(joystick, index, settings, this); joysticks->insert(tempJoystickID, curJoystick); trackjoysticks.insert(tempJoystickID, curJoystick); emit deviceAdded(curJoystick); } */ Joystick *joystick = openJoystickDevice(index); if (joystick) { Logger::LogInfo(QString("New joystick found - #%1 [%2]") .arg(index+1) .arg(QTime::currentTime().toString("hh:mm:ss.zzz"))); emit deviceAdded(joystick); } } #else SDL_Joystick *joystick = SDL_JoystickOpen(index); if (joystick) { SDL_JoystickID tempJoystickID = SDL_JoystickInstanceID(joystick); if (!joysticks->contains(tempJoystickID)) { settings->getLock()->lock(); settings->beginGroup("Mappings"); QString temp; SDL_JoystickGUID tempGUID = SDL_JoystickGetGUID(joystick); char guidString[65] = {'0'}; SDL_JoystickGetGUIDString(tempGUID, guidString, sizeof(guidString)); temp = QString(guidString); bool disableGameController = settings->value(QString("%1Disable").arg(temp), false).toBool(); if (SDL_IsGameController(index) && !disableGameController) { // Make sure to decrement reference count SDL_JoystickClose(joystick); SDL_GameController *controller = SDL_GameControllerOpen(index); if (controller) { SDL_Joystick *sdlStick = SDL_GameControllerGetJoystick(controller); SDL_JoystickID tempJoystickID = SDL_JoystickInstanceID(sdlStick); if (!joysticks->contains(tempJoystickID)) { GameController *damncontroller = new GameController(controller, index, settings, this); connect(damncontroller, SIGNAL(requestWait()), eventWorker, SLOT(haltServices())); joysticks->insert(tempJoystickID, damncontroller); trackcontrollers.insert(tempJoystickID, damncontroller); settings->endGroup(); settings->getLock()->unlock(); emit deviceAdded(damncontroller); } } else { settings->endGroup(); settings->getLock()->unlock(); } } else { Joystick *curJoystick = new Joystick(joystick, index, settings, this); joysticks->insert(tempJoystickID, curJoystick); trackjoysticks.insert(tempJoystickID, curJoystick); settings->endGroup(); settings->getLock()->unlock(); emit deviceAdded(curJoystick); } } else { // Make sure to decrement reference count SDL_JoystickClose(joystick); } } #endif } Joystick *InputDaemon::openJoystickDevice(int index) { // Check if joystick is considered connected. SDL_Joystick *joystick = SDL_JoystickOpen(index); Joystick *curJoystick = 0; if (joystick) { SDL_JoystickID tempJoystickID = SDL_JoystickInstanceID(joystick); curJoystick = new Joystick(joystick, index, settings, this); joysticks->insert(tempJoystickID, curJoystick); trackjoysticks.insert(tempJoystickID, curJoystick); } return curJoystick; } #endif InputDeviceBitArrayStatus* InputDaemon::createOrGrabBitStatusEntry(QHash *statusHash, InputDevice *device, bool readCurrent) { InputDeviceBitArrayStatus *bitArrayStatus = 0; if (!statusHash->contains(device)) { bitArrayStatus = new InputDeviceBitArrayStatus(device, readCurrent); statusHash->insert(device, bitArrayStatus); } else { bitArrayStatus = statusHash->value(device); } return bitArrayStatus; } void InputDaemon::firstInputPass(QQueue *sdlEventQueue) { SDL_Event event; while (SDL_PollEvent(&event) > 0) { switch (event.type) { case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: { #ifdef USE_SDL_2 InputDevice *joy = trackjoysticks.value(event.jbutton.which); #else InputDevice *joy = joysticks->value(event.jbutton.which); #endif if (joy) { SetJoystick* set = joy->getActiveSetJoystick(); JoyButton *button = set->getJoyButton(event.jbutton.button); if (button) { //InputDeviceBitArrayStatus *temp = createOrGrabBitStatusEntry(&releaseEventsGenerated, joy, false); //temp->changeButtonStatus(event.jbutton.button, event.type == SDL_JOYBUTTONUP); InputDeviceBitArrayStatus *pending = createOrGrabBitStatusEntry(&pendingEventValues, joy); pending->changeButtonStatus(event.jbutton.button, event.type == SDL_JOYBUTTONDOWN ? true : false); sdlEventQueue->append(event); } } #ifdef USE_SDL_2 else { sdlEventQueue->append(event); } #endif break; } case SDL_JOYAXISMOTION: { #ifdef USE_SDL_2 InputDevice *joy = trackjoysticks.value(event.jaxis.which); #else InputDevice *joy = joysticks->value(event.jaxis.which); #endif if (joy) { SetJoystick* set = joy->getActiveSetJoystick(); JoyAxis *axis = set->getJoyAxis(event.jaxis.axis); if (axis) { InputDeviceBitArrayStatus *temp = createOrGrabBitStatusEntry(&releaseEventsGenerated, joy, false); temp->changeAxesStatus(event.jaxis.axis, event.jaxis.axis == 0); InputDeviceBitArrayStatus *pending = createOrGrabBitStatusEntry(&pendingEventValues, joy); pending->changeAxesStatus(event.jaxis.axis, !axis->inDeadZone(event.jaxis.value)); sdlEventQueue->append(event); } } #ifdef USE_SDL_2 else { sdlEventQueue->append(event); } #endif break; } case SDL_JOYHATMOTION: { #ifdef USE_SDL_2 InputDevice *joy = trackjoysticks.value(event.jhat.which); #else InputDevice *joy = joysticks->value(event.jhat.which); #endif if (joy) { SetJoystick* set = joy->getActiveSetJoystick(); JoyDPad *dpad = set->getJoyDPad(event.jhat.hat); if (dpad) { //InputDeviceBitArrayStatus *temp = createOrGrabBitStatusEntry(&releaseEventsGenerated, joy, false); //temp->changeHatStatus(event.jhat.hat, event.jhat.value == 0); InputDeviceBitArrayStatus *pending = createOrGrabBitStatusEntry(&pendingEventValues, joy); pending->changeHatStatus(event.jhat.hat, event.jhat.value != 0 ? true : false); sdlEventQueue->append(event); } } #ifdef USE_SDL_2 else { sdlEventQueue->append(event); } #endif break; } #ifdef USE_SDL_2 case SDL_CONTROLLERAXISMOTION: { InputDevice *joy = trackcontrollers.value(event.caxis.which); if (joy) { SetJoystick* set = joy->getActiveSetJoystick(); JoyAxis *axis = set->getJoyAxis(event.caxis.axis); if (axis) { InputDeviceBitArrayStatus *temp = createOrGrabBitStatusEntry(&releaseEventsGenerated, joy, false); if (event.caxis.axis != SDL_CONTROLLER_AXIS_TRIGGERLEFT && event.caxis.axis != SDL_CONTROLLER_AXIS_TRIGGERRIGHT) { temp->changeAxesStatus(event.caxis.axis, event.caxis.value == 0); } else { temp->changeAxesStatus(event.caxis.axis, event.caxis.value == GAMECONTROLLERTRIGGERRELEASE); } InputDeviceBitArrayStatus *pending = createOrGrabBitStatusEntry(&pendingEventValues, joy); pending->changeAxesStatus(event.caxis.axis, !axis->inDeadZone(event.caxis.value)); sdlEventQueue->append(event); } } break; } case SDL_CONTROLLERBUTTONDOWN: case SDL_CONTROLLERBUTTONUP: { InputDevice *joy = trackcontrollers.value(event.cbutton.which); if (joy) { SetJoystick* set = joy->getActiveSetJoystick(); JoyButton *button = set->getJoyButton(event.cbutton.button); if (button) { //InputDeviceBitArrayStatus *temp = createOrGrabBitStatusEntry(&releaseEventsGenerated, joy, false); //temp->changeButtonStatus(event.cbutton.button, event.type == SDL_CONTROLLERBUTTONUP); InputDeviceBitArrayStatus *pending = createOrGrabBitStatusEntry(&pendingEventValues, joy); pending->changeButtonStatus(event.cbutton.button, event.type == SDL_CONTROLLERBUTTONDOWN ? true : false); sdlEventQueue->append(event); } } break; } case SDL_JOYDEVICEREMOVED: case SDL_JOYDEVICEADDED: { sdlEventQueue->append(event); break; } #endif case SDL_QUIT: { sdlEventQueue->append(event); break; } } } } #ifdef USE_SDL_2 void InputDaemon::modifyUnplugEvents(QQueue *sdlEventQueue) { QHashIterator genIter(releaseEventsGenerated); while (genIter.hasNext()) { genIter.next(); InputDevice *device = genIter.key(); InputDeviceBitArrayStatus *generatedTemp = genIter.value(); QBitArray tempBitArray = generatedTemp->generateFinalBitArray(); //qDebug() << "ARRAY: " << tempBitArray; unsigned int bitArraySize = tempBitArray.size(); //qDebug() << "ARRAY SIZE: " << bitArraySize; if (bitArraySize > 0 && tempBitArray.count(true) == device->getNumberAxes()) { if (pendingEventValues.contains(device)) { InputDeviceBitArrayStatus *pendingTemp = pendingEventValues.value(device); QBitArray pendingBitArray = pendingTemp->generateFinalBitArray(); QBitArray unplugBitArray = createUnplugEventBitArray(device); unsigned int pendingBitArraySize = pendingBitArray.size(); if (bitArraySize == pendingBitArraySize && pendingBitArray == unplugBitArray) { QQueue tempQueue; while (!sdlEventQueue->isEmpty()) { SDL_Event event = sdlEventQueue->dequeue(); switch (event.type) { case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: { tempQueue.enqueue(event); break; } case SDL_JOYAXISMOTION: { if (event.jaxis.which != device->getSDLJoystickID()) { tempQueue.enqueue(event); } else { InputDevice *joy = trackjoysticks.value(event.jaxis.which); if (joy) { JoyAxis *axis = joy->getActiveSetJoystick()->getJoyAxis(event.jaxis.axis); if (axis) { if (axis->getThrottle() != JoyAxis::NormalThrottle) { event.jaxis.value = axis->getProperReleaseValue(); } } } tempQueue.enqueue(event); } break; } case SDL_JOYHATMOTION: { tempQueue.enqueue(event); break; } case SDL_CONTROLLERAXISMOTION: { if (event.caxis.which != device->getSDLJoystickID()) { tempQueue.enqueue(event); } else { InputDevice *joy = trackcontrollers.value(event.caxis.which); if (joy) { SetJoystick* set = joy->getActiveSetJoystick(); JoyAxis *axis = set->getJoyAxis(event.caxis.axis); if (axis) { if (event.caxis.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT || event.caxis.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) { event.caxis.value = axis->getProperReleaseValue(); } } } tempQueue.enqueue(event); } break; } case SDL_CONTROLLERBUTTONDOWN: case SDL_CONTROLLERBUTTONUP: { tempQueue.enqueue(event); break; } case SDL_JOYDEVICEREMOVED: case SDL_JOYDEVICEADDED: { tempQueue.enqueue(event); break; } default: { tempQueue.enqueue(event); } } } sdlEventQueue->swap(tempQueue); } } } } } #endif #ifdef USE_SDL_2 QBitArray InputDaemon::createUnplugEventBitArray(InputDevice *device) { InputDeviceBitArrayStatus tempStatus(device, false); for (int i=0; i < device->getNumberRawAxes(); i++) { JoyAxis *axis = device->getActiveSetJoystick()->getJoyAxis(i); if (axis && axis->getThrottle() != JoyAxis::NormalThrottle) { tempStatus.changeAxesStatus(i, true); } } QBitArray unplugBitArray = tempStatus.generateFinalBitArray(); return unplugBitArray; } #endif void InputDaemon::secondInputPass(QQueue *sdlEventQueue) { QHash activeDevices; while (!sdlEventQueue->isEmpty()) { SDL_Event event = sdlEventQueue->dequeue(); switch (event.type) { //qDebug() << QTime::currentTime() << " :"; case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: { #ifdef USE_SDL_2 InputDevice *joy = trackjoysticks.value(event.jbutton.which); #else InputDevice *joy = joysticks->value(event.jbutton.which); #endif if (joy) { SetJoystick* set = joy->getActiveSetJoystick(); JoyButton *button = set->getJoyButton(event.jbutton.button); if (button) { //button->joyEvent(event.type == SDL_JOYBUTTONDOWN ? true : false); button->queuePendingEvent(event.type == SDL_JOYBUTTONDOWN ? true : false); if (!activeDevices.contains(event.jbutton.which)) { activeDevices.insert(event.jbutton.which, joy); } } } #ifdef USE_SDL_2 else if (trackcontrollers.contains(event.jbutton.which)) { GameController *gamepad = trackcontrollers.value(event.jbutton.which); gamepad->rawButtonEvent(event.jbutton.button, event.type == SDL_JOYBUTTONDOWN ? true : false); } #endif break; } case SDL_JOYAXISMOTION: { #ifdef USE_SDL_2 InputDevice *joy = trackjoysticks.value(event.jaxis.which); #else InputDevice *joy = joysticks->value(event.jaxis.which); #endif if (joy) { SetJoystick* set = joy->getActiveSetJoystick(); JoyAxis *axis = set->getJoyAxis(event.jaxis.axis); if (axis) { //axis->joyEvent(event.jaxis.value); axis->queuePendingEvent(event.jaxis.value); if (!activeDevices.contains(event.jaxis.which)) { activeDevices.insert(event.jaxis.which, joy); } } joy->rawAxisEvent(event.jaxis.which, event.jaxis.value); } #ifdef USE_SDL_2 else if (trackcontrollers.contains(event.jaxis.which)) { GameController *gamepad = trackcontrollers.value(event.jaxis.which); gamepad->rawAxisEvent(event.jaxis.axis, event.jaxis.value); } #endif break; } case SDL_JOYHATMOTION: { #ifdef USE_SDL_2 InputDevice *joy = trackjoysticks.value(event.jhat.which); #else InputDevice *joy = joysticks->value(event.jhat.which); #endif if (joy) { SetJoystick* set = joy->getActiveSetJoystick(); JoyDPad *dpad = set->getJoyDPad(event.jhat.hat); if (dpad) { //dpad->joyEvent(event.jhat.value); dpad->joyEvent(event.jhat.value); if (!activeDevices.contains(event.jhat.which)) { activeDevices.insert(event.jhat.which, joy); } } } #ifdef USE_SDL_2 else if (trackcontrollers.contains(event.jhat.which)) { GameController *gamepad = trackcontrollers.value(event.jaxis.which); gamepad->rawDPadEvent(event.jhat.hat, event.jhat.value); } #endif break; } #ifdef USE_SDL_2 case SDL_CONTROLLERAXISMOTION: { InputDevice *joy = trackcontrollers.value(event.caxis.which); if (joy) { SetJoystick* set = joy->getActiveSetJoystick(); JoyAxis *axis = set->getJoyAxis(event.caxis.axis); if (axis) { //qDebug() << QTime::currentTime() << ": " << "Axis " << event.caxis.axis+1 // << ": " << event.caxis.value; //axis->joyEvent(event.caxis.value); axis->queuePendingEvent(event.caxis.value); if (!activeDevices.contains(event.caxis.which)) { activeDevices.insert(event.caxis.which, joy); } } } break; } case SDL_CONTROLLERBUTTONDOWN: case SDL_CONTROLLERBUTTONUP: { InputDevice *joy = trackcontrollers.value(event.cbutton.which); if (joy) { SetJoystick* set = joy->getActiveSetJoystick(); JoyButton *button = set->getJoyButton(event.cbutton.button); if (button) { //button->joyEvent(event.type == SDL_CONTROLLERBUTTONDOWN ? true : false); button->queuePendingEvent(event.type == SDL_CONTROLLERBUTTONDOWN ? true : false); if (!activeDevices.contains(event.cbutton.which)) { activeDevices.insert(event.cbutton.which, joy); } } } break; } case SDL_JOYDEVICEREMOVED: { InputDevice *device = joysticks->value(event.jdevice.which); if (device) { Logger::LogInfo(QString("Removing joystick #%1 [%2]") .arg(device->getRealJoyNumber()) .arg(QTime::currentTime().toString("hh:mm:ss.zzz"))); //activeDevices.remove(event.jdevice.which); removeDevice(device); } break; } case SDL_JOYDEVICEADDED: { addInputDevice(event.jdevice.which); break; } #endif case SDL_QUIT: { stopped = true; break; } default: break; } // Active possible queued events. QHashIterator activeDevIter(activeDevices); while (activeDevIter.hasNext()) { InputDevice *tempDevice = activeDevIter.next().value(); tempDevice->activatePossibleControlStickEvents(); tempDevice->activatePossibleAxisEvents(); tempDevice->activatePossibleDPadEvents(); tempDevice->activatePossibleVDPadEvents(); tempDevice->activatePossibleButtonEvents(); } if (JoyButton::shouldInvokeMouseEvents()) { // Do not wait for next event loop run. Execute immediately. JoyButton::invokeMouseEvents(); } } } void InputDaemon::clearBitArrayStatusInstances() { QHashIterator genIter(releaseEventsGenerated); while (genIter.hasNext()) { InputDeviceBitArrayStatus *temp = genIter.next().value(); if (temp) { delete temp; temp = 0; } } releaseEventsGenerated.clear(); QHashIterator pendIter(pendingEventValues); while (pendIter.hasNext()) { InputDeviceBitArrayStatus *temp = pendIter.next().value(); if (temp) { delete temp; temp = 0; } } pendingEventValues.clear(); } void InputDaemon::resetActiveButtonMouseDistances() { pollResetTimer.stop(); JoyButton::resetActiveButtonMouseDistances(); } void InputDaemon::updatePollResetRate(unsigned int tempPollRate) { Q_UNUSED(tempPollRate); bool wasActive = pollResetTimer.isActive(); pollResetTimer.stop(); pollResetTimer.setInterval( qMax(JoyButton::getMouseRefreshRate(), JoyButton::getGamepadRefreshRate()) + 1); if (wasActive) { pollResetTimer.start(); } } antimicro-2.23/src/inputdaemon.h000066400000000000000000000067021300750276700167240ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef INPUTDAEMONTHREAD_H #define INPUTDAEMONTHREAD_H #include #include #include #include #ifdef USE_SDL_2 #include #include #include "gamecontroller/gamecontroller.h" #else #include #include #endif #include "joystick.h" #include "sdleventreader.h" #include "antimicrosettings.h" #include "inputdevicebitarraystatus.h" class InputDaemon : public QObject { Q_OBJECT public: explicit InputDaemon (QMap *joysticks, AntiMicroSettings *settings, bool graphical=true, QObject *parent=0); ~InputDaemon(); protected: InputDeviceBitArrayStatus* createOrGrabBitStatusEntry( QHash *statusHash, InputDevice *device, bool readCurrent=true); void firstInputPass(QQueue *sdlEventQueue); void secondInputPass(QQueue *sdlEventQueue); #ifdef USE_SDL_2 void modifyUnplugEvents(QQueue *sdlEventQueue); QBitArray createUnplugEventBitArray(InputDevice *device); Joystick* openJoystickDevice(int index); #endif void clearBitArrayStatusInstances(); QMap *joysticks; #ifdef USE_SDL_2 QHash trackjoysticks; QHash trackcontrollers; #endif QHash releaseEventsGenerated; QHash pendingEventValues; bool stopped; bool graphical; SDLEventReader *eventWorker; QThread *sdlWorkerThread; AntiMicroSettings *settings; QTimer pollResetTimer; static const int GAMECONTROLLERTRIGGERRELEASE; signals: void joystickRefreshed (InputDevice *joystick); void joysticksRefreshed(QMap *joysticks); void complete(InputDevice *joystick); void complete(); #ifdef USE_SDL_2 void deviceUpdated(int index, InputDevice *device); void deviceRemoved(SDL_JoystickID deviceID); void deviceAdded(InputDevice *device); #endif public slots: void run(); void quit(); void refresh(); void refreshJoystick(InputDevice *joystick); void refreshJoysticks(); void deleteJoysticks(); void startWorker(); #ifdef USE_SDL_2 void refreshMapping(QString mapping, InputDevice *device); void removeDevice(InputDevice *device); void addInputDevice(int index); void refreshIndexes(); #endif private slots: void stop(); void resetActiveButtonMouseDistances(); void updatePollResetRate(unsigned int tempPollRate); }; #endif // INPUTDAEMONTHREAD_H antimicro-2.23/src/inputdevice.cpp000066400000000000000000002355261300750276700172630ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include "inputdevice.h" const int InputDevice::NUMBER_JOYSETS = 8; const int InputDevice::DEFAULTKEYPRESSTIME = 100; const unsigned int InputDevice::DEFAULTKEYREPEATDELAY = 660; // 660 ms const unsigned int InputDevice::DEFAULTKEYREPEATRATE = 40; // 40 ms. 25 times per second const int InputDevice::RAISEDDEADZONE = 20000; QRegExp InputDevice::emptyGUID("^[0]+$"); InputDevice::InputDevice(int deviceIndex, AntiMicroSettings *settings, QObject *parent) : QObject(parent) { buttonDownCount = 0; joyNumber = deviceIndex; active_set = 0; joystickID = 0; keyPressTime = 0; deviceEdited = false; #ifdef Q_OS_WIN keyRepeatEnabled = true; #else keyRepeatEnabled = false; #endif keyRepeatDelay = 0; keyRepeatRate = 0; rawAxisDeadZone = RAISEDDEADZONE; this->settings = settings; } InputDevice::~InputDevice() { QHashIterator iter(joystick_sets); while (iter.hasNext()) { SetJoystick *setjoystick = iter.next().value(); if (setjoystick) { delete setjoystick; setjoystick = 0; } } joystick_sets.clear(); } int InputDevice::getJoyNumber() { return joyNumber; } int InputDevice::getRealJoyNumber() { int joynumber = getJoyNumber(); return joynumber + 1; } void InputDevice::reset() { resetButtonDownCount(); deviceEdited = false; profileName = ""; //cali.clear(); //buttonstates.clear(); //axesstates.clear(); //dpadstates.clear(); for (int i=0; i < NUMBER_JOYSETS; i++) { SetJoystick* set = joystick_sets.value(i); set->reset(); } } /** * @brief Obtain current joystick element values, create new SetJoystick objects, * and then transfer most recent joystick element values to new * current set. */ void InputDevice::transferReset() { // Grab current states for all elements in old set SetJoystick *current_set = joystick_sets.value(active_set); for (int i = 0; i < current_set->getNumberButtons(); i++) { JoyButton *button = current_set->getJoyButton(i); buttonstates.append(button->getButtonState()); } for (int i = 0; i < current_set->getNumberAxes(); i++) { JoyAxis *axis = current_set->getJoyAxis(i); axesstates.append(axis->getCurrentRawValue()); } for (int i = 0; i < current_set->getNumberHats(); i++) { JoyDPad *dpad = current_set->getJoyDPad(i); dpadstates.append(dpad->getCurrentDirection()); } reset(); } void InputDevice::reInitButtons() { SetJoystick *current_set = joystick_sets.value(active_set); for (int i = 0; i < current_set->getNumberButtons(); i++) { bool value = buttonstates.at(i); JoyButton *button = current_set->getJoyButton(i); //button->joyEvent(value); button->queuePendingEvent(value); } for (int i = 0; i < current_set->getNumberAxes(); i++) { int value = axesstates.at(i); JoyAxis *axis = current_set->getJoyAxis(i); //axis->joyEvent(value); axis->queuePendingEvent(value); } for (int i = 0; i < current_set->getNumberHats(); i++) { int value = dpadstates.at(i); JoyDPad *dpad = current_set->getJoyDPad(i); //dpad->joyEvent(value); dpad->queuePendingEvent(value); } activatePossibleControlStickEvents(); activatePossibleAxisEvents(); activatePossibleDPadEvents(); activatePossibleVDPadEvents(); activatePossibleButtonEvents(); buttonstates.clear(); axesstates.clear(); dpadstates.clear(); } void InputDevice::setActiveSetNumber(int index) { if ((index >= 0 && index < NUMBER_JOYSETS) && (index != active_set)) { QList buttonstates; QList axesstates; QList dpadstates; QList stickstates; QList vdpadstates; // Grab current states for all elements in old set SetJoystick *current_set = joystick_sets.value(active_set); SetJoystick *old_set = current_set; SetJoystick *tempSet = joystick_sets.value(index); for (int i = 0; i < current_set->getNumberButtons(); i++) { JoyButton *button = current_set->getJoyButton(i); buttonstates.append(button->getButtonState()); tempSet->getJoyButton(i)->copyLastMouseDistanceFromDeadZone(button); tempSet->getJoyButton(i)->copyLastAccelerationDistance(button); tempSet->getJoyButton(i)->setUpdateInitAccel(false); } for (int i = 0; i < current_set->getNumberAxes(); i++) { JoyAxis *axis = current_set->getJoyAxis(i); axesstates.append(axis->getCurrentRawValue()); tempSet->getJoyAxis(i)->copyRawValues(axis); tempSet->getJoyAxis(i)->copyThrottledValues(axis); JoyAxisButton *button = tempSet->getJoyAxis(i)->getAxisButtonByValue(axis->getCurrentRawValue()); if (button) { button->setUpdateInitAccel(false); } } for (int i = 0; i < current_set->getNumberHats(); i++) { JoyDPad *dpad = current_set->getJoyDPad(i); dpadstates.append(dpad->getCurrentDirection()); JoyDPadButton::JoyDPadDirections tempDir = static_cast(dpad->getCurrentDirection()); tempSet->getJoyDPad(i)->setDirButtonsUpdateInitAccel(tempDir, false); tempSet->getJoyDPad(i)->copyLastDistanceValues(dpad); } for (int i=0; i < current_set->getNumberSticks(); i++) { // Last distances for elements are taken from associated axes. // Copying is not required here. JoyControlStick *stick = current_set->getJoyStick(i); stickstates.append(stick->getCurrentDirection()); tempSet->getJoyStick(i)->setDirButtonsUpdateInitAccel(stick->getCurrentDirection(), false); } for (int i = 0; i < current_set->getNumberVDPads(); i++) { JoyDPad *dpad = current_set->getVDPad(i); vdpadstates.append(dpad->getCurrentDirection()); JoyDPadButton::JoyDPadDirections tempDir = static_cast(dpad->getCurrentDirection()); tempSet->getVDPad(i)->setDirButtonsUpdateInitAccel(tempDir, false); tempSet->getVDPad(i)->copyLastDistanceValues(dpad); } // Release all current pressed elements and change set number joystick_sets.value(active_set)->release(); active_set = index; // Activate all buttons in the switched set current_set = joystick_sets.value(active_set); for (int i=0; i < current_set->getNumberSticks(); i++) { JoyControlStick::JoyStickDirections value = stickstates.at(i); //bool tempignore = true; bool tempignore = false; QList buttonList; QList oldButtonList; JoyControlStick *stick = current_set->getJoyStick(i); JoyControlStick *oldStick = old_set->getJoyStick(i); if (stick->getJoyMode() == JoyControlStick::StandardMode && value) { switch (value) { case JoyControlStick::StickRightUp: { buttonList.append(stick->getDirectionButton(JoyControlStick::StickUp)); buttonList.append(stick->getDirectionButton(JoyControlStick::StickRight)); oldButtonList.append(oldStick->getDirectionButton(JoyControlStick::StickUp)); oldButtonList.append(oldStick->getDirectionButton(JoyControlStick::StickRight)); break; } case JoyControlStick::StickRightDown: { buttonList.append(stick->getDirectionButton(JoyControlStick::StickRight)); buttonList.append(stick->getDirectionButton(JoyControlStick::StickDown)); oldButtonList.append(oldStick->getDirectionButton(JoyControlStick::StickRight)); oldButtonList.append(oldStick->getDirectionButton(JoyControlStick::StickDown)); break; } case JoyControlStick::StickLeftDown: { buttonList.append(stick->getDirectionButton(JoyControlStick::StickDown)); buttonList.append(stick->getDirectionButton(JoyControlStick::StickLeft)); oldButtonList.append(oldStick->getDirectionButton(JoyControlStick::StickDown)); oldButtonList.append(oldStick->getDirectionButton(JoyControlStick::StickLeft)); break; } case JoyControlStick::StickLeftUp: { buttonList.append(stick->getDirectionButton(JoyControlStick::StickLeft)); buttonList.append(stick->getDirectionButton(JoyControlStick::StickUp)); oldButtonList.append(oldStick->getDirectionButton(JoyControlStick::StickLeft)); oldButtonList.append(oldStick->getDirectionButton(JoyControlStick::StickUp)); break; } default: { buttonList.append(stick->getDirectionButton(value)); oldButtonList.append(oldStick->getDirectionButton(value)); } } } else if (value) { buttonList.append(stick->getDirectionButton(value)); oldButtonList.append(oldStick->getDirectionButton(value)); } QHashIterator iter(*stick->getButtons()); while (iter.hasNext()) { JoyControlStickButton *tempButton = iter.next().value(); if (!buttonList.contains(tempButton)) { tempButton->setWhileHeldStatus(false); } } for (int j=0; j < buttonList.size(); j++) { JoyControlStickButton *button = buttonList.at(j); JoyControlStickButton *oldButton = oldButtonList.at(j); if (button && oldButton) { if (button->getChangeSetCondition() == JoyButton::SetChangeWhileHeld) { if (oldButton->getChangeSetCondition() == JoyButton::SetChangeWhileHeld && oldButton->getWhileHeldStatus()) { // Button from old set involved in a while held set // change. Carry over to new set button to ensure // set changes are done in the proper order. button->setWhileHeldStatus(true); } else if (!button->getWhileHeldStatus()) { // Ensure that set change events are performed if needed. tempignore = false; } } } } } // Activate all dpad buttons in the switched set for (int i = 0; i < current_set->getNumberVDPads(); i++) { int value = vdpadstates.at(i); //bool tempignore = true; bool tempignore = false; JoyDPad *dpad = current_set->getVDPad(i); QList buttonList; QList oldButtonList; if (dpad->getJoyMode() == JoyDPad::StandardMode && value) { switch (value) { case JoyDPadButton::DpadRightUp: { buttonList.append(dpad->getJoyButton(JoyDPadButton::DpadUp)); buttonList.append(dpad->getJoyButton(JoyDPadButton::DpadRight)); oldButtonList.append(old_set->getVDPad(i)->getJoyButton(JoyDPadButton::DpadUp)); oldButtonList.append(old_set->getVDPad(i)->getJoyButton(JoyDPadButton::DpadRight)); break; } case JoyDPadButton::DpadRightDown: { buttonList.append(dpad->getJoyButton(JoyDPadButton::DpadRight)); buttonList.append(dpad->getJoyButton(JoyDPadButton::DpadDown)); oldButtonList.append(old_set->getVDPad(i)->getJoyButton(JoyDPadButton::DpadRight)); oldButtonList.append(old_set->getVDPad(i)->getJoyButton(JoyDPadButton::DpadDown)); break; } case JoyDPadButton::DpadLeftDown: { buttonList.append(dpad->getJoyButton(JoyDPadButton::DpadDown)); buttonList.append(dpad->getJoyButton(JoyDPadButton::DpadLeft)); oldButtonList.append(old_set->getVDPad(i)->getJoyButton(JoyDPadButton::DpadDown)); oldButtonList.append(old_set->getVDPad(i)->getJoyButton(JoyDPadButton::DpadLeft)); break; } case JoyDPadButton::DpadLeftUp: { buttonList.append(dpad->getJoyButton(JoyDPadButton::DpadLeft)); buttonList.append(dpad->getJoyButton(JoyDPadButton::DpadUp)); oldButtonList.append(old_set->getVDPad(i)->getJoyButton(JoyDPadButton::DpadLeft)); oldButtonList.append(old_set->getVDPad(i)->getJoyButton(JoyDPadButton::DpadUp)); break; } default: { buttonList.append(dpad->getJoyButton(value)); oldButtonList.append(old_set->getVDPad(i)->getJoyButton(value)); } } } else if (value) { buttonList.append(dpad->getJoyButton(value)); oldButtonList.append(old_set->getVDPad(i)->getJoyButton(value)); } QHashIterator iter(*dpad->getJoyButtons()); while (iter.hasNext()) { // Ensure that set change events are performed if needed. JoyDPadButton *button = iter.next().value(); if (!buttonList.contains(button)) { button->setWhileHeldStatus(false); } } for (int j=0; j < buttonList.size(); j++) { JoyDPadButton *button = buttonList.at(j); JoyDPadButton *oldButton = oldButtonList.at(j); if (button && oldButton) { if (button->getChangeSetCondition() == JoyButton::SetChangeWhileHeld) { if (value) { if (oldButton->getChangeSetCondition() == JoyButton::SetChangeWhileHeld && oldButton->getWhileHeldStatus()) { // Button from old set involved in a while held set // change. Carry over to new set button to ensure // set changes are done in the proper order. button->setWhileHeldStatus(true); } else if (!button->getWhileHeldStatus()) { // Ensure that set change events are performed if needed. tempignore = false; } } else { button->setWhileHeldStatus(false); } } } } } for (int i = 0; i < current_set->getNumberButtons(); i++) { bool value = buttonstates.at(i); //bool tempignore = true; bool tempignore = false; JoyButton *button = current_set->getJoyButton(i); JoyButton *oldButton = old_set->getJoyButton(i); if (button->getChangeSetCondition() == JoyButton::SetChangeWhileHeld) { if (value) { if (oldButton->getChangeSetCondition() == JoyButton::SetChangeWhileHeld && oldButton->getWhileHeldStatus()) { // Button from old set involved in a while held set // change. Carry over to new set button to ensure // set changes are done in the proper order. button->setWhileHeldStatus(true); } else if (!button->getWhileHeldStatus()) { // Ensure that set change events are performed if needed. tempignore = false; } } else { // Ensure that set change events are performed if needed. button->setWhileHeldStatus(false); //tempignore = false; } } //button->joyEvent(value, tempignore); button->queuePendingEvent(value, tempignore); } // Activate all axis buttons in the switched set for (int i = 0; i < current_set->getNumberAxes(); i++) { int value = axesstates.at(i); //bool tempignore = true; bool tempignore = false; JoyAxis *axis = current_set->getJoyAxis(i); JoyAxisButton *oldButton = old_set->getJoyAxis(i)->getAxisButtonByValue(value); JoyAxisButton *button = axis->getAxisButtonByValue(value); if (button && oldButton) { if (button->getChangeSetCondition() == JoyButton::SetChangeWhileHeld) { if (oldButton->getChangeSetCondition() == JoyButton::SetChangeWhileHeld && oldButton->getWhileHeldStatus()) { // Button from old set involved in a while held set // change. Carry over to new set button to ensure // set changes are done in the proper order. button->setWhileHeldStatus(true); } else if (!button->getWhileHeldStatus()) { // Ensure that set change events are performed if needed. tempignore = false; } } } else if (!button) { // Ensure that set change events are performed if needed. axis->getPAxisButton()->setWhileHeldStatus(false); axis->getNAxisButton()->setWhileHeldStatus(false); } //axis->joyEvent(value, tempignore); axis->queuePendingEvent(value, tempignore, false); } // Activate all dpad buttons in the switched set for (int i = 0; i < current_set->getNumberHats(); i++) { int value = dpadstates.at(i); //bool tempignore = true; bool tempignore = false; JoyDPad *dpad = current_set->getJoyDPad(i); QList buttonList; QList oldButtonList; if (dpad->getJoyMode() == JoyDPad::StandardMode && value) { switch (value) { case JoyDPadButton::DpadRightUp: { buttonList.append(dpad->getJoyButton(JoyDPadButton::DpadUp)); buttonList.append(dpad->getJoyButton(JoyDPadButton::DpadRight)); oldButtonList.append(old_set->getJoyDPad(i)->getJoyButton(JoyDPadButton::DpadUp)); oldButtonList.append(old_set->getJoyDPad(i)->getJoyButton(JoyDPadButton::DpadRight)); break; } case JoyDPadButton::DpadRightDown: { buttonList.append(dpad->getJoyButton(JoyDPadButton::DpadRight)); buttonList.append(dpad->getJoyButton(JoyDPadButton::DpadDown)); oldButtonList.append(old_set->getJoyDPad(i)->getJoyButton(JoyDPadButton::DpadRight)); oldButtonList.append(old_set->getJoyDPad(i)->getJoyButton(JoyDPadButton::DpadDown)); break; } case JoyDPadButton::DpadLeftDown: { buttonList.append(dpad->getJoyButton(JoyDPadButton::DpadDown)); buttonList.append(dpad->getJoyButton(JoyDPadButton::DpadLeft)); oldButtonList.append(old_set->getJoyDPad(i)->getJoyButton(JoyDPadButton::DpadDown)); oldButtonList.append(old_set->getJoyDPad(i)->getJoyButton(JoyDPadButton::DpadLeft)); break; } case JoyDPadButton::DpadLeftUp: { buttonList.append(dpad->getJoyButton(JoyDPadButton::DpadLeft)); buttonList.append(dpad->getJoyButton(JoyDPadButton::DpadUp)); oldButtonList.append(old_set->getJoyDPad(i)->getJoyButton(JoyDPadButton::DpadLeft)); oldButtonList.append(old_set->getJoyDPad(i)->getJoyButton(JoyDPadButton::DpadUp)); break; } default: { buttonList.append(dpad->getJoyButton(value)); oldButtonList.append(old_set->getJoyDPad(i)->getJoyButton(value)); } } } else if (value) { buttonList.append(dpad->getJoyButton(value)); oldButtonList.append(old_set->getJoyDPad(i)->getJoyButton(value)); } QHashIterator iter(*dpad->getJoyButtons()); while (iter.hasNext()) { // Ensure that set change events are performed if needed. JoyDPadButton *button = iter.next().value(); if (!buttonList.contains(button)) { button->setWhileHeldStatus(false); } } for (int j=0; j < buttonList.size(); j++) { JoyDPadButton *button = buttonList.at(j); JoyDPadButton *oldButton = oldButtonList.at(j); if (button && oldButton) { if (button->getChangeSetCondition() == JoyButton::SetChangeWhileHeld) { if (value) { if (oldButton->getChangeSetCondition() == JoyButton::SetChangeWhileHeld && oldButton->getWhileHeldStatus()) { // Button from old set involved in a while held set // change. Carry over to new set button to ensure // set changes are done in the proper order. button->setWhileHeldStatus(true); } else if (!button->getWhileHeldStatus()) { // Ensure that set change events are performed if needed. tempignore = false; } } else { button->setWhileHeldStatus(false); } } } } //dpad->joyEvent(value, tempignore); dpad->queuePendingEvent(value, tempignore); } activatePossibleControlStickEvents(); activatePossibleAxisEvents(); activatePossibleDPadEvents(); activatePossibleVDPadEvents(); activatePossibleButtonEvents(); /*if (JoyButton::shouldInvokeMouseEvents()) { // Run mouse events early if needed. JoyButton::invokeMouseEvents(); } */ } } int InputDevice::getActiveSetNumber() { return active_set; } SetJoystick* InputDevice::getActiveSetJoystick() { return joystick_sets.value(active_set); } int InputDevice::getNumberButtons() { return getActiveSetJoystick()->getNumberButtons(); } int InputDevice::getNumberAxes() { return getActiveSetJoystick()->getNumberAxes(); } int InputDevice::getNumberHats() { return getActiveSetJoystick()->getNumberHats(); } int InputDevice::getNumberSticks() { return getActiveSetJoystick()->getNumberSticks(); } int InputDevice::getNumberVDPads() { return getActiveSetJoystick()->getNumberVDPads(); } SetJoystick* InputDevice::getSetJoystick(int index) { return joystick_sets.value(index); } void InputDevice::propogateSetChange(int index) { emit setChangeActivated(index); } void InputDevice::changeSetButtonAssociation(int button_index, int originset, int newset, int mode) { JoyButton *button = joystick_sets.value(newset)->getJoyButton(button_index); JoyButton::SetChangeCondition tempmode = (JoyButton::SetChangeCondition)mode; button->setChangeSetSelection(originset); button->setChangeSetCondition(tempmode, true); } void InputDevice::readConfig(QXmlStreamReader *xml) { if (xml->isStartElement() && xml->name() == getXmlName()) { //reset(); transferReset(); xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != getXmlName())) { if (xml->name() == "sets" && xml->isStartElement()) { xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "sets")) { if (xml->name() == "set" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); index = index - 1; if (index >= 0 && index < joystick_sets.size()) { joystick_sets.value(index)->readConfig(xml); } } else { // If none of the above, skip the element xml->skipCurrentElement(); } xml->readNextStartElement(); } } else if (xml->name() == "stickAxisAssociation" && xml->isStartElement()) { int stickIndex = xml->attributes().value("index").toString().toInt(); int xAxis = xml->attributes().value("xAxis").toString().toInt(); int yAxis = xml->attributes().value("yAxis").toString().toInt(); if (stickIndex > 0 && xAxis > 0 && yAxis > 0) { xAxis -= 1; yAxis -= 1; stickIndex -= 1; for (int i=0; i getJoyAxis(xAxis); JoyAxis *axis2 = currentset->getJoyAxis(yAxis); if (axis1 && axis2) { JoyControlStick *stick = new JoyControlStick(axis1, axis2, stickIndex, i, this); currentset->addControlStick(stickIndex, stick); } } xml->readNext(); } else { xml->skipCurrentElement(); } } else if (xml->name() == "vdpadButtonAssociations" && xml->isStartElement()) { int vdpadIndex = xml->attributes().value("index").toString().toInt(); if (vdpadIndex > 0) { for (int i=0; i getVDPad(vdpadIndex-1); if (!vdpad) { vdpad = new VDPad(vdpadIndex-1, i, currentset, currentset); currentset->addVDPad(vdpadIndex-1, vdpad); } } xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "vdpadButtonAssociations")) { if (xml->name() == "vdpadButtonAssociation" && xml->isStartElement()) { int vdpadAxisIndex = xml->attributes().value("axis").toString().toInt(); int vdpadButtonIndex = xml->attributes().value("button").toString().toInt(); int vdpadDirection = xml->attributes().value("direction").toString().toInt(); if (vdpadAxisIndex > 0 && vdpadDirection > 0) { vdpadAxisIndex -= 1; for (int i=0; i < joystick_sets.size(); i++) { SetJoystick *currentset = joystick_sets.value(i); VDPad *vdpad = currentset->getVDPad(vdpadIndex-1); if (vdpad) { JoyAxis *axis = currentset->getJoyAxis(vdpadAxisIndex); if (axis) { JoyButton *button = 0; if (vdpadButtonIndex == 0) { button = axis->getNAxisButton(); } else if (vdpadButtonIndex == 1) { button = axis->getPAxisButton(); } if (button) { vdpad->addVButton((JoyDPadButton::JoyDPadDirections)vdpadDirection, button); } } } } } else if (vdpadButtonIndex > 0 && vdpadDirection > 0) { vdpadButtonIndex -= 1; for (int i=0; i < joystick_sets.size(); i++) { SetJoystick *currentset = joystick_sets.value(i); VDPad *vdpad = currentset->getVDPad(vdpadIndex-1); if (vdpad) { JoyButton *button = currentset->getJoyButton(vdpadButtonIndex); if (button) { vdpad->addVButton((JoyDPadButton::JoyDPadDirections)vdpadDirection, button); } } } } xml->readNext(); } else { xml->skipCurrentElement(); } xml->readNextStartElement(); } } for (int i=0; i < joystick_sets.size(); i++) { SetJoystick *currentset = joystick_sets.value(i); for (int j=0; j < currentset->getNumberVDPads(); j++) { VDPad *vdpad = currentset->getVDPad(j); if (vdpad && vdpad->isEmpty()) { currentset->removeVDPad(j); } } } } else if (xml->name() == "names" && xml->isStartElement()) { xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "names")) { if (xml->name() == "buttonname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty()) { setButtonName(index, temp); } } else if (xml->name() == "axisbuttonname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); int buttonIndex = xml->attributes().value("button").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; buttonIndex = buttonIndex - 1; if (index >= 0 && !temp.isEmpty()) { setAxisButtonName(index, buttonIndex, temp); } } else if (xml->name() == "controlstickbuttonname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); int buttonIndex = xml->attributes().value("button").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty()) { setStickButtonName(index, buttonIndex, temp); } } else if (xml->name() == "dpadbuttonname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); int buttonIndex = xml->attributes().value("button").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty()) { setDPadButtonName(index, buttonIndex, temp); } } else if (xml->name() == "vdpadbuttonname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); int buttonIndex = xml->attributes().value("button").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty()) { setVDPadButtonName(index, buttonIndex, temp); } } else if (xml->name() == "axisname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty()) { setAxisName(index, temp); } } else if (xml->name() == "controlstickname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty()) { setStickName(index, temp); } } else if (xml->name() == "dpadname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty()) { setDPadName(index, temp); } } else if (xml->name() == "vdpadname" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); QString temp = xml->readElementText(); index = index - 1; if (index >= 0 && !temp.isEmpty()) { setVDPadName(index, temp); } } else { // If none of the above, skip the element xml->skipCurrentElement(); } xml->readNextStartElement(); } } else if (xml->name() == "keyPressTime" && xml->isStartElement()) { QString temptext = xml->readElementText(); int tempchoice = temptext.toInt(); if (tempchoice >= 10) { this->setDeviceKeyPressTime(tempchoice); } } else if (xml->name() == "profilename" && xml->isStartElement()) { QString temptext = xml->readElementText(); this->setProfileName(temptext); } else { // If none of the above, skip the element xml->skipCurrentElement(); } xml->readNextStartElement(); } reInitButtons(); } } void InputDevice::writeConfig(QXmlStreamWriter *xml) { xml->writeStartElement(getXmlName()); xml->writeAttribute("configversion", QString::number(PadderCommon::LATESTCONFIGFILEVERSION)); xml->writeAttribute("appversion", PadderCommon::programVersion); xml->writeComment("The SDL name for a joystick is included for informational purposes only."); xml->writeTextElement("sdlname", getSDLName()); #ifdef USE_SDL_2 xml->writeComment("The GUID for a joystick is included for informational purposes only."); xml->writeTextElement("guid", getGUIDString()); #endif if (!profileName.isEmpty()) { xml->writeTextElement("profilename", profileName); } for (int i=0; i < getNumberSticks(); i++) { JoyControlStick *stick = getActiveSetJoystick()->getJoyStick(i); xml->writeStartElement("stickAxisAssociation"); xml->writeAttribute("index", QString::number(stick->getRealJoyIndex())); xml->writeAttribute("xAxis", QString::number(stick->getAxisX()->getRealJoyIndex())); xml->writeAttribute("yAxis", QString::number(stick->getAxisY()->getRealJoyIndex())); xml->writeEndElement(); } for (int i=0; i < getNumberVDPads(); i++) { VDPad *vdpad = getActiveSetJoystick()->getVDPad(i); xml->writeStartElement("vdpadButtonAssociations"); xml->writeAttribute("index", QString::number(vdpad->getRealJoyNumber())); JoyButton *button = vdpad->getVButton(JoyDPadButton::DpadUp); if (button) { xml->writeStartElement("vdpadButtonAssociation"); if (typeid(*button) == typeid(JoyAxisButton)) { JoyAxisButton *axisbutton = static_cast(button); xml->writeAttribute("axis", QString::number(axisbutton->getAxis()->getRealJoyIndex())); xml->writeAttribute("button", QString::number(button->getJoyNumber())); } else { xml->writeAttribute("axis", QString::number(0)); xml->writeAttribute("button", QString::number(button->getRealJoyNumber())); } xml->writeAttribute("direction", QString::number(JoyDPadButton::DpadUp)); xml->writeEndElement(); } button = vdpad->getVButton(JoyDPadButton::DpadDown); if (button) { xml->writeStartElement("vdpadButtonAssociation"); if (typeid(*button) == typeid(JoyAxisButton)) { JoyAxisButton *axisbutton = static_cast(button); xml->writeAttribute("axis", QString::number(axisbutton->getAxis()->getRealJoyIndex())); xml->writeAttribute("button", QString::number(button->getJoyNumber())); } else { xml->writeAttribute("axis", QString::number(0)); xml->writeAttribute("button", QString::number(button->getRealJoyNumber())); } xml->writeAttribute("direction", QString::number(JoyDPadButton::DpadDown)); xml->writeEndElement(); } button = vdpad->getVButton(JoyDPadButton::DpadLeft); if (button) { xml->writeStartElement("vdpadButtonAssociation"); if (typeid(*button) == typeid(JoyAxisButton)) { JoyAxisButton *axisbutton = static_cast(button); xml->writeAttribute("axis", QString::number(axisbutton->getAxis()->getRealJoyIndex())); xml->writeAttribute("button", QString::number(button->getJoyNumber())); } else { xml->writeAttribute("axis", QString::number(0)); xml->writeAttribute("button", QString::number(button->getRealJoyNumber())); } xml->writeAttribute("direction", QString::number(JoyDPadButton::DpadLeft)); xml->writeEndElement(); } button = vdpad->getVButton(JoyDPadButton::DpadRight); if (button) { xml->writeStartElement("vdpadButtonAssociation"); if (typeid(*button) == typeid(JoyAxisButton)) { JoyAxisButton *axisbutton = static_cast(button); xml->writeAttribute("axis", QString::number(axisbutton->getAxis()->getRealJoyIndex())); xml->writeAttribute("button", QString::number(button->getJoyNumber())); } else { xml->writeAttribute("axis", QString::number(0)); xml->writeAttribute("button", QString::number(button->getRealJoyNumber())); } xml->writeAttribute("direction", QString::number(JoyDPadButton::DpadRight)); xml->writeEndElement(); } xml->writeEndElement(); } bool tempHasNames = elementsHaveNames(); if (tempHasNames) { xml->writeStartElement("names"); // SetJoystick *tempSet = getActiveSetJoystick(); for (int i=0; i < getNumberButtons(); i++) { JoyButton *button = tempSet->getJoyButton(i); if (button && !button->getButtonName().isEmpty()) { xml->writeStartElement("buttonname"); xml->writeAttribute("index", QString::number(button->getRealJoyNumber())); xml->writeCharacters(button->getButtonName()); xml->writeEndElement(); } } for (int i=0; i < getNumberAxes(); i++) { JoyAxis *axis = tempSet->getJoyAxis(i); if (axis) { if (!axis->getAxisName().isEmpty()) { xml->writeStartElement("axisname"); xml->writeAttribute("index", QString::number(axis->getRealJoyIndex())); xml->writeCharacters(axis->getAxisName()); xml->writeEndElement(); } JoyAxisButton *naxisbutton = axis->getNAxisButton(); if (!naxisbutton->getButtonName().isEmpty()) { xml->writeStartElement("axisbuttonname"); xml->writeAttribute("index", QString::number(axis->getRealJoyIndex())); xml->writeAttribute("button", QString::number(naxisbutton->getRealJoyNumber())); xml->writeCharacters(naxisbutton->getButtonName()); xml->writeEndElement(); } JoyAxisButton *paxisbutton = axis->getPAxisButton(); if (!paxisbutton->getButtonName().isEmpty()) { xml->writeStartElement("axisbuttonname"); xml->writeAttribute("index", QString::number(axis->getRealJoyIndex())); xml->writeAttribute("button", QString::number(paxisbutton->getRealJoyNumber())); xml->writeCharacters(paxisbutton->getButtonName()); xml->writeEndElement(); } } } for (int i=0; i < getNumberSticks(); i++) { JoyControlStick *stick = tempSet->getJoyStick(i); if (stick) { if (!stick->getStickName().isEmpty()) { xml->writeStartElement("controlstickname"); xml->writeAttribute("index", QString::number(stick->getRealJoyIndex())); xml->writeCharacters(stick->getStickName()); xml->writeEndElement(); } QHash *buttons = stick->getButtons(); QHashIterator iter(*buttons); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); if (button && !button->getButtonName().isEmpty()) { xml->writeStartElement("controlstickbuttonname"); xml->writeAttribute("index", QString::number(stick->getRealJoyIndex())); xml->writeAttribute("button", QString::number(button->getRealJoyNumber())); xml->writeCharacters(button->getButtonName()); xml->writeEndElement(); } } } } for (int i=0; i < getNumberHats(); i++) { JoyDPad *dpad = tempSet->getJoyDPad(i); if (dpad) { if (!dpad->getDpadName().isEmpty()) { xml->writeStartElement("dpadname"); xml->writeAttribute("index", QString::number(dpad->getRealJoyNumber())); xml->writeCharacters(dpad->getDpadName()); xml->writeEndElement(); } QHash *temp = dpad->getButtons(); QHashIterator iter(*temp); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); if (button && !button->getButtonName().isEmpty()) { xml->writeStartElement("dpadbuttonname"); xml->writeAttribute("index", QString::number(dpad->getRealJoyNumber())); xml->writeAttribute("button", QString::number(button->getRealJoyNumber())); xml->writeCharacters(button->getButtonName()); xml->writeEndElement(); } } } } for (int i=0; i < getNumberVDPads(); i++) { VDPad *vdpad = getActiveSetJoystick()->getVDPad(i); if (vdpad) { if (!vdpad->getDpadName().isEmpty()) { xml->writeStartElement("vdpadname"); xml->writeAttribute("index", QString::number(vdpad->getRealJoyNumber())); xml->writeCharacters(vdpad->getDpadName()); xml->writeEndElement(); } QHash *temp = vdpad->getButtons(); QHashIterator iter(*temp); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); if (button && !button->getButtonName().isEmpty()) { xml->writeStartElement("vdpadbutton"); xml->writeAttribute("index", QString::number(vdpad->getRealJoyNumber())); xml->writeAttribute("button", QString::number(button->getRealJoyNumber())); xml->writeCharacters(button->getButtonName()); xml->writeEndElement(); } } } } xml->writeEndElement(); // } if (keyPressTime > 0 && keyPressTime != DEFAULTKEYPRESSTIME) { xml->writeTextElement("keyPressTime", QString::number(keyPressTime)); } xml->writeStartElement("sets"); for (int i=0; i < joystick_sets.size(); i++) { joystick_sets.value(i)->writeConfig(xml); } xml->writeEndElement(); xml->writeEndElement(); } void InputDevice::changeSetAxisButtonAssociation(int button_index, int axis_index, int originset, int newset, int mode) { JoyAxisButton *button = 0; if (button_index == 0) { button = joystick_sets.value(newset)->getJoyAxis(axis_index)->getNAxisButton(); } else if (button_index == 1) { button = joystick_sets.value(newset)->getJoyAxis(axis_index)->getPAxisButton(); } JoyButton::SetChangeCondition tempmode = (JoyButton::SetChangeCondition)mode; button->setChangeSetSelection(originset); button->setChangeSetCondition(tempmode, true); } void InputDevice::changeSetStickButtonAssociation(int button_index, int stick_index, int originset, int newset, int mode) { JoyControlStickButton *button = joystick_sets.value(newset)->getJoyStick(stick_index)->getDirectionButton((JoyControlStick::JoyStickDirections)button_index); JoyButton::SetChangeCondition tempmode = (JoyButton::SetChangeCondition)mode; button->setChangeSetSelection(originset); button->setChangeSetCondition(tempmode, true); } void InputDevice::changeSetDPadButtonAssociation(int button_index, int dpad_index, int originset, int newset, int mode) { JoyDPadButton *button = joystick_sets.value(newset)->getJoyDPad(dpad_index)->getJoyButton(button_index); JoyButton::SetChangeCondition tempmode = (JoyButton::SetChangeCondition)mode; button->setChangeSetSelection(originset); button->setChangeSetCondition(tempmode, true); } void InputDevice::changeSetVDPadButtonAssociation(int button_index, int dpad_index, int originset, int newset, int mode) { JoyDPadButton *button = joystick_sets.value(newset)->getVDPad(dpad_index)->getJoyButton(button_index); JoyButton::SetChangeCondition tempmode = (JoyButton::SetChangeCondition)mode; button->setChangeSetSelection(originset); button->setChangeSetCondition(tempmode, true); } void InputDevice::propogateSetAxisThrottleChange(int index, int originset) { SetJoystick *currentSet = joystick_sets.value(originset); if (currentSet) { JoyAxis *axis = currentSet->getJoyAxis(index); if (axis) { int throttleSetting = axis->getThrottle(); QHashIterator iter(joystick_sets); while (iter.hasNext()) { iter.next(); SetJoystick *temp = iter.value(); // Ignore change for set axis that initiated the change if (temp != currentSet) { temp->getJoyAxis(index)->setThrottle(throttleSetting); } } } } } void InputDevice::removeControlStick(int index) { for (int i=0; i < NUMBER_JOYSETS; i++) { SetJoystick *currentset = getSetJoystick(i); if (currentset->getJoyStick(index)) { currentset->removeControlStick(index); } } } bool InputDevice::isActive() { return buttonDownCount > 0; } void InputDevice::buttonDownEvent(int setindex, int buttonindex) { Q_UNUSED(setindex); Q_UNUSED(buttonindex); bool old = isActive(); buttonDownCount += 1; if (isActive() != old) { emit clicked(joyNumber); } } void InputDevice::buttonUpEvent(int setindex, int buttonindex) { Q_UNUSED(setindex); Q_UNUSED(buttonindex); bool old = isActive(); buttonDownCount -= 1; if (buttonDownCount < 0) { buttonDownCount = 0; } if (isActive() != old) { emit released(joyNumber); } } void InputDevice::buttonClickEvent(int buttonindex) { emit rawButtonClick(buttonindex); } void InputDevice::buttonReleaseEvent(int buttonindex) { emit rawButtonRelease(buttonindex); } void InputDevice::axisButtonDownEvent(int setindex, int axisindex, int buttonindex) { Q_UNUSED(axisindex); buttonDownEvent(setindex, buttonindex); } void InputDevice::axisButtonUpEvent(int setindex, int axisindex, int buttonindex) { Q_UNUSED(axisindex); buttonUpEvent(setindex, buttonindex); } void InputDevice::dpadButtonClickEvent(int buttonindex) { JoyDPadButton *dpadbutton = static_cast(sender()); if (dpadbutton) { emit rawDPadButtonClick(dpadbutton->getDPad()->getIndex(), buttonindex); } } void InputDevice::dpadButtonReleaseEvent(int buttonindex) { JoyDPadButton *dpadbutton = static_cast(sender()); if (dpadbutton) { emit rawDPadButtonRelease(dpadbutton->getDPad()->getIndex(), buttonindex); } } void InputDevice::dpadButtonDownEvent(int setindex, int dpadindex, int buttonindex) { Q_UNUSED(dpadindex); buttonDownEvent(setindex, buttonindex); } void InputDevice::dpadButtonUpEvent(int setindex, int dpadindex, int buttonindex) { Q_UNUSED(dpadindex); buttonUpEvent(setindex, buttonindex); } void InputDevice::stickButtonDownEvent(int setindex, int stickindex, int buttonindex) { Q_UNUSED(stickindex); buttonDownEvent(setindex, buttonindex); } void InputDevice::stickButtonUpEvent(int setindex, int stickindex, int buttonindex) { Q_UNUSED(stickindex); buttonUpEvent(setindex, buttonindex); } void InputDevice::setButtonName(int index, QString tempName) { QHashIterator iter(joystick_sets); while (iter.hasNext()) { SetJoystick *tempSet = iter.next().value(); disconnect(tempSet, SIGNAL(setButtonNameChange(int)), this, SLOT(updateSetButtonNames(int))); JoyButton *button = tempSet->getJoyButton(index); if (button) { button->setButtonName(tempName); } connect(tempSet, SIGNAL(setButtonNameChange(int)), this, SLOT(updateSetButtonNames(int))); } } void InputDevice::setAxisButtonName(int axisIndex, int buttonIndex, QString tempName) { QHashIterator iter(joystick_sets); while (iter.hasNext()) { SetJoystick *tempSet = iter.next().value(); disconnect(tempSet, SIGNAL(setAxisButtonNameChange(int,int)), this, SLOT(updateSetAxisButtonNames(int,int))); JoyAxis *axis = tempSet->getJoyAxis(axisIndex); if (axis) { JoyAxisButton *button = 0; if (buttonIndex == 0) { button = axis->getNAxisButton(); } else if (buttonIndex == 1) { button = axis->getPAxisButton(); } if (button) { button->setButtonName(tempName); } } connect(tempSet, SIGNAL(setAxisButtonNameChange(int,int)), this, SLOT(updateSetAxisButtonNames(int,int))); } } void InputDevice::setStickButtonName(int stickIndex, int buttonIndex, QString tempName) { QHashIterator iter(joystick_sets); while (iter.hasNext()) { SetJoystick *tempSet = iter.next().value(); disconnect(tempSet, SIGNAL(setStickButtonNameChange(int,int)), this, SLOT(updateSetStickButtonNames(int,int))); JoyControlStick *stick = tempSet->getJoyStick(stickIndex); if (stick) { JoyControlStickButton *button = stick->getDirectionButton(JoyControlStick::JoyStickDirections(buttonIndex)); if (button) { button->setButtonName(tempName); } } connect(tempSet, SIGNAL(setStickButtonNameChange(int,int)), this, SLOT(updateSetStickButtonNames(int,int))); } } void InputDevice::setDPadButtonName(int dpadIndex, int buttonIndex, QString tempName) { QHashIterator iter(joystick_sets); while (iter.hasNext()) { SetJoystick *tempSet = iter.next().value(); disconnect(tempSet, SIGNAL(setDPadButtonNameChange(int,int)), this, SLOT(updateSetDPadButtonNames(int,int))); JoyDPad *dpad = tempSet->getJoyDPad(dpadIndex); if (dpad) { JoyDPadButton *button = dpad->getJoyButton(buttonIndex); if (button) { button->setButtonName(tempName); } } connect(tempSet, SIGNAL(setDPadButtonNameChange(int,int)), this, SLOT(updateSetDPadButtonNames(int,int))); } } void InputDevice::setVDPadButtonName(int vdpadIndex, int buttonIndex, QString tempName) { QHashIterator iter(joystick_sets); while (iter.hasNext()) { SetJoystick *tempSet = iter.next().value(); disconnect(tempSet, SIGNAL(setVDPadButtonNameChange(int,int)), this, SLOT(updateSetVDPadButtonNames(int,int))); VDPad *vdpad = tempSet->getVDPad(vdpadIndex); if (vdpad) { JoyDPadButton *button = vdpad->getJoyButton(buttonIndex); if (button) { button->setButtonName(tempName); } } connect(tempSet, SIGNAL(setVDPadButtonNameChange(int,int)), this, SLOT(updateSetVDPadButtonNames(int,int))); } } void InputDevice::setAxisName(int axisIndex, QString tempName) { QHashIterator iter(joystick_sets); while (iter.hasNext()) { SetJoystick *tempSet = iter.next().value(); disconnect(tempSet, SIGNAL(setAxisNameChange(int)), this, SLOT(updateSetAxisNames(int))); JoyAxis *axis = tempSet->getJoyAxis(axisIndex); if (axis) { axis->setAxisName(tempName); } connect(tempSet, SIGNAL(setAxisNameChange(int)), this, SLOT(updateSetAxisNames(int))); } } void InputDevice::setStickName(int stickIndex, QString tempName) { QHashIterator iter(joystick_sets); while (iter.hasNext()) { SetJoystick *tempSet = iter.next().value(); disconnect(tempSet, SIGNAL(setStickNameChange(int)), this, SLOT(updateSetStickNames(int))); JoyControlStick *stick = tempSet->getJoyStick(stickIndex); if (stick) { stick->setStickName(tempName); } connect(tempSet, SIGNAL(setStickNameChange(int)), this, SLOT(updateSetStickNames(int))); } } void InputDevice::setDPadName(int dpadIndex, QString tempName) { QHashIterator iter(joystick_sets); while (iter.hasNext()) { SetJoystick *tempSet = iter.next().value(); disconnect(tempSet, SIGNAL(setDPadNameChange(int)), this, SLOT(updateSetDPadNames(int))); JoyDPad *dpad = tempSet->getJoyDPad(dpadIndex); if (dpad) { dpad->setDPadName(tempName); } connect(tempSet, SIGNAL(setDPadNameChange(int)), this, SLOT(updateSetDPadNames(int))); } } void InputDevice::setVDPadName(int vdpadIndex, QString tempName) { QHashIterator iter(joystick_sets); while (iter.hasNext()) { SetJoystick *tempSet = iter.next().value(); disconnect(tempSet, SIGNAL(setVDPadNameChange(int)), this, SLOT(updateSetVDPadNames(int))); VDPad *vdpad = tempSet->getVDPad(vdpadIndex); if (vdpad) { vdpad->setDPadName(tempName); } connect(tempSet, SIGNAL(setVDPadNameChange(int)), this, SLOT(updateSetVDPadNames(int))); } } void InputDevice::updateSetButtonNames(int index) { JoyButton *button = getActiveSetJoystick()->getJoyButton(index); if (button) { setButtonName(index, button->getButtonName()); } } void InputDevice::updateSetAxisButtonNames(int axisIndex, int buttonIndex) { JoyAxis *axis = getActiveSetJoystick()->getJoyAxis(axisIndex); if (axis) { JoyAxisButton *button = 0; if (buttonIndex == 0) { button = axis->getNAxisButton(); } else if (buttonIndex == 1) { button = axis->getPAxisButton(); } if (button) { setAxisButtonName(axisIndex, buttonIndex, button->getButtonName()); } } } void InputDevice::updateSetStickButtonNames(int stickIndex, int buttonIndex) { JoyControlStick *stick = getActiveSetJoystick()->getJoyStick(stickIndex); if (stick) { JoyControlStickButton *button = stick->getDirectionButton(JoyControlStick::JoyStickDirections(buttonIndex)); if (button) { setStickButtonName(stickIndex, buttonIndex, button->getButtonName()); } } } void InputDevice::updateSetDPadButtonNames(int dpadIndex, int buttonIndex) { JoyDPad *dpad = getActiveSetJoystick()->getJoyDPad(dpadIndex); if (dpad) { JoyDPadButton *button = dpad->getJoyButton(buttonIndex); if (button) { setDPadButtonName(dpadIndex, buttonIndex, button->getButtonName()); } } } void InputDevice::updateSetVDPadButtonNames(int vdpadIndex, int buttonIndex) { VDPad *vdpad = getActiveSetJoystick()->getVDPad(vdpadIndex); if (vdpad) { JoyDPadButton *button = vdpad->getJoyButton(buttonIndex); if (button) { setVDPadButtonName(vdpadIndex, buttonIndex, button->getButtonName()); } } } void InputDevice::updateSetAxisNames(int axisIndex) { JoyAxis *axis = getActiveSetJoystick()->getJoyAxis(axisIndex); if (axis) { setAxisName(axisIndex, axis->getAxisName()); } } void InputDevice::updateSetStickNames(int stickIndex) { JoyControlStick *stick = getActiveSetJoystick()->getJoyStick(stickIndex); if (stick) { setStickName(stickIndex, stick->getStickName()); } } void InputDevice::updateSetDPadNames(int dpadIndex) { JoyDPad *dpad = getActiveSetJoystick()->getJoyDPad(dpadIndex); if (dpad) { setDPadName(dpadIndex, dpad->getDpadName()); } } void InputDevice::updateSetVDPadNames(int vdpadIndex) { VDPad *vdpad = getActiveSetJoystick()->getVDPad(vdpadIndex); if (vdpad) { setVDPadName(vdpadIndex, vdpad->getDpadName()); } } void InputDevice::resetButtonDownCount() { buttonDownCount = 0; emit released(joyNumber); } void InputDevice::enableSetConnections(SetJoystick *setstick) { connect(setstick, SIGNAL(setChangeActivated(int)), this, SLOT(resetButtonDownCount())); connect(setstick, SIGNAL(setChangeActivated(int)), this, SLOT(setActiveSetNumber(int))); connect(setstick, SIGNAL(setChangeActivated(int)), this, SLOT(propogateSetChange(int))); connect(setstick, SIGNAL(setAssignmentButtonChanged(int,int,int,int)), this, SLOT(changeSetButtonAssociation(int,int,int,int))); connect(setstick, SIGNAL(setAssignmentAxisChanged(int,int,int,int,int)), this, SLOT(changeSetAxisButtonAssociation(int,int,int,int,int))); connect(setstick, SIGNAL(setAssignmentDPadChanged(int,int,int,int,int)), this, SLOT(changeSetDPadButtonAssociation(int,int,int,int,int))); connect(setstick, SIGNAL(setAssignmentVDPadChanged(int,int,int,int,int)), this, SLOT(changeSetVDPadButtonAssociation(int,int,int,int,int))); connect(setstick, SIGNAL(setAssignmentStickChanged(int,int,int,int,int)), this, SLOT(changeSetStickButtonAssociation(int,int,int,int,int))); connect(setstick, SIGNAL(setAssignmentAxisThrottleChanged(int,int)), this, SLOT(propogateSetAxisThrottleChange(int, int))); connect(setstick, SIGNAL(setButtonClick(int,int)), this, SLOT(buttonDownEvent(int,int))); connect(setstick, SIGNAL(setButtonRelease(int,int)), this, SLOT(buttonUpEvent(int,int))); connect(setstick, SIGNAL(setAxisButtonClick(int,int,int)), this, SLOT(axisButtonDownEvent(int,int,int))); connect(setstick, SIGNAL(setAxisButtonRelease(int,int,int)), this, SLOT(axisButtonUpEvent(int,int,int))); connect(setstick, SIGNAL(setAxisActivated(int,int, int)), this, SLOT(axisActivatedEvent(int,int,int))); connect(setstick, SIGNAL(setAxisReleased(int,int,int)), this, SLOT(axisReleasedEvent(int,int,int))); connect(setstick, SIGNAL(setDPadButtonClick(int,int,int)), this, SLOT(dpadButtonDownEvent(int,int,int))); connect(setstick, SIGNAL(setDPadButtonRelease(int,int,int)), this, SLOT(dpadButtonUpEvent(int,int,int))); connect(setstick, SIGNAL(setStickButtonClick(int,int,int)), this, SLOT(stickButtonDownEvent(int,int,int))); connect(setstick, SIGNAL(setStickButtonRelease(int,int,int)), this, SLOT(stickButtonUpEvent(int,int,int))); connect(setstick, SIGNAL(setButtonNameChange(int)), this, SLOT(updateSetButtonNames(int))); connect(setstick, SIGNAL(setAxisButtonNameChange(int,int)), this, SLOT(updateSetAxisButtonNames(int,int))); connect(setstick, SIGNAL(setStickButtonNameChange(int,int)), this, SLOT(updateSetStickButtonNames(int,int))); connect(setstick, SIGNAL(setDPadButtonNameChange(int,int)), this, SLOT(updateSetDPadButtonNames(int,int))); connect(setstick, SIGNAL(setVDPadButtonNameChange(int,int)), this, SLOT(updateSetVDPadButtonNames(int,int))); connect(setstick, SIGNAL(setAxisNameChange(int)), this, SLOT(updateSetAxisNames(int))); connect(setstick, SIGNAL(setStickNameChange(int)), this, SLOT(updateSetStickNames(int))); connect(setstick, SIGNAL(setDPadNameChange(int)), this, SLOT(updateSetDPadNames(int))); connect(setstick, SIGNAL(setVDPadNameChange(int)), this, SLOT(updateSetVDPadNames(int))); } void InputDevice::axisActivatedEvent(int setindex, int axisindex, int value) { Q_UNUSED(setindex); emit rawAxisActivated(axisindex, value); } void InputDevice::axisReleasedEvent(int setindex, int axisindex, int value) { Q_UNUSED(setindex); emit rawAxisReleased(axisindex, value); } void InputDevice::setIndex(int index) { if (index >= 0) { joyNumber = index; } else { joyNumber = 0; } } void InputDevice::setDeviceKeyPressTime(unsigned int newPressTime) { keyPressTime = newPressTime; emit propertyUpdated(); } unsigned int InputDevice::getDeviceKeyPressTime() { return keyPressTime; } void InputDevice::profileEdited() { if (!deviceEdited) { deviceEdited = true; emit profileUpdated(); } } bool InputDevice::isDeviceEdited() { return deviceEdited; } void InputDevice::revertProfileEdited() { deviceEdited = false; } QString InputDevice::getStringIdentifier() { QString identifier; QString tempGUID = getGUIDString(); QString tempName = getSDLName(); if (!tempGUID.isEmpty()) { identifier = tempGUID; } else if (!tempName.isEmpty()) { identifier = tempName; } return identifier; } void InputDevice::establishPropertyUpdatedConnection() { connect(this, SIGNAL(propertyUpdated()), this, SLOT(profileEdited())); } void InputDevice::disconnectPropertyUpdatedConnection() { disconnect(this, SIGNAL(propertyUpdated()), this, SLOT(profileEdited())); } void InputDevice::setKeyRepeatStatus(bool enabled) { keyRepeatEnabled = enabled; } void InputDevice::setKeyRepeatDelay(int delay) { if (delay >= 250 && delay <= 1000) { keyRepeatDelay = delay; } } void InputDevice::setKeyRepeatRate(int rate) { if (rate >= 20 && rate <= 200) { keyRepeatRate = rate; } } bool InputDevice::isKeyRepeatEnabled() { return keyRepeatEnabled; } int InputDevice::getKeyRepeatDelay() { int tempKeyRepeatDelay = DEFAULTKEYREPEATDELAY; if (keyRepeatDelay != 0) { tempKeyRepeatDelay = keyRepeatDelay; } return tempKeyRepeatDelay; } int InputDevice::getKeyRepeatRate() { int tempKeyRepeatRate = DEFAULTKEYREPEATRATE; if (keyRepeatRate != 0) { tempKeyRepeatRate = keyRepeatRate; } return tempKeyRepeatRate; } void InputDevice::setProfileName(QString value) { if (profileName != value) { if (value.size() > 50) { value.truncate(47); value.append("..."); } profileName = value; emit propertyUpdated(); emit profileNameEdited(value); } } QString InputDevice::getProfileName() { return profileName; } int InputDevice::getButtonDownCount() { return buttonDownCount; } #ifdef USE_SDL_2 QString InputDevice::getSDLPlatform() { QString temp = SDL_GetPlatform(); return temp; } #endif /** * @brief Check if device is using the SDL Game Controller API * @return Status showing if device is using the Game Controller API */ bool InputDevice::isGameController() { return false; } bool InputDevice::hasCalibrationThrottle(int axisNum) { bool result = false; if (cali.contains(axisNum)) { result = true; } return result; } JoyAxis::ThrottleTypes InputDevice::getCalibrationThrottle(int axisNum) { return cali.value(axisNum); } void InputDevice::setCalibrationThrottle(int axisNum, JoyAxis::ThrottleTypes throttle) { if (!cali.contains(axisNum)) { for (int i=0; i < NUMBER_JOYSETS; i++) { joystick_sets.value(i)->setAxisThrottle(axisNum, throttle); } cali.insert(axisNum, throttle); } } void InputDevice::setCalibrationStatus(int axisNum, JoyAxis::ThrottleTypes throttle) { if (!cali.contains(axisNum)) { cali.insert(axisNum, throttle); } } void InputDevice::removeCalibrationStatus(int axisNum) { if (cali.contains(axisNum)) { cali.remove(axisNum); } } void InputDevice::sendLoadProfileRequest(QString location) { if (!location.isEmpty()) { emit requestProfileLoad(location); } } AntiMicroSettings* InputDevice::getSettings() { return settings; } bool InputDevice::isKnownController() { bool result = false; if (isGameController()) { result = true; } else { settings->beginGroup("Mappings"); if (settings->contains(getGUIDString())) { result = true; } else if (settings->contains(QString("%1%2").arg(getGUIDString()).arg("Disabled"))) { result = true; } settings->endGroup(); } return result; } void InputDevice::activatePossiblePendingEvents() { activatePossibleControlStickEvents(); activatePossibleAxisEvents(); activatePossibleDPadEvents(); activatePossibleVDPadEvents(); activatePossibleButtonEvents(); } void InputDevice::activatePossibleControlStickEvents() { SetJoystick *currentSet = getActiveSetJoystick(); for (int i=0; i < currentSet->getNumberSticks(); i++) { JoyControlStick *tempStick = currentSet->getJoyStick(i); if (tempStick && tempStick->hasPendingEvent()) { tempStick->activatePendingEvent(); } } } void InputDevice::activatePossibleAxisEvents() { SetJoystick *currentSet = getActiveSetJoystick(); for (int i=0; i < currentSet->getNumberAxes(); i++) { JoyAxis *tempAxis = currentSet->getJoyAxis(i); if (tempAxis && tempAxis->hasPendingEvent()) { tempAxis->activatePendingEvent(); } } } void InputDevice::activatePossibleDPadEvents() { SetJoystick *currentSet = getActiveSetJoystick(); for (int i=0; i < currentSet->getNumberHats(); i++) { JoyDPad *tempDPad = currentSet->getJoyDPad(i); if (tempDPad && tempDPad->hasPendingEvent()) { tempDPad->activatePendingEvent(); } } } void InputDevice::activatePossibleVDPadEvents() { SetJoystick *currentSet = getActiveSetJoystick(); for (int i=0; i < currentSet->getNumberVDPads(); i++) { VDPad *tempVDPad = currentSet->getVDPad(i); if (tempVDPad && tempVDPad->hasPendingEvent()) { tempVDPad->activatePendingEvent(); } } } void InputDevice::activatePossibleButtonEvents() { SetJoystick *currentSet = getActiveSetJoystick(); for (int i=0; i < currentSet->getNumberButtons(); i++) { JoyButton *tempButton = currentSet->getJoyButton(i); if (tempButton && tempButton->hasPendingEvent()) { tempButton->activatePendingEvent(); } } } bool InputDevice::elementsHaveNames() { bool result = false; SetJoystick *tempSet = getActiveSetJoystick(); for (int i=0; i < getNumberButtons() && !result; i++) { JoyButton *button = tempSet->getJoyButton(i); if (button && !button->getButtonName().isEmpty()) { result = true; } } for (int i=0; i < getNumberAxes() && !result; i++) { JoyAxis *axis = tempSet->getJoyAxis(i); if (axis) { if (!axis->getAxisName().isEmpty()) { result = true; } JoyAxisButton *naxisbutton = axis->getNAxisButton(); if (!naxisbutton->getButtonName().isEmpty()) { result = true; } JoyAxisButton *paxisbutton = axis->getPAxisButton(); if (!paxisbutton->getButtonName().isEmpty()) { result = true; } } } for (int i=0; i < getNumberSticks() && !result; i++) { JoyControlStick *stick = tempSet->getJoyStick(i); if (stick) { if (!stick->getStickName().isEmpty()) { result = true; } QHash *buttons = stick->getButtons(); QHashIterator iter(*buttons); while (iter.hasNext() && !result) { JoyControlStickButton *button = iter.next().value(); if (button && !button->getButtonName().isEmpty()) { result = true; } } } } for (int i=0; i < getNumberHats() && !result; i++) { JoyDPad *dpad = tempSet->getJoyDPad(i); if (dpad) { if (!dpad->getDpadName().isEmpty()) { result = true; } QHash *temp = dpad->getButtons(); QHashIterator iter(*temp); while (iter.hasNext() && !result) { JoyDPadButton *button = iter.next().value(); if (button && !button->getButtonName().isEmpty()) { result = true; } } } } for (int i=0; i < getNumberVDPads() && !result; i++) { VDPad *vdpad = getActiveSetJoystick()->getVDPad(i); if (vdpad) { if (!vdpad->getDpadName().isEmpty()) { result = true; } QHash *temp = vdpad->getButtons(); QHashIterator iter(*temp); while (iter.hasNext() && !result) { JoyDPadButton *button = iter.next().value(); if (button && !button->getButtonName().isEmpty()) { result = true; } } } } return result; } /** * @brief Check if the GUID passed is considered empty. * @param GUID string * @return if GUID is considered empty. */ bool InputDevice::isEmptyGUID(QString tempGUID) { bool result = false; if (tempGUID.contains(emptyGUID)) { result = true; } return result; } /** * @brief Check if GUID passed matches the expected GUID for a device. * Needed for xinput GUID abstraction. * @param GUID string * @return if GUID is considered a match. */ bool InputDevice::isRelevantGUID(QString tempGUID) { bool result = false; if (tempGUID == getGUIDString()) { result = true; } return result; } QString InputDevice::getRawGUIDString() { QString temp = getGUIDString(); return temp; } void InputDevice::haltServices() { emit requestWait(); } void InputDevice::finalRemoval() { this->closeSDLDevice(); this->deleteLater(); } void InputDevice::setRawAxisDeadZone(int deadZone) { if (deadZone > 0 && deadZone <= JoyAxis::AXISMAX) { this->rawAxisDeadZone = deadZone; } else { this->rawAxisDeadZone = RAISEDDEADZONE; } } int InputDevice::getRawAxisDeadZone() { return rawAxisDeadZone; } void InputDevice::rawAxisEvent(int index, int value) { emit rawAxisMoved(index, value); } antimicro-2.23/src/inputdevice.h000066400000000000000000000206351300750276700167210ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef INPUTDEVICE_H #define INPUTDEVICE_H #include #include #include #include #include #ifdef USE_SDL_2 #include #include #else #include typedef Sint32 SDL_JoystickID; #endif #include "setjoystick.h" #include "common.h" #include "antimicrosettings.h" class InputDevice : public QObject { Q_OBJECT public: explicit InputDevice(int deviceIndex, AntiMicroSettings *settings, QObject *parent = 0); virtual ~InputDevice(); virtual int getNumberButtons(); virtual int getNumberAxes(); virtual int getNumberHats(); virtual int getNumberSticks(); virtual int getNumberVDPads(); int getJoyNumber(); int getRealJoyNumber(); int getActiveSetNumber(); SetJoystick* getActiveSetJoystick(); SetJoystick* getSetJoystick(int index); void removeControlStick(int index); bool isActive(); int getButtonDownCount(); virtual QString getName() = 0; virtual QString getSDLName() = 0; // GUID only available on SDL 2. virtual QString getGUIDString() = 0; virtual QString getRawGUIDString(); virtual QString getStringIdentifier(); virtual QString getXmlName() = 0; virtual void closeSDLDevice() = 0; #ifdef USE_SDL_2 virtual SDL_JoystickID getSDLJoystickID() = 0; QString getSDLPlatform(); #endif virtual bool isGameController(); virtual bool isKnownController(); void setButtonName(int index, QString tempName); void setAxisButtonName(int axisIndex, int buttonIndex, QString tempName); void setStickButtonName(int stickIndex, int buttonIndex, QString tempName); void setDPadButtonName(int dpadIndex, int buttonIndex, QString tempName); void setVDPadButtonName(int vdpadIndex, int buttonIndex, QString tempName); void setAxisName(int axisIndex, QString tempName); void setStickName(int stickIndex, QString tempName); void setDPadName(int dpadIndex, QString tempName); void setVDPadName(int vdpadIndex, QString tempName); virtual int getNumberRawButtons() = 0; virtual int getNumberRawAxes() = 0; virtual int getNumberRawHats() = 0; unsigned int getDeviceKeyPressTime(); void setIndex(int index); bool isDeviceEdited(); void revertProfileEdited(); void setKeyRepeatStatus(bool enabled); void setKeyRepeatDelay(int delay); void setKeyRepeatRate(int rate); bool isKeyRepeatEnabled(); int getKeyRepeatDelay(); int getKeyRepeatRate(); QString getProfileName(); bool hasCalibrationThrottle(int axisNum); JoyAxis::ThrottleTypes getCalibrationThrottle(int axisNum); void setCalibrationThrottle(int axisNum, JoyAxis::ThrottleTypes throttle); void setCalibrationStatus(int axisNum, JoyAxis::ThrottleTypes throttle); void removeCalibrationStatus(int axisNum); void sendLoadProfileRequest(QString location); AntiMicroSettings *getSettings(); void activatePossiblePendingEvents(); void activatePossibleControlStickEvents(); void activatePossibleAxisEvents(); void activatePossibleDPadEvents(); void activatePossibleVDPadEvents(); void activatePossibleButtonEvents(); bool isEmptyGUID(QString tempGUID); bool isRelevantGUID(QString tempGUID); void setRawAxisDeadZone(int deadZone); int getRawAxisDeadZone(); void rawAxisEvent(int index, int value); static const int NUMBER_JOYSETS; static const int DEFAULTKEYPRESSTIME; static const unsigned int DEFAULTKEYREPEATDELAY; static const unsigned int DEFAULTKEYREPEATRATE; static const int RAISEDDEADZONE; protected: void enableSetConnections(SetJoystick *setstick); bool elementsHaveNames(); SDL_Joystick* joyhandle; QHash joystick_sets; QHash cali; AntiMicroSettings *settings; int active_set; int joyNumber; int buttonDownCount; SDL_JoystickID joystickID; unsigned int keyPressTime; bool deviceEdited; bool keyRepeatEnabled; int keyRepeatDelay; int keyRepeatRate; QString profileName; QList buttonstates; QList axesstates; QList dpadstates; int rawAxisDeadZone; static QRegExp emptyGUID; signals: void setChangeActivated(int index); void setAxisThrottleActivated(int index); void clicked(int index); void released(int index); void rawButtonClick(int index); void rawButtonRelease(int index); void rawAxisButtonClick(int axis, int buttonindex); void rawAxisButtonRelease(int axis, int buttonindex); void rawDPadButtonClick(int dpad, int buttonindex); void rawDPadButtonRelease(int dpad, int buttonindex); void rawAxisActivated(int axis, int value); void rawAxisReleased(int axis, int value); void rawAxisMoved(int axis, int value); void profileUpdated(); void propertyUpdated(); void profileNameEdited(QString text); void requestProfileLoad(QString location); void requestWait(); public slots: void reset(); void transferReset(); void reInitButtons(); void resetButtonDownCount(); void setActiveSetNumber(int index); void changeSetButtonAssociation(int button_index, int originset, int newset, int mode); void changeSetAxisButtonAssociation(int button_index, int axis_index, int originset, int newset, int mode); void changeSetStickButtonAssociation(int button_index, int stick_index, int originset, int newset, int mode); void changeSetDPadButtonAssociation(int button_index, int dpad_index, int originset, int newset, int mode); void changeSetVDPadButtonAssociation(int button_index, int dpad_index, int originset, int newset, int mode); void setDeviceKeyPressTime(unsigned int newPressTime); void profileEdited(); void setProfileName(QString value); void haltServices(); void finalRemoval(); virtual void readConfig(QXmlStreamReader *xml); virtual void writeConfig(QXmlStreamWriter *xml); void establishPropertyUpdatedConnection(); void disconnectPropertyUpdatedConnection(); protected slots: void propogateSetChange(int index); void propogateSetAxisThrottleChange(int index, int originset); void buttonDownEvent(int setindex, int buttonindex); void buttonUpEvent(int setindex, int buttonindex); virtual void axisActivatedEvent(int setindex, int axisindex, int value); virtual void axisReleasedEvent(int setindex, int axisindex, int value); virtual void buttonClickEvent(int buttonindex); virtual void buttonReleaseEvent(int buttonindex); virtual void axisButtonDownEvent(int setindex, int axisindex, int buttonindex); virtual void axisButtonUpEvent(int setindex, int axisindex, int buttonindex); virtual void dpadButtonDownEvent(int setindex, int dpadindex, int buttonindex); virtual void dpadButtonUpEvent(int setindex, int dpadindex, int buttonindex); virtual void dpadButtonClickEvent(int buttonindex); virtual void dpadButtonReleaseEvent(int buttonindex); virtual void stickButtonDownEvent(int setindex, int stickindex, int buttonindex); virtual void stickButtonUpEvent(int setindex, int stickindex, int buttonindex); void updateSetButtonNames(int index); void updateSetAxisButtonNames(int axisIndex, int buttonIndex); void updateSetStickButtonNames(int stickIndex, int buttonIndex); void updateSetDPadButtonNames(int dpadIndex, int buttonIndex); void updateSetVDPadButtonNames(int vdpadIndex, int buttonIndex); void updateSetAxisNames(int axisIndex); void updateSetStickNames(int stickIndex); void updateSetDPadNames(int dpadIndex); void updateSetVDPadNames(int vdpadIndex); }; Q_DECLARE_METATYPE(InputDevice*) Q_DECLARE_METATYPE(SDL_JoystickID) #endif // INPUTDEVICE_H antimicro-2.23/src/inputdevicebitarraystatus.cpp000066400000000000000000000073441300750276700222600ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "inputdevicebitarraystatus.h" InputDeviceBitArrayStatus::InputDeviceBitArrayStatus(InputDevice *device, bool readCurrent, QObject *parent) : QObject(parent) { for (int i=0; i < device->getNumberRawAxes(); i++) { SetJoystick *currentSet = device->getActiveSetJoystick(); JoyAxis *axis = currentSet->getJoyAxis(i); if (axis && readCurrent) { axesStatus.append(!axis->inDeadZone(axis->getCurrentRawValue()) ? true : false); } else { axesStatus.append(false); } } for (int i=0; i < device->getNumberRawHats(); i++) { SetJoystick *currentSet = device->getActiveSetJoystick(); JoyDPad *dpad = currentSet->getJoyDPad(i); if (dpad && readCurrent) { hatButtonStatus.append(dpad->getCurrentDirection() != JoyDPadButton::DpadCentered ? true : false); } else { hatButtonStatus.append(false); } } buttonStatus.resize(device->getNumberRawButtons()); buttonStatus.fill(0); for (int i=0; i < device->getNumberRawButtons(); i++) { SetJoystick *currentSet = device->getActiveSetJoystick(); JoyButton *button = currentSet->getJoyButton(i); if (button && readCurrent) { buttonStatus.setBit(i, button->getButtonState()); } } } void InputDeviceBitArrayStatus::changeAxesStatus(int axisIndex, bool value) { if (axisIndex >= 0 && axisIndex <= axesStatus.size()) { axesStatus.replace(axisIndex, value); } } void InputDeviceBitArrayStatus::changeButtonStatus(int buttonIndex, bool value) { if (buttonIndex >= 0 && buttonIndex <= buttonStatus.size()) { buttonStatus.setBit(buttonIndex, value); } } void InputDeviceBitArrayStatus::changeHatStatus(int hatIndex, bool value) { if (hatIndex >= 0 && hatIndex <= hatButtonStatus.size()) { hatButtonStatus.replace(hatIndex, value); } } QBitArray InputDeviceBitArrayStatus::generateFinalBitArray() { unsigned int totalArraySize = 0; totalArraySize = axesStatus.size() + hatButtonStatus.size() + buttonStatus.size(); QBitArray aggregateBitArray(totalArraySize, false); unsigned int currentBit = 0; for (int i=0; i < axesStatus.size(); i++) { aggregateBitArray.setBit(currentBit, axesStatus.at(i)); currentBit++; } for (int i=0; i < hatButtonStatus.size(); i++) { aggregateBitArray.setBit(currentBit, hatButtonStatus.at(i)); currentBit++; } for (int i=0; i < buttonStatus.size(); i++) { aggregateBitArray.setBit(currentBit, buttonStatus.at(i)); currentBit++; } return aggregateBitArray; } void InputDeviceBitArrayStatus::clearStatusValues() { for (int i=0; i < axesStatus.size(); i++) { axesStatus.replace(i, false); } for (int i=0; i < hatButtonStatus.size(); i++) { hatButtonStatus.replace(i, false); } buttonStatus.fill(false); } antimicro-2.23/src/inputdevicebitarraystatus.h000066400000000000000000000027171300750276700217240ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef INPUTDEVICESTATUSEVENT_H #define INPUTDEVICESTATUSEVENT_H #include #include #include #include "inputdevice.h" class InputDeviceBitArrayStatus : public QObject { Q_OBJECT public: explicit InputDeviceBitArrayStatus(InputDevice *device, bool readCurrent = true, QObject *parent = 0); void changeAxesStatus(int axisIndex, bool value); void changeButtonStatus(int buttonIndex, bool value); void changeHatStatus(int hatIndex, bool value); QBitArray generateFinalBitArray(); void clearStatusValues(); protected: QList axesStatus; QList hatButtonStatus; QBitArray buttonStatus; signals: public slots: }; #endif // INPUTDEVICESTATUSEVENT_H antimicro-2.23/src/joyaxis.cpp000066400000000000000000000657341300750276700164340ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include "joyaxis.h" #include "joycontrolstick.h" #include "inputdevice.h" #include "event.h" // Set default values for many properties. const int JoyAxis::AXISMIN = -32767; const int JoyAxis::AXISMAX = 32767; const int JoyAxis::AXISDEADZONE = 6000; const int JoyAxis::AXISMAXZONE = 32000; // Speed in pixels/second const float JoyAxis::JOYSPEED = 20.0; const JoyAxis::ThrottleTypes JoyAxis::DEFAULTTHROTTLE = JoyAxis::NormalThrottle; const QString JoyAxis::xmlName = "axis"; JoyAxis::JoyAxis(int index, int originset, SetJoystick *parentSet, QObject *parent) : QObject(parent) { stick = 0; lastKnownThottledValue = 0; lastKnownRawValue = 0; this->originset = originset; this->parentSet = parentSet; naxisbutton = new JoyAxisButton(this, 0, originset, parentSet, this); paxisbutton = new JoyAxisButton(this, 1, originset, parentSet, this); reset(); this->index = index; } JoyAxis::~JoyAxis() { reset(); } void JoyAxis::queuePendingEvent(int value, bool ignoresets, bool updateLastValues) { pendingEvent = false; pendingValue = 0; pendingIgnoreSets = false; //pendingUpdateLastValues = true; if (this->stick) { stickPassEvent(value, ignoresets, updateLastValues); } else { pendingEvent = true; pendingValue = value; pendingIgnoreSets = ignoresets; //pendingUpdateLastValues = updateLastValues; } } void JoyAxis::activatePendingEvent() { if (pendingEvent) { joyEvent(pendingValue, pendingIgnoreSets); pendingEvent = false; pendingValue = false; pendingIgnoreSets = false; //pendingUpdateLastValues = true; } } bool JoyAxis::hasPendingEvent() { return pendingEvent; } void JoyAxis::clearPendingEvent() { pendingEvent = false; pendingValue = false; pendingIgnoreSets = false; } void JoyAxis::stickPassEvent(int value, bool ignoresets, bool updateLastValues) { if (this->stick) { if (updateLastValues) { lastKnownThottledValue = currentThrottledValue; lastKnownRawValue = currentRawValue; } setCurrentRawValue(value); //currentRawValue = value; bool safezone = !inDeadZone(currentRawValue); currentThrottledValue = calculateThrottledValue(value); if (safezone && !isActive) { isActive = eventActive = true; emit active(value); } else if (!safezone && isActive) { isActive = eventActive = false; emit released(value); } if (!ignoresets) { stick->queueJoyEvent(ignoresets); } else { stick->joyEvent(ignoresets); } emit moved(currentRawValue); } } void JoyAxis::joyEvent(int value, bool ignoresets, bool updateLastValues) { if (this->stick && !pendingEvent) { stickPassEvent(value, ignoresets, updateLastValues); } else { if (updateLastValues) { lastKnownThottledValue = currentThrottledValue; lastKnownRawValue = currentRawValue; } setCurrentRawValue(value); //currentRawValue = value; bool safezone = !inDeadZone(currentRawValue); currentThrottledValue = calculateThrottledValue(value); // If in joystick mode and this is the first detected event, // use the current value as the axis center point. If the value // is below -30,000 then consider it a trigger. InputDevice *device = parentSet->getInputDevice(); if (!device->isGameController() && !device->hasCalibrationThrottle(index)) { performCalibration(currentRawValue); safezone = !inDeadZone(currentRawValue); currentThrottledValue = calculateThrottledValue(value); } if (safezone && !isActive) { isActive = eventActive = true; emit active(value); createDeskEvent(ignoresets); } else if (!safezone && isActive) { isActive = eventActive = false; emit released(value); createDeskEvent(ignoresets); } else if (isActive) { createDeskEvent(ignoresets); } } emit moved(currentRawValue); } bool JoyAxis::inDeadZone(int value) { bool result = false; int temp = calculateThrottledValue(value); if (abs(temp) <= deadZone) { result = true; } return result; } QString JoyAxis::getName(bool forceFullFormat, bool displayNames) { QString label = getPartialName(forceFullFormat, displayNames); label.append(": "); if (throttle == NormalThrottle) { label.append("-"); if (!naxisbutton->getActionName().isEmpty() && displayNames) { label.append(naxisbutton->getActionName()); } else { label.append(naxisbutton->getCalculatedActiveZoneSummary()); } label.append(" | +"); if (!paxisbutton->getActionName().isEmpty() && displayNames) { label.append(paxisbutton->getActionName()); } else { label.append(paxisbutton->getCalculatedActiveZoneSummary()); } } else if (throttle == PositiveThrottle || throttle == PositiveHalfThrottle) { label.append("+"); if (!paxisbutton->getActionName().isEmpty() && displayNames) { label.append(paxisbutton->getActionName()); } else { label.append(paxisbutton->getCalculatedActiveZoneSummary()); } } else if (throttle == NegativeThrottle || throttle == NegativeHalfThrottle) { label.append("-"); if (!naxisbutton->getActionName().isEmpty() && displayNames) { label.append(naxisbutton->getActionName()); } else { label.append(naxisbutton->getCalculatedActiveZoneSummary()); } } return label; } int JoyAxis::getRealJoyIndex() { return index + 1; } int JoyAxis::getCurrentThrottledValue() { return currentThrottledValue; } int JoyAxis::calculateThrottledValue(int value) { int temp = value; if (throttle == NegativeHalfThrottle) { value = value <= 0 ? value : -value; temp = value; } else if (throttle == NegativeThrottle) { temp = (value + AXISMIN) / 2; } else if (throttle == PositiveThrottle) { temp = (value + AXISMAX) / 2; } else if (throttle == PositiveHalfThrottle) { value = value >= 0 ? value : -value; temp = value; } return temp; } void JoyAxis::setIndex(int index) { this->index = index; } int JoyAxis::getIndex() { return index; } void JoyAxis::createDeskEvent(bool ignoresets) { JoyAxisButton *eventbutton = 0; if (currentThrottledValue > deadZone) { eventbutton = paxisbutton; } else if (currentThrottledValue < -deadZone) { eventbutton = naxisbutton; } if (eventbutton && !activeButton) { // There is no active button. Call joyEvent and set current // button as active button eventbutton->joyEvent(eventActive, ignoresets); activeButton = eventbutton; } else if (!eventbutton && activeButton) { // Currently in deadzone. Disable currently active button. activeButton->joyEvent(eventActive, ignoresets); activeButton = 0; } else if (eventbutton && activeButton && eventbutton == activeButton) { //Button is currently active. Just pass current value eventbutton->joyEvent(eventActive, ignoresets); } else if (eventbutton && activeButton && eventbutton != activeButton) { // Deadzone skipped. Button for new event is not the currently // active button. Disable the active button before enabling // the new button activeButton->joyEvent(!eventActive, ignoresets); eventbutton->joyEvent(eventActive, ignoresets); activeButton = eventbutton; } } void JoyAxis::setDeadZone(int value) { deadZone = abs(value); emit propertyUpdated(); } int JoyAxis::getDeadZone() { return deadZone; } void JoyAxis::setMaxZoneValue(int value) { value = abs(value); if (value >= AXISMAX) { maxZoneValue = AXISMAX; emit propertyUpdated(); } else { maxZoneValue = value; emit propertyUpdated(); } } int JoyAxis::getMaxZoneValue() { return maxZoneValue; } /** * @brief Set throttle value for axis. * @param Current value for axis. */ void JoyAxis::setThrottle(int value) { if (value >= JoyAxis::NegativeHalfThrottle && value <= JoyAxis::PositiveHalfThrottle) { if (value != throttle) { throttle = value; adjustRange(); emit throttleChanged(); emit propertyUpdated(); } } } /** * @brief Set the initial calibrated throttle based on the first event * passed by SDL. * @param Current value for axis. */ void JoyAxis::setInitialThrottle(int value) { if (value >= JoyAxis::NegativeHalfThrottle && value <= JoyAxis::PositiveHalfThrottle) { if (value != throttle) { throttle = value; adjustRange(); emit throttleChanged(); } } } int JoyAxis::getThrottle() { return throttle; } void JoyAxis::readConfig(QXmlStreamReader *xml) { if (xml->isStartElement() && xml->name() == getXmlName()) { //reset(); xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != getXmlName())) { bool found = false; found = readMainConfig(xml); if (!found && xml->name() == naxisbutton->getXmlName() && xml->isStartElement()) { found = true; readButtonConfig(xml); } if (!found) { xml->skipCurrentElement(); } xml->readNextStartElement(); } } } void JoyAxis::writeConfig(QXmlStreamWriter *xml) { bool currentlyDefault = isDefault(); xml->writeStartElement(getXmlName()); xml->writeAttribute("index", QString::number(index+1)); if (!currentlyDefault) { if (deadZone != AXISDEADZONE) { xml->writeTextElement("deadZone", QString::number(deadZone)); } if (maxZoneValue != AXISMAXZONE) { xml->writeTextElement("maxZone", QString::number(maxZoneValue)); } } //if (throttle != DEFAULTTHROTTLE) //{ xml->writeStartElement("throttle"); if (throttle == JoyAxis::NegativeHalfThrottle) { xml->writeCharacters("negativehalf"); } else if (throttle == JoyAxis::NegativeThrottle) { xml->writeCharacters("negative"); } else if (throttle == JoyAxis::NormalThrottle) { xml->writeCharacters("normal"); } else if (throttle == JoyAxis::PositiveThrottle) { xml->writeCharacters("positive"); } else if (throttle == JoyAxis::PositiveHalfThrottle) { xml->writeCharacters("positivehalf"); } xml->writeEndElement(); //} if (!currentlyDefault) { naxisbutton->writeConfig(xml); paxisbutton->writeConfig(xml); } xml->writeEndElement(); } bool JoyAxis::readMainConfig(QXmlStreamReader *xml) { bool found = false; if (xml->name() == "deadZone" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); int tempchoice = temptext.toInt(); this->setDeadZone(tempchoice); } else if (xml->name() == "maxZone" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); int tempchoice = temptext.toInt(); this->setMaxZoneValue(tempchoice); } else if (xml->name() == "throttle" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); if (temptext == "negativehalf") { this->setThrottle(JoyAxis::NegativeHalfThrottle); } else if (temptext == "negative") { this->setThrottle(JoyAxis::NegativeThrottle); } else if (temptext == "normal") { this->setThrottle(JoyAxis::NormalThrottle); } else if (temptext == "positive") { this->setThrottle(JoyAxis::PositiveThrottle); } else if (temptext == "positivehalf") { this->setThrottle(JoyAxis::PositiveHalfThrottle); } InputDevice *device = parentSet->getInputDevice(); if (!device->hasCalibrationThrottle(index)) { device->setCalibrationStatus(index, static_cast(throttle)); } setCurrentRawValue(currentThrottledDeadValue); //currentRawValue = currentThrottledDeadValue; currentThrottledValue = calculateThrottledValue(currentRawValue); } return found; } bool JoyAxis::readButtonConfig(QXmlStreamReader *xml) { bool found = false; int index = xml->attributes().value("index").toString().toInt(); if (index == 1) { found = true; naxisbutton->readConfig(xml); } else if (index == 2) { found = true; paxisbutton->readConfig(xml); } return found; } void JoyAxis::reset() { deadZone = getDefaultDeadZone(); isActive = false; eventActive = false; maxZoneValue = getDefaultMaxZone(); throttle = getDefaultThrottle(); paxisbutton->reset(); naxisbutton->reset(); activeButton = 0; lastKnownThottledValue = 0; lastKnownRawValue = 0; adjustRange(); setCurrentRawValue(currentThrottledDeadValue); currentThrottledValue = calculateThrottledValue(currentRawValue); axisName.clear(); pendingEvent = false; pendingValue = currentRawValue; pendingIgnoreSets = false; //pendingUpdateLastValues = true; } void JoyAxis::reset(int index) { reset(); this->index = index; } JoyAxisButton* JoyAxis::getPAxisButton() { return paxisbutton; } JoyAxisButton* JoyAxis::getNAxisButton() { return naxisbutton; } int JoyAxis::getCurrentRawValue() { return currentRawValue; } void JoyAxis::adjustRange() { if (throttle == JoyAxis::NegativeThrottle) { currentThrottledDeadValue = AXISMAX; } else if (throttle == JoyAxis::NormalThrottle || throttle == JoyAxis::PositiveHalfThrottle || throttle == JoyAxis::NegativeHalfThrottle) { currentThrottledDeadValue = 0; } else if (throttle == JoyAxis::PositiveThrottle) { currentThrottledDeadValue = AXISMIN; } currentThrottledValue = calculateThrottledValue(currentRawValue); } int JoyAxis::getCurrentThrottledDeadValue() { return currentThrottledDeadValue; } double JoyAxis::getDistanceFromDeadZone() { return getDistanceFromDeadZone(currentThrottledValue); } double JoyAxis::getDistanceFromDeadZone(int value) { double distance = 0.0; int currentValue = value; if (currentValue >= deadZone) { distance = (currentValue - deadZone)/static_cast(maxZoneValue - deadZone); } else if (currentValue <= -deadZone) { distance = (currentValue + deadZone)/static_cast(-maxZoneValue + deadZone); } distance = qBound(0.0, distance, 1.0); return distance; } /** * @brief Get the current value for an axis in either direction converted to * the range of -1.0 to 1.0. * @param Current interger value of the axis * @return Axis value in the range of -1.0 to 1.0 */ double JoyAxis::getRawDistance(int value) { double distance = 0.0; int currentValue = value; distance = currentValue / static_cast(maxZoneValue); distance = qBound(-1.0, distance, 1.0); return distance; } void JoyAxis::propogateThrottleChange() { emit throttleChangePropogated(this->index); } int JoyAxis::getCurrentlyAssignedSet() { return originset; } void JoyAxis::setControlStick(JoyControlStick *stick) { removeVDPads(); removeControlStick(); this->stick = stick; emit propertyUpdated(); } bool JoyAxis::isPartControlStick() { return (this->stick != 0); } JoyControlStick* JoyAxis::getControlStick() { return this->stick; } void JoyAxis::removeControlStick(bool performRelease) { if (stick) { if (performRelease) { stick->releaseButtonEvents(); } this->stick = 0; emit propertyUpdated(); } } bool JoyAxis::hasControlOfButtons() { bool value = true; if (paxisbutton->isPartVDPad() || naxisbutton->isPartVDPad()) { value = false; } return value; } void JoyAxis::removeVDPads() { if (paxisbutton->isPartVDPad()) { paxisbutton->joyEvent(false, true); paxisbutton->removeVDPad(); } if (naxisbutton->isPartVDPad()) { naxisbutton->joyEvent(false, true); naxisbutton->removeVDPad(); } } bool JoyAxis::isDefault() { bool value = true; value = value && (deadZone == getDefaultDeadZone()); value = value && (maxZoneValue == getDefaultMaxZone()); //value = value && (throttle == getDefaultThrottle()); value = value && (paxisbutton->isDefault()); value = value && (naxisbutton->isDefault()); return value; } /* Use this method to keep currentRawValue in the expected range. * SDL has a minimum axis value of -32768 which should be ignored to * ensure that JoyControlStick will not encounter overflow problems * on a 32 bit machine. */ void JoyAxis::setCurrentRawValue(int value) { if (value >= JoyAxis::AXISMIN && value <= JoyAxis::AXISMAX) { currentRawValue = value; } else if (value > JoyAxis::AXISMAX) { currentRawValue = JoyAxis::AXISMAX; } else if (value < JoyAxis::AXISMIN) { currentRawValue = JoyAxis::AXISMIN; } } void JoyAxis::setButtonsMouseMode(JoyButton::JoyMouseMovementMode mode) { paxisbutton->setMouseMode(mode); naxisbutton->setMouseMode(mode); } bool JoyAxis::hasSameButtonsMouseMode() { bool result = true; if (paxisbutton->getMouseMode() != naxisbutton->getMouseMode()) { result = false; } return result; } JoyButton::JoyMouseMovementMode JoyAxis::getButtonsPresetMouseMode() { JoyButton::JoyMouseMovementMode resultMode = JoyButton::MouseCursor; if (paxisbutton->getMouseMode() == naxisbutton->getMouseMode()) { resultMode = paxisbutton->getMouseMode(); } return resultMode; } void JoyAxis::setButtonsMouseCurve(JoyButton::JoyMouseCurve mouseCurve) { paxisbutton->setMouseCurve(mouseCurve); naxisbutton->setMouseCurve(mouseCurve); } bool JoyAxis::hasSameButtonsMouseCurve() { bool result = true; if (paxisbutton->getMouseCurve() != naxisbutton->getMouseCurve()) { result = false; } return result; } JoyButton::JoyMouseCurve JoyAxis::getButtonsPresetMouseCurve() { JoyButton::JoyMouseCurve resultCurve = JoyButton::LinearCurve; if (paxisbutton->getMouseCurve() == naxisbutton->getMouseCurve()) { resultCurve = paxisbutton->getMouseCurve(); } return resultCurve; } void JoyAxis::setButtonsSpringWidth(int value) { paxisbutton->setSpringWidth(value); naxisbutton->setSpringWidth(value); } void JoyAxis::setButtonsSpringHeight(int value) { paxisbutton->setSpringHeight(value); naxisbutton->setSpringHeight(value); } int JoyAxis::getButtonsPresetSpringWidth() { int presetSpringWidth = 0; if (paxisbutton->getSpringWidth() == naxisbutton->getSpringWidth()) { presetSpringWidth = paxisbutton->getSpringWidth(); } return presetSpringWidth; } int JoyAxis::getButtonsPresetSpringHeight() { int presetSpringHeight = 0; if (paxisbutton->getSpringHeight() == naxisbutton->getSpringHeight()) { presetSpringHeight = paxisbutton->getSpringHeight(); } return presetSpringHeight; } void JoyAxis::setButtonsSensitivity(double value) { paxisbutton->setSensitivity(value); naxisbutton->setSensitivity(value); } double JoyAxis::getButtonsPresetSensitivity() { double presetSensitivity = 1.0; if (paxisbutton->getSensitivity() == naxisbutton->getSensitivity()) { presetSensitivity = paxisbutton->getSensitivity(); } return presetSensitivity; } JoyAxisButton* JoyAxis::getAxisButtonByValue(int value) { JoyAxisButton *eventbutton = 0; int throttledValue = calculateThrottledValue(value); if (throttledValue > deadZone) { eventbutton = paxisbutton; } else if (throttledValue < -deadZone) { eventbutton = naxisbutton; } return eventbutton; } void JoyAxis::setAxisName(QString tempName) { if (tempName.length() <= 20 && tempName != axisName) { axisName = tempName; emit axisNameChanged(); emit propertyUpdated(); } } QString JoyAxis::getAxisName() { return axisName; } void JoyAxis::setButtonsWheelSpeedX(int value) { paxisbutton->setWheelSpeedX(value); naxisbutton->setWheelSpeedX(value); } void JoyAxis::setButtonsWheelSpeedY(int value) { paxisbutton->setWheelSpeedY(value); naxisbutton->setWheelSpeedY(value); } void JoyAxis::setDefaultAxisName(QString tempname) { defaultAxisName = tempname; } QString JoyAxis::getDefaultAxisName() { return defaultAxisName; } QString JoyAxis::getPartialName(bool forceFullFormat, bool displayNames) { QString label; if (!axisName.isEmpty() && displayNames) { if (forceFullFormat) { label.append(tr("Axis")).append(" "); } label.append(axisName); } else if (!defaultAxisName.isEmpty()) { if (forceFullFormat) { label.append(tr("Axis")).append(" "); } label.append(defaultAxisName); } else { label.append(tr("Axis")).append(" "); label.append(QString::number(getRealJoyIndex())); } return label; } QString JoyAxis::getXmlName() { return this->xmlName; } int JoyAxis::getDefaultDeadZone() { return this->AXISDEADZONE; } int JoyAxis::getDefaultMaxZone() { return this->AXISMAXZONE; } JoyAxis::ThrottleTypes JoyAxis::getDefaultThrottle() { return this->DEFAULTTHROTTLE; } SetJoystick* JoyAxis::getParentSet() { return parentSet; } void JoyAxis::establishPropertyUpdatedConnection() { connect(this, SIGNAL(propertyUpdated()), getParentSet()->getInputDevice(), SLOT(profileEdited())); } void JoyAxis::disconnectPropertyUpdatedConnection() { disconnect(this, SIGNAL(propertyUpdated()), getParentSet()->getInputDevice(), SLOT(profileEdited())); } void JoyAxis::setButtonsSpringRelativeStatus(bool value) { paxisbutton->setSpringRelativeStatus(value); naxisbutton->setSpringRelativeStatus(value); } bool JoyAxis::isRelativeSpring() { bool relative = false; if (paxisbutton->isRelativeSpring() == naxisbutton->isRelativeSpring()) { relative = paxisbutton->isRelativeSpring(); } return relative; } void JoyAxis::performCalibration(int value) { InputDevice *device = parentSet->getInputDevice(); if (value <= -30000) { // Assume axis is a trigger. Set default throttle to Positive. device->setCalibrationThrottle(index, PositiveThrottle); } else { // Ensure that default throttle is used when a device is reset. device->setCalibrationThrottle(index, static_cast(throttle)); } //else if (value >= -15000 && value <= 15000) //{ // device->setCalibrationThrottle(index, NormalThrottle); //} } void JoyAxis::copyAssignments(JoyAxis *destAxis) { destAxis->reset(); destAxis->deadZone = deadZone; destAxis->maxZoneValue = maxZoneValue; destAxis->axisName = axisName; paxisbutton->copyAssignments(destAxis->paxisbutton); naxisbutton->copyAssignments(destAxis->naxisbutton); if (!destAxis->isDefault()) { emit propertyUpdated(); } } void JoyAxis::setButtonsEasingDuration(double value) { paxisbutton->setEasingDuration(value); naxisbutton->setEasingDuration(value); } double JoyAxis::getButtonsEasingDuration() { double result = JoyButton::DEFAULTEASINGDURATION; if (paxisbutton->getEasingDuration() == naxisbutton->getEasingDuration()) { result = paxisbutton->getEasingDuration(); } return result; } int JoyAxis::getLastKnownThrottleValue() { return lastKnownThottledValue; } int JoyAxis::getLastKnownRawValue() { return lastKnownRawValue; } /** * @brief Determine an appropriate release value for an axis depending * on the current throttle setting being used. * @return Release value for an axis */ int JoyAxis::getProperReleaseValue() { // Handles NormalThrottle case int value = 0; if (throttle == NegativeHalfThrottle) { value = 0; } else if (throttle == NegativeThrottle) { value = JoyAxis::AXISMAX; } else if (throttle == PositiveThrottle) { value = JoyAxis::AXISMIN; } else if (throttle == PositiveHalfThrottle) { value = 0; } return value; } void JoyAxis::setExtraAccelerationCurve(JoyButton::JoyExtraAccelerationCurve curve) { paxisbutton->setExtraAccelerationCurve(curve); naxisbutton->setExtraAccelerationCurve(curve); } JoyButton::JoyExtraAccelerationCurve JoyAxis::getExtraAccelerationCurve() { JoyButton::JoyExtraAccelerationCurve result = JoyButton::LinearAccelCurve; if (paxisbutton->getExtraAccelerationCurve() == naxisbutton->getExtraAccelerationCurve()) { result = paxisbutton->getExtraAccelerationCurve(); } return result; } void JoyAxis::copyRawValues(JoyAxis *srcAxis) { this->lastKnownRawValue = srcAxis->lastKnownRawValue; this->currentRawValue = srcAxis->currentRawValue; } void JoyAxis::copyThrottledValues(JoyAxis *srcAxis) { this->lastKnownThottledValue = srcAxis->lastKnownThottledValue; this->currentThrottledValue = srcAxis->currentThrottledValue; } void JoyAxis::eventReset() { naxisbutton->eventReset(); paxisbutton->eventReset(); } antimicro-2.23/src/joyaxis.h000066400000000000000000000144751300750276700160750ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYAXIS_H #define JOYAXIS_H #include #include #include #include #include #include #include "joybuttontypes/joyaxisbutton.h" class JoyControlStick; class JoyAxis : public QObject { Q_OBJECT public: explicit JoyAxis(int index, int originset, SetJoystick *parentSet, QObject *parent=0); ~JoyAxis(); enum ThrottleTypes { NegativeHalfThrottle = -2, NegativeThrottle = -1, NormalThrottle = 0, PositiveThrottle = 1, PositiveHalfThrottle = 2 }; void joyEvent(int value, bool ignoresets=false, bool updateLastValues=true); void queuePendingEvent(int value, bool ignoresets=false, bool updateLastValues=true); void activatePendingEvent(); bool hasPendingEvent(); void clearPendingEvent(); bool inDeadZone(int value); virtual QString getName(bool forceFullFormat=false, bool displayNames=false); virtual QString getPartialName(bool forceFullFormat=false, bool displayNames=false); virtual QString getXmlName(); void setIndex(int index); int getIndex(); int getRealJoyIndex(); JoyAxisButton *getPAxisButton(); JoyAxisButton *getNAxisButton(); int getDeadZone(); int getMaxZoneValue(); void setThrottle(int value); void setInitialThrottle(int value); int getThrottle(); int getCurrentThrottledValue(); int getCurrentRawValue(); //int getCurrentThrottledMin(); //int getCurrentThrottledMax(); int getCurrentThrottledDeadValue(); int getCurrentlyAssignedSet(); JoyAxisButton* getAxisButtonByValue(int value); double getDistanceFromDeadZone(); double getDistanceFromDeadZone(int value); double getRawDistance(int value); virtual void readConfig(QXmlStreamReader *xml); virtual void writeConfig(QXmlStreamWriter *xml); void setControlStick(JoyControlStick *stick); void removeControlStick(bool performRelease = true); bool isPartControlStick(); JoyControlStick* getControlStick(); bool hasControlOfButtons(); void removeVDPads(); void setButtonsMouseMode(JoyButton::JoyMouseMovementMode mode); bool hasSameButtonsMouseMode(); JoyButton::JoyMouseMovementMode getButtonsPresetMouseMode(); void setButtonsMouseCurve(JoyButton::JoyMouseCurve mouseCurve); bool hasSameButtonsMouseCurve(); JoyButton::JoyMouseCurve getButtonsPresetMouseCurve(); void setButtonsSpringWidth(int value); int getButtonsPresetSpringWidth(); void setButtonsSpringHeight(int value); int getButtonsPresetSpringHeight(); void setButtonsSensitivity(double value); double getButtonsPresetSensitivity(); void setButtonsWheelSpeedX(int value); void setButtonsWheelSpeedY(int value); double getButtonsEasingDuration(); virtual QString getAxisName(); virtual int getDefaultDeadZone(); virtual int getDefaultMaxZone(); virtual ThrottleTypes getDefaultThrottle(); virtual void setDefaultAxisName(QString tempname); virtual QString getDefaultAxisName(); SetJoystick* getParentSet(); virtual bool isDefault(); bool isRelativeSpring(); void copyAssignments(JoyAxis *destAxis); int getLastKnownThrottleValue(); int getLastKnownRawValue(); int getProperReleaseValue(); // Don't use direct assignment but copying from a current axis. void copyRawValues(JoyAxis *srcAxis); void copyThrottledValues(JoyAxis *srcAxis); void setExtraAccelerationCurve(JoyButton::JoyExtraAccelerationCurve curve); JoyButton::JoyExtraAccelerationCurve getExtraAccelerationCurve(); virtual void eventReset(); // Define default values for many properties. static const int AXISMIN; static const int AXISMAX; static const int AXISDEADZONE; static const int AXISMAXZONE; static const ThrottleTypes DEFAULTTHROTTLE; static const float JOYSPEED; static const QString xmlName; protected: void createDeskEvent(bool ignoresets = false); void adjustRange(); int calculateThrottledValue(int value); void setCurrentRawValue(int value); void performCalibration(int value); void stickPassEvent(int value, bool ignoresets=false, bool updateLastValues=true); virtual bool readMainConfig(QXmlStreamReader *xml); virtual bool readButtonConfig(QXmlStreamReader *xml); int index; int deadZone; int maxZoneValue; bool isActive; JoyAxisButton *paxisbutton; JoyAxisButton *naxisbutton; bool eventActive; int currentThrottledValue; int currentRawValue; int throttle; JoyAxisButton *activeButton; int originset; int currentThrottledDeadValue; JoyControlStick *stick; QString axisName; QString defaultAxisName; SetJoystick *parentSet; int lastKnownThottledValue; int lastKnownRawValue; int pendingValue; bool pendingEvent; bool pendingIgnoreSets; // TODO: CHECK IF PROPERTY IS NEEDED. //bool pendingUpdateLastValues; signals: void active(int value); void released(int value); void moved(int value); void throttleChangePropogated(int index); void throttleChanged(); void axisNameChanged(); void propertyUpdated(); public slots: virtual void reset(); virtual void reset(int index); void propogateThrottleChange(); void setDeadZone(int value); void setMaxZoneValue(int value); void setAxisName(QString tempName); void setButtonsSpringRelativeStatus(bool value); void setButtonsEasingDuration(double value); void establishPropertyUpdatedConnection(); void disconnectPropertyUpdatedConnection(); }; #endif // JOYAXIS_H antimicro-2.23/src/joyaxiscontextmenu.cpp000066400000000000000000000464671300750276700207300ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "joyaxiscontextmenu.h" #include "mousedialog/mouseaxissettingsdialog.h" #include "antkeymapper.h" #include "inputdevice.h" #include "common.h" JoyAxisContextMenu::JoyAxisContextMenu(JoyAxis *axis, QWidget *parent) : QMenu(parent), helper(axis) { this->axis = axis; helper.moveToThread(axis->thread()); connect(this, SIGNAL(aboutToHide()), this, SLOT(deleteLater())); } void JoyAxisContextMenu::buildMenu() { bool actAsTrigger = false; PadderCommon::inputDaemonMutex.lock(); if (axis->getThrottle() == JoyAxis::PositiveThrottle || axis->getThrottle() == JoyAxis::PositiveHalfThrottle) { actAsTrigger = true; } PadderCommon::inputDaemonMutex.unlock(); if (actAsTrigger) { buildTriggerMenu(); } else { buildAxisMenu(); } } void JoyAxisContextMenu::buildAxisMenu() { QAction *action = 0; QActionGroup *presetGroup = new QActionGroup(this); int presetMode = 0; int currentPreset = getPresetIndex(); action = this->addAction(tr("Mouse (Horizontal)")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setAxisPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("Mouse (Inverted Horizontal)")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setAxisPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("Mouse (Vertical)")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setAxisPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("Mouse (Inverted Vertical)")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setAxisPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("Arrows: Up | Down")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setAxisPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("Arrows: Left | Right")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setAxisPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("Keys: W | S")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setAxisPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("Keys: A | D")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setAxisPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("NumPad: KP_8 | KP_2")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setAxisPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("NumPad: KP_4 | KP_6")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setAxisPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("None")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setAxisPreset())); presetGroup->addAction(action); this->addSeparator(); action = this->addAction(tr("Mouse Settings")); action->setCheckable(false); connect(action, SIGNAL(triggered()), this, SLOT(openMouseSettingsDialog())); } int JoyAxisContextMenu::getPresetIndex() { int result = 0; PadderCommon::inputDaemonMutex.lock(); JoyAxisButton *naxisbutton = axis->getNAxisButton(); QList *naxisslots = naxisbutton->getAssignedSlots(); JoyAxisButton *paxisbutton = axis->getPAxisButton(); QList *paxisslots = paxisbutton->getAssignedSlots(); if (naxisslots->length() == 1 && paxisslots->length() == 1) { JoyButtonSlot *nslot = naxisslots->at(0); JoyButtonSlot *pslot = paxisslots->at(0); if (nslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && nslot->getSlotCode() == JoyButtonSlot::MouseLeft && pslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && pslot->getSlotCode() == JoyButtonSlot::MouseRight) { result = 1; } else if (nslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && nslot->getSlotCode() == JoyButtonSlot::MouseRight && pslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && pslot->getSlotCode() == JoyButtonSlot::MouseLeft) { result = 2; } else if (nslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && nslot->getSlotCode() == JoyButtonSlot::MouseUp && pslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && pslot->getSlotCode() == JoyButtonSlot::MouseDown) { result = 3; } else if (nslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && nslot->getSlotCode() == JoyButtonSlot::MouseDown && pslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && pslot->getSlotCode() == JoyButtonSlot::MouseUp) { result = 4; } else if (nslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)nslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Up) && pslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)pslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Down)) { result = 5; } else if (nslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)nslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Left) && pslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)pslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Right)) { result = 6; } else if (nslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)nslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_W) && pslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)pslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_S)) { result = 7; } else if (nslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)nslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_A) && pslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)pslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_D)) { result = 8; } else if (nslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)nslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_8) && pslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)pslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_2)) { result = 9; } else if (nslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)nslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_4) && pslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && (unsigned int)pslot->getSlotCode() == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_6)) { result = 10; } } else if (naxisslots->length() == 0 && paxisslots->length() == 0) { result = 11; } PadderCommon::inputDaemonMutex.unlock(); return result; } void JoyAxisContextMenu::setAxisPreset() { //PadderCommon::lockInputDevices(); //InputDevice *tempDevice = axis->getParentSet()->getInputDevice(); //QMetaObject::invokeMethod(tempDevice, "haltServices", Qt::BlockingQueuedConnection); QAction *action = static_cast(sender()); int item = action->data().toInt(); JoyButtonSlot *nbuttonslot = 0; JoyButtonSlot *pbuttonslot = 0; if (item == 0) { nbuttonslot = new JoyButtonSlot(JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); pbuttonslot = new JoyButtonSlot(JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); } else if (item == 1) { nbuttonslot = new JoyButtonSlot(JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); pbuttonslot = new JoyButtonSlot(JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); } else if (item == 2) { nbuttonslot = new JoyButtonSlot(JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); pbuttonslot = new JoyButtonSlot(JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); } else if (item == 3) { nbuttonslot = new JoyButtonSlot(JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); pbuttonslot = new JoyButtonSlot(JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); } else if (item == 4) { nbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Up), Qt::Key_Up, JoyButtonSlot::JoyKeyboard, this); pbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Down), Qt::Key_Down, JoyButtonSlot::JoyKeyboard, this); } else if (item == 5) { nbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Left), Qt::Key_Left, JoyButtonSlot::JoyKeyboard, this); pbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Right), Qt::Key_Right, JoyButtonSlot::JoyKeyboard, this); } else if (item == 6) { nbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_W), Qt::Key_W, JoyButtonSlot::JoyKeyboard, this); pbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_S), Qt::Key_S, JoyButtonSlot::JoyKeyboard, this); } else if (item == 7) { nbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_A), Qt::Key_A, JoyButtonSlot::JoyKeyboard, this); pbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_D), Qt::Key_D, JoyButtonSlot::JoyKeyboard, this); } else if (item == 8) { nbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_8), QtKeyMapperBase::AntKey_KP_8, JoyButtonSlot::JoyKeyboard, this); pbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_2), QtKeyMapperBase::AntKey_KP_2, JoyButtonSlot::JoyKeyboard, this); } else if (item == 9) { nbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_4), QtKeyMapperBase::AntKey_KP_4, JoyButtonSlot::JoyKeyboard, this); pbuttonslot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_6), QtKeyMapperBase::AntKey_KP_6, JoyButtonSlot::JoyKeyboard, this); } else if (item == 10) { QMetaObject::invokeMethod(&helper, "clearAndResetAxisButtons", Qt::BlockingQueuedConnection); } if (nbuttonslot) { QMetaObject::invokeMethod(&helper, "setNAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, nbuttonslot->getSlotCode()), Q_ARG(unsigned int, nbuttonslot->getSlotCodeAlias()), Q_ARG(JoyButtonSlot::JoySlotInputAction, nbuttonslot->getSlotMode())); //JoyAxisButton *button = axis->getNAxisButton(); //QMetaObject::invokeMethod(button, "clearSlotsEventReset", // Q_ARG(bool, false)); //button->clearSlotsEventReset(false); /*QMetaObject::invokeMethod(button, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, nbuttonslot->getSlotCode()), Q_ARG(unsigned int, nbuttonslot->getSlotCodeAlias()), Q_ARG(JoyButtonSlot::JoySlotInputAction, nbuttonslot->getSlotMode())); */ //button->setAssignedSlot(nbuttonslot->getSlotCode(), nbuttonslot->getSlotCodeAlias(), nbuttonslot->getSlotMode()); nbuttonslot->deleteLater(); } if (pbuttonslot) { QMetaObject::invokeMethod(&helper, "setPAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, nbuttonslot->getSlotCode()), Q_ARG(unsigned int, nbuttonslot->getSlotCodeAlias()), Q_ARG(JoyButtonSlot::JoySlotInputAction, nbuttonslot->getSlotMode())); //JoyAxisButton *button = axis->getPAxisButton(); //QMetaObject::invokeMethod(button, "clearSlotsEventReset", // Q_ARG(bool, false)); //button->clearSlotsEventReset(false); /*QMetaObject::invokeMethod(button, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, pbuttonslot->getSlotCode()), Q_ARG(unsigned int, pbuttonslot->getSlotCodeAlias()), Q_ARG(JoyButtonSlot::JoySlotInputAction, pbuttonslot->getSlotMode())); */ //button->setAssignedSlot(pbuttonslot->getSlotCode(), pbuttonslot->getSlotCodeAlias(), pbuttonslot->getSlotMode()); pbuttonslot->deleteLater(); } //PadderCommon::unlockInputDevices(); } void JoyAxisContextMenu::openMouseSettingsDialog() { MouseAxisSettingsDialog *dialog = new MouseAxisSettingsDialog(this->axis, parentWidget()); dialog->show(); } void JoyAxisContextMenu::buildTriggerMenu() { QAction *action = 0; QActionGroup *presetGroup = new QActionGroup(this); int presetMode = 0; int currentPreset = getTriggerPresetIndex(); action = this->addAction(tr("Left Mouse Button")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setTriggerPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("Right Mouse Button")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setTriggerPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("None")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setTriggerPreset())); presetGroup->addAction(action); this->addSeparator(); action = this->addAction(tr("Mouse Settings")); action->setCheckable(false); connect(action, SIGNAL(triggered()), this, SLOT(openMouseSettingsDialog())); } int JoyAxisContextMenu::getTriggerPresetIndex() { int result = 0; PadderCommon::inputDaemonMutex.lock(); JoyAxisButton *paxisbutton = axis->getPAxisButton(); QList *paxisslots = paxisbutton->getAssignedSlots(); if (paxisslots->length() == 1) { JoyButtonSlot *pslot = paxisslots->at(0); if (pslot->getSlotMode() == JoyButtonSlot::JoyMouseButton && pslot->getSlotCode() == JoyButtonSlot::MouseLB) { result = 1; } else if (pslot->getSlotMode() == JoyButtonSlot::JoyMouseButton && pslot->getSlotCode() == JoyButtonSlot::MouseRB) { result = 2; } } else if (paxisslots->length() == 0) { result = 3; } PadderCommon::inputDaemonMutex.unlock(); return result; } void JoyAxisContextMenu::setTriggerPreset() { QAction *action = static_cast(sender()); int item = action->data().toInt(); JoyButtonSlot *pbuttonslot = 0; if (item == 0) { pbuttonslot = new JoyButtonSlot(JoyButtonSlot::MouseLB, JoyButtonSlot::JoyMouseButton, this); } else if (item == 1) { pbuttonslot = new JoyButtonSlot(JoyButtonSlot::MouseRB, JoyButtonSlot::JoyMouseButton, this); } else if (item == 2) { JoyAxisButton *pbutton = axis->getPAxisButton(); QMetaObject::invokeMethod(pbutton, "clearSlotsEventReset", Qt::BlockingQueuedConnection); } if (pbuttonslot) { QMetaObject::invokeMethod(&helper, "setPAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, pbuttonslot->getSlotCode()), Q_ARG(unsigned int, pbuttonslot->getSlotCodeAlias()), Q_ARG(JoyButtonSlot::JoySlotInputAction, pbuttonslot->getSlotMode())); //JoyAxisButton *button = axis->getPAxisButton(); //QMetaObject::invokeMethod(button, "clearSlotsEventReset", // Q_ARG(bool, false)); //button->clearSlotsEventReset(false); /*QMetaObject::invokeMethod(button, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, pbuttonslot->getSlotCode()), Q_ARG(unsigned int, pbuttonslot->getSlotCodeAlias()), Q_ARG(JoyButtonSlot::JoySlotInputAction, pbuttonslot->getSlotMode())); */ //button->setAssignedSlot(pbuttonslot->getSlotCode(), pbuttonslot->getSlotCodeAlias(), pbuttonslot->getSlotMode()); pbuttonslot->deleteLater(); } } antimicro-2.23/src/joyaxiscontextmenu.h000066400000000000000000000025771300750276700203670ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYAXISCONTEXTMENU_H #define JOYAXISCONTEXTMENU_H #include #include "joyaxis.h" #include "uihelpers/joyaxiscontextmenuhelper.h" class JoyAxisContextMenu : public QMenu { Q_OBJECT public: explicit JoyAxisContextMenu(JoyAxis *axis, QWidget *parent = 0); void buildMenu(); void buildAxisMenu(); void buildTriggerMenu(); protected: int getPresetIndex(); int getTriggerPresetIndex(); JoyAxis *axis; JoyAxisContextMenuHelper helper; signals: public slots: private slots: void setAxisPreset(); void setTriggerPreset(); void openMouseSettingsDialog(); }; #endif // JOYAXISCONTEXTMENU_H antimicro-2.23/src/joyaxiswidget.cpp000066400000000000000000000063731300750276700176320ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "joyaxiswidget.h" #include "joyaxiscontextmenu.h" JoyAxisWidget::JoyAxisWidget(JoyAxis *axis, bool displayNames, QWidget *parent) : FlashButtonWidget(displayNames, parent) { this->axis = axis; refreshLabel(); enableFlashes(); this->setContextMenuPolicy(Qt::CustomContextMenu); connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint&))); JoyAxisButton *nAxisButton = axis->getNAxisButton(); JoyAxisButton *pAxisButton = axis->getPAxisButton(); tryFlash(); connect(axis, SIGNAL(throttleChanged()), this, SLOT(refreshLabel())); connect(axis, SIGNAL(axisNameChanged()), this, SLOT(refreshLabel())); //connect(nAxisButton, SIGNAL(slotsChanged()), this, SLOT(refreshLabel())); //connect(pAxisButton, SIGNAL(slotsChanged()), this, SLOT(refreshLabel())); connect(nAxisButton, SIGNAL(propertyUpdated()), this, SLOT(refreshLabel())); connect(pAxisButton, SIGNAL(propertyUpdated()), this, SLOT(refreshLabel())); connect(nAxisButton, SIGNAL(activeZoneChanged()), this, SLOT(refreshLabel())); connect(pAxisButton, SIGNAL(activeZoneChanged()), this, SLOT(refreshLabel())); axis->establishPropertyUpdatedConnection(); nAxisButton->establishPropertyUpdatedConnections(); pAxisButton->establishPropertyUpdatedConnections(); } JoyAxis* JoyAxisWidget::getAxis() { return axis; } void JoyAxisWidget::disableFlashes() { disconnect(axis, SIGNAL(active(int)), this, SLOT(flash())); disconnect(axis, SIGNAL(released(int)), this, SLOT(unflash())); this->unflash(); } void JoyAxisWidget::enableFlashes() { connect(axis, SIGNAL(active(int)), this, SLOT(flash()), Qt::QueuedConnection); connect(axis, SIGNAL(released(int)), this, SLOT(unflash()), Qt::QueuedConnection); } /** * @brief Generate the string that will be displayed on the button * @return Display string */ QString JoyAxisWidget::generateLabel() { QString temp; temp = axis->getName(false, displayNames).replace("&", "&&"); return temp; } void JoyAxisWidget::showContextMenu(const QPoint &point) { QPoint globalPos = this->mapToGlobal(point); JoyAxisContextMenu *contextMenu = new JoyAxisContextMenu(axis, this); contextMenu->buildMenu(); contextMenu->popup(globalPos); } void JoyAxisWidget::tryFlash() { JoyAxisButton *nAxisButton = axis->getNAxisButton(); JoyAxisButton *pAxisButton = axis->getPAxisButton(); if (nAxisButton->getButtonState() || pAxisButton->getButtonState()) { flash(); } } antimicro-2.23/src/joyaxiswidget.h000066400000000000000000000024431300750276700172710ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYAXISWIDGET_H #define JOYAXISWIDGET_H #include #include "flashbuttonwidget.h" #include "joyaxis.h" class JoyAxisWidget : public FlashButtonWidget { Q_OBJECT public: explicit JoyAxisWidget(JoyAxis *axis, bool displayNames, QWidget *parent=0); JoyAxis* getAxis(); void tryFlash(); protected: virtual QString generateLabel(); JoyAxis *axis; signals: public slots: void disableFlashes(); void enableFlashes(); private slots: void showContextMenu(const QPoint &point); }; #endif // JOYAXISWIDGET_H antimicro-2.23/src/joybutton.cpp000066400000000000000000005260471300750276700170020ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include #include "setjoystick.h" #include "inputdevice.h" #include "joybutton.h" #include "vdpad.h" #include "event.h" #include "logger.h" #ifdef Q_OS_WIN #include "eventhandlerfactory.h" #endif const QString JoyButton::xmlName = "button"; // Set default values for many properties. const int JoyButton::ENABLEDTURBODEFAULT = 100; const double JoyButton::DEFAULTMOUSESPEEDMOD = 1.0; double JoyButton::mouseSpeedModifier = JoyButton::DEFAULTMOUSESPEEDMOD; const unsigned int JoyButton::DEFAULTKEYREPEATDELAY = 600; // 600 ms const unsigned int JoyButton::DEFAULTKEYREPEATRATE = 40; // 40 ms. 25 times per second const JoyButton::JoyMouseCurve JoyButton::DEFAULTMOUSECURVE = JoyButton::EnhancedPrecisionCurve; const bool JoyButton::DEFAULTTOGGLE = false; const int JoyButton::DEFAULTTURBOINTERVAL = 0; const bool JoyButton::DEFAULTUSETURBO = false; const int JoyButton::DEFAULTMOUSESPEEDX = 50; const int JoyButton::DEFAULTMOUSESPEEDY = 50; const int JoyButton::DEFAULTSETSELECTION = -1; const JoyButton::SetChangeCondition JoyButton::DEFAULTSETCONDITION = JoyButton::SetChangeDisabled; const JoyButton::JoyMouseMovementMode JoyButton::DEFAULTMOUSEMODE = JoyButton::MouseCursor; const int JoyButton::DEFAULTSPRINGWIDTH = 0; const int JoyButton::DEFAULTSPRINGHEIGHT = 0; const double JoyButton::DEFAULTSENSITIVITY = 1.0; const int JoyButton::DEFAULTWHEELX = 20; const int JoyButton::DEFAULTWHEELY = 20; const bool JoyButton::DEFAULTCYCLERESETACTIVE = false; const int JoyButton::DEFAULTCYCLERESET = 0; const bool JoyButton::DEFAULTRELATIVESPRING = false; const JoyButton::TurboMode JoyButton::DEFAULTTURBOMODE = JoyButton::NormalTurbo; const double JoyButton::DEFAULTEASINGDURATION = 0.5; const double JoyButton::MINIMUMEASINGDURATION = 0.2; const double JoyButton::MAXIMUMEASINGDURATION = 5.0; const unsigned int JoyButton::MINCYCLERESETTIME = 10; const unsigned int JoyButton::MAXCYCLERESETTIME = 60000; const int JoyButton::DEFAULTMOUSEHISTORYSIZE = 10; const double JoyButton::DEFAULTWEIGHTMODIFIER = 0.2; const int JoyButton::MAXIMUMMOUSEHISTORYSIZE = 100; const double JoyButton::MAXIMUMWEIGHTMODIFIER = 1.0; const int JoyButton::MAXIMUMMOUSEREFRESHRATE = 16; int JoyButton::IDLEMOUSEREFRESHRATE = (5 * 20); const int JoyButton::DEFAULTIDLEMOUSEREFRESHRATE = 100; const double JoyButton::DEFAULTEXTRACCELVALUE = 2.0; const double JoyButton::DEFAULTMINACCELTHRESHOLD = 10.0; const double JoyButton::DEFAULTMAXACCELTHRESHOLD = 100.0; const double JoyButton::DEFAULTSTARTACCELMULTIPLIER = 0.0; const double JoyButton::DEFAULTACCELEASINGDURATION = 0.1; const JoyButton::JoyExtraAccelerationCurve JoyButton::DEFAULTEXTRAACCELCURVE = JoyButton::LinearAccelCurve; const int JoyButton::DEFAULTSPRINGRELEASERADIUS = 0; // Keep references to active keys and mouse buttons. QHash JoyButton::activeKeys; QHash JoyButton::activeMouseButtons; JoyButtonSlot* JoyButton::lastActiveKey = 0; // Keep track of active Mouse Speed Mod slots. QList JoyButton::mouseSpeedModList; // Lists used for cursor mode calculations. QList JoyButton::cursorXSpeeds; QList JoyButton::cursorYSpeeds; // Lists used for spring mode calculations. QList JoyButton::springXSpeeds; QList JoyButton::springYSpeeds; // Keeps timestamp of last mouse event. //QElapsedTimer JoyButton::lastMouseTime; // Temporary test object to test old mouse time behavior. QTime JoyButton::testOldMouseTime; // Helper object to have a single mouse event for all JoyButton // instances. JoyButtonMouseHelper JoyButton::mouseHelper; QTimer JoyButton::staticMouseEventTimer; QList JoyButton::pendingMouseButtons; // History buffers used for mouse smoothing routine. QList JoyButton::mouseHistoryX; QList JoyButton::mouseHistoryY; // Carry over remainder of a cursor move for the next mouse event. double JoyButton::cursorRemainderX = 0.0; double JoyButton::cursorRemainderY = 0.0; double JoyButton::weightModifier = 0; int JoyButton::mouseHistorySize = 1; int JoyButton::mouseRefreshRate = 5; int JoyButton::springModeScreen = -1; int JoyButton::gamepadRefreshRate = 10; #ifdef Q_OS_WIN JoyKeyRepeatHelper JoyButton::repeatHelper; #endif static const double PI = acos(-1.0); JoyButton::JoyButton(int index, int originset, SetJoystick *parentSet, QObject *parent) : QObject(parent) { vdpad = 0; slotiter = 0; turboTimer.setParent(this); pauseTimer.setParent(this); holdTimer.setParent(this); pauseWaitTimer.setParent(this); createDeskTimer.setParent(this); releaseDeskTimer.setParent(this); mouseWheelVerticalEventTimer.setParent(this); mouseWheelHorizontalEventTimer.setParent(this); setChangeTimer.setParent(this); keyPressTimer.setParent(this); delayTimer.setParent(this); slotSetChangeTimer.setParent(this); activeZoneTimer.setParent(this); setChangeTimer.setSingleShot(true); slotSetChangeTimer.setSingleShot(true); this->parentSet = parentSet; connect(&pauseWaitTimer, SIGNAL(timeout()), this, SLOT(pauseWaitEvent())); connect(&keyPressTimer, SIGNAL(timeout()), this, SLOT(keyPressEvent())); connect(&holdTimer, SIGNAL(timeout()), this, SLOT(holdEvent())); connect(&delayTimer, SIGNAL(timeout()), this, SLOT(delayEvent())); connect(&createDeskTimer, SIGNAL(timeout()), this, SLOT(waitForDeskEvent())); connect(&releaseDeskTimer, SIGNAL(timeout()), this, SLOT(waitForReleaseDeskEvent())); connect(&turboTimer, SIGNAL(timeout()), this, SLOT(turboEvent())); connect(&mouseWheelVerticalEventTimer, SIGNAL(timeout()), this, SLOT(wheelEventVertical())); connect(&mouseWheelHorizontalEventTimer, SIGNAL(timeout()), this, SLOT(wheelEventHorizontal())); connect(&setChangeTimer, SIGNAL(timeout()), this, SLOT(checkForSetChange())); connect(&slotSetChangeTimer, SIGNAL(timeout()), this, SLOT(slotSetChange())); connect(&activeZoneTimer, SIGNAL(timeout()), this, SLOT(buildActiveZoneSummaryString())); activeZoneTimer.setInterval(0); activeZoneTimer.setSingleShot(true); // Will only matter on the first call establishMouseTimerConnections(); // Make sure to call before calling reset this->resetProperties(); this->index = index; this->originset = originset; quitEvent = true; } JoyButton::~JoyButton() { reset(); } void JoyButton::queuePendingEvent(bool pressed, bool ignoresets) { pendingEvent = false; pendingPress = false; pendingIgnoreSets = false; if (this->vdpad) { vdpadPassEvent(pressed, ignoresets); } else { pendingEvent = true; pendingPress = pressed; pendingIgnoreSets = ignoresets; } } void JoyButton::activatePendingEvent() { if (pendingEvent) { joyEvent(pendingPress, pendingIgnoreSets); pendingEvent = false; pendingPress = false; pendingIgnoreSets = false; } } bool JoyButton::hasPendingEvent() { return pendingEvent; } void JoyButton::clearPendingEvent() { pendingEvent = false; pendingPress = false; pendingIgnoreSets = false; } void JoyButton::vdpadPassEvent(bool pressed, bool ignoresets) { if (this->vdpad && pressed != isButtonPressed) { isButtonPressed = pressed; if (isButtonPressed) { emit clicked(index); } else { emit released(index); } if (!ignoresets) { this->vdpad->queueJoyEvent(ignoresets); } else { this->vdpad->joyEvent(pressed, ignoresets); } } } void JoyButton::joyEvent(bool pressed, bool ignoresets) { if (this->vdpad && !pendingEvent) { vdpadPassEvent(pressed, ignoresets); } else if (ignoreEvents) { if (pressed != isButtonPressed) { isButtonPressed = pressed; if (isButtonPressed) { emit clicked(index); } else { emit released(index); } } } else { if (pressed != isDown) { if (pressed) { emit clicked(index); if (updateInitAccelValues) { oldAccelMulti = updateOldAccelMulti = 0.0; accelTravel = 0.0; } } else { emit released(index); } bool activePress = pressed; setChangeTimer.stop(); if (toggle && pressed) { isDown = true; toggleActiveState = !toggleActiveState; if (!isButtonPressed) { this->ignoresets = ignoresets; isButtonPressed = !isButtonPressed; ignoreSetQueue.enqueue(ignoresets); isButtonPressedQueue.enqueue(isButtonPressed); } else { activePress = false; } } else if (toggle && !pressed && isDown) { isDown = false; if (!toggleActiveState) { this->ignoresets = ignoresets; isButtonPressed = !isButtonPressed; ignoreSetQueue.enqueue(ignoresets); isButtonPressedQueue.enqueue(isButtonPressed); } } else { this->ignoresets = ignoresets; isButtonPressed = isDown = pressed; ignoreSetQueue.enqueue(ignoresets); isButtonPressedQueue.enqueue(isButtonPressed); } if (useTurbo) { if (isButtonPressed && activePress && !turboTimer.isActive()) { if (cycleResetActive && cycleResetHold.elapsed() >= cycleResetInterval && slotiter) { slotiter->toFront(); currentCycle = 0; previousCycle = 0; } buttonHold.restart(); buttonHeldRelease.restart(); keyPressHold.restart(); cycleResetHold.restart(); turboTimer.start(); // Newly activated button. Just entered safe zone. if (updateInitAccelValues) { initializeDistanceValues(); } currentAccelerationDistance = getAccelerationDistance(); Logger::LogDebug(tr("Processing turbo for #%1 - %2") .arg(parentSet->getInputDevice()->getRealJoyNumber()) .arg(getPartialName())); turboEvent(); } else if (!isButtonPressed && !activePress && turboTimer.isActive()) { turboTimer.stop(); Logger::LogDebug(tr("Finishing turbo for button #%1 - %2") .arg(parentSet->getInputDevice()->getRealJoyNumber()) .arg(getPartialName())); if (isKeyPressed) { turboEvent(); } else { lastDistance = getMouseDistanceFromDeadZone(); } activeZoneTimer.start(); } } // Toogle is enabled and a controller button change has occurred. // Switch to a different distance zone if appropriate else if (toggle && !activePress && isButtonPressed) { bool releasedCalled = distanceEvent(); if (releasedCalled) { quitEvent = true; buttonHold.restart(); buttonHeldRelease.restart(); keyPressHold.restart(); //createDeskTimer.start(0); releaseDeskTimer.stop(); if (!keyPressTimer.isActive()) { waitForDeskEvent(); } } } else if (isButtonPressed && activePress) { if (cycleResetActive && cycleResetHold.elapsed() >= cycleResetInterval && slotiter) { slotiter->toFront(); currentCycle = 0; previousCycle = 0; } buttonHold.restart(); buttonHeldRelease.restart(); cycleResetHold.restart(); keyPressHold.restart(); //createDeskTimer.start(0); releaseDeskTimer.stop(); // Newly activated button. Just entered safe zone. if (updateInitAccelValues) { initializeDistanceValues(); } currentAccelerationDistance = getAccelerationDistance(); Logger::LogDebug(tr("Processing press for button #%1 - %2") .arg(parentSet->getInputDevice()->getRealJoyNumber()) .arg(getPartialName())); if (!keyPressTimer.isActive()) { checkForPressedSetChange(); if (!setChangeTimer.isActive()) { waitForDeskEvent(); } } } else if (!isButtonPressed && !activePress) { Logger::LogDebug(tr("Processing release for button #%1 - %2") .arg(parentSet->getInputDevice()->getRealJoyNumber()) .arg(getPartialName())); waitForReleaseDeskEvent(); } if (updateInitAccelValues) { updateLastMouseDistance = false; updateStartingMouseDistance = false; updateOldAccelMulti = 0.0; } } else if (!useTurbo && isButtonPressed) { resetAccelerationDistances(); currentAccelerationDistance = getAccelerationDistance(); if (!setChangeTimer.isActive()) { bool releasedCalled = distanceEvent(); if (releasedCalled) { Logger::LogDebug(tr("Distance change for button #%1 - %2") .arg(parentSet->getInputDevice()->getRealJoyNumber()) .arg(getPartialName())); quitEvent = true; buttonHold.restart(); buttonHeldRelease.restart(); keyPressHold.restart(); //createDeskTimer.start(0); releaseDeskTimer.stop(); if (!keyPressTimer.isActive()) { waitForDeskEvent(); } } } } } updateInitAccelValues = true; } /** * @brief Get 0 indexed number of button * @return 0 indexed button index number */ int JoyButton::getJoyNumber() { return index; } /** * @brief Get a 1 indexed number of button * @return 1 indexed button index number */ int JoyButton::getRealJoyNumber() { return index + 1; } void JoyButton::setJoyNumber(int index) { this->index = index; } void JoyButton::setToggle(bool toggle) { if (toggle != this->toggle) { this->toggle = toggle; emit toggleChanged(toggle); emit propertyUpdated(); } } void JoyButton::setTurboInterval(int interval) { if (interval >= 10 && interval != this->turboInterval) { this->turboInterval = interval; emit turboIntervalChanged(interval); emit propertyUpdated(); } else if (interval < 10 && interval != this->turboInterval) { interval = 0; this->setUseTurbo(false); this->turboInterval = interval; emit turboIntervalChanged(interval); emit propertyUpdated(); } } void JoyButton::reset() { disconnectPropertyUpdatedConnections(); turboTimer.stop(); pauseWaitTimer.stop(); createDeskTimer.stop(); releaseDeskTimer.stop(); holdTimer.stop(); mouseWheelVerticalEventTimer.stop(); mouseWheelHorizontalEventTimer.stop(); setChangeTimer.stop(); keyPressTimer.stop(); delayTimer.stop(); #ifdef Q_OS_WIN repeatHelper.getRepeatTimer()->stop(); #endif slotSetChangeTimer.stop(); if (slotiter) { delete slotiter; slotiter = 0; } releaseActiveSlots(); clearAssignedSlots(); isButtonPressedQueue.clear(); ignoreSetQueue.clear(); mouseEventQueue.clear(); mouseWheelVerticalEventQueue.clear(); mouseWheelHorizontalEventQueue.clear(); resetProperties(); // quitEvent changed here } void JoyButton::reset(int index) { JoyButton::reset(); this->index = index; } bool JoyButton::getToggleState() { return toggle; } int JoyButton::getTurboInterval() { return turboInterval; } void JoyButton::turboEvent() { if (!isKeyPressed) { if (!isButtonPressedQueue.isEmpty()) { ignoreSetQueue.clear(); isButtonPressedQueue.clear(); ignoreSetQueue.enqueue(false); isButtonPressedQueue.enqueue(isButtonPressed); } createDeskEvent(); isKeyPressed = true; if (turboTimer.isActive()) { int tempInterval = turboInterval / 2; if (turboTimer.interval() != tempInterval) { turboTimer.start(tempInterval); } } } else { if (!isButtonPressedQueue.isEmpty()) { ignoreSetQueue.enqueue(false); isButtonPressedQueue.enqueue(!isButtonPressed); } releaseDeskEvent(); isKeyPressed = false; if (turboTimer.isActive()) { int tempInterval = turboInterval / 2; if (turboTimer.interval() != tempInterval) { turboTimer.start(tempInterval); } } } } bool JoyButton::distanceEvent() { bool released = false; if (slotiter) { QReadLocker tempLocker(&assignmentsLock); bool distanceFound = containsDistanceSlots(); if (distanceFound) { double currentDistance = getDistanceFromDeadZone(); double tempDistance = 0.0; JoyButtonSlot *previousDistanceSlot = 0; QListIterator iter(assignments); if (previousCycle) { iter.findNext(previousCycle); } while (iter.hasNext()) { JoyButtonSlot *slot = iter.next(); int tempcode = slot->getSlotCode(); if (slot->getSlotMode() == JoyButtonSlot::JoyDistance) { tempDistance += tempcode / 100.0; if (currentDistance < tempDistance) { iter.toBack(); } else { previousDistanceSlot = slot; } } else if (slot->getSlotMode() == JoyButtonSlot::JoyCycle) { tempDistance = 0.0; iter.toBack(); } } // No applicable distance slot if (!previousDistanceSlot) { if (this->currentDistance) { // Distance slot is currently active. // Release slots, return iterator to // the front, and nullify currentDistance pauseWaitTimer.stop(); holdTimer.stop(); // Release stuff releaseActiveSlots(); currentPause = currentHold = 0; //quitEvent = true; slotiter->toFront(); if (previousCycle) { slotiter->findNext(previousCycle); } this->currentDistance = 0; released = true; } } // An applicable distance slot was found else if (previousDistanceSlot) { if (this->currentDistance != previousDistanceSlot) { // Active distance slot is not the applicable slot. // Deactive slots in previous distance range and // activate new slots. Set currentDistance to // new slot. pauseWaitTimer.stop(); holdTimer.stop(); // Release stuff releaseActiveSlots(); currentPause = currentHold = 0; //quitEvent = true; slotiter->toFront(); if (previousCycle) { slotiter->findNext(previousCycle); } slotiter->findNext(previousDistanceSlot); this->currentDistance = previousDistanceSlot; released = true; } } } } return released; } void JoyButton::createDeskEvent() { quitEvent = false; if (!slotiter) { assignmentsLock.lockForRead(); slotiter = new QListIterator(assignments); assignmentsLock.unlock(); distanceEvent(); } else if (!slotiter->hasPrevious()) { distanceEvent(); } else if (currentCycle) { currentCycle = 0; distanceEvent(); } assignmentsLock.lockForRead(); activateSlots(); assignmentsLock.unlock(); if (currentCycle) { quitEvent = true; } else if (!currentPause && !currentHold && !keyPressTimer.isActive()) { quitEvent = true; } } void JoyButton::activateSlots() { if (slotiter) { QWriteLocker tempLocker(&activeZoneLock); bool exit = false; //bool delaySequence = checkForDelaySequence(); bool delaySequence = false; bool changeRepeatState = false; while (slotiter->hasNext() && !exit) { JoyButtonSlot *slot = slotiter->next(); int tempcode = slot->getSlotCode(); JoyButtonSlot::JoySlotInputAction mode = slot->getSlotMode(); if (mode == JoyButtonSlot::JoyKeyboard) { sendevent(slot, true); activeSlots.append(slot); int oldvalue = activeKeys.value(tempcode, 0) + 1; activeKeys.insert(tempcode, oldvalue); if (!slot->isModifierKey()) { lastActiveKey = slot; changeRepeatState = true; } else { lastActiveKey = 0; changeRepeatState = true; } } else if (mode == JoyButtonSlot::JoyMouseButton) { if (tempcode == JoyButtonSlot::MouseWheelUp || tempcode == JoyButtonSlot::MouseWheelDown) { slot->getMouseInterval()->restart(); wheelVerticalTime.restart(); currentWheelVerticalEvent = slot; activeSlots.append(slot); wheelEventVertical(); currentWheelVerticalEvent = 0; } else if (tempcode == JoyButtonSlot::MouseWheelLeft || tempcode == JoyButtonSlot::MouseWheelRight) { slot->getMouseInterval()->restart(); wheelHorizontalTime.restart(); currentWheelHorizontalEvent = slot; activeSlots.append(slot); wheelEventHorizontal(); currentWheelHorizontalEvent = 0; } else { sendevent(slot, true); activeSlots.append(slot); int oldvalue = activeMouseButtons.value(tempcode, 0) + 1; activeMouseButtons.insert(tempcode, oldvalue); } } else if (mode == JoyButtonSlot::JoyMouseMovement) { slot->getMouseInterval()->restart(); //currentMouseEvent = slot; activeSlots.append(slot); //mouseEventQueue.enqueue(slot); //mouseEvent(); if (pendingMouseButtons.size() == 0) { mouseHelper.setFirstSpringStatus(true); } pendingMouseButtons.append(this); mouseEventQueue.enqueue(slot); //currentMouseEvent = 0; // Temporarily lower timer interval. Helps improve mouse control // precision on the lower end of an axis. if (!staticMouseEventTimer.isActive() || staticMouseEventTimer.interval() != 0) { if (!staticMouseEventTimer.isActive() || staticMouseEventTimer.interval() == IDLEMOUSEREFRESHRATE) { int tempRate = qBound(0, mouseRefreshRate - gamepadRefreshRate, MAXIMUMMOUSEREFRESHRATE); //Logger::LogInfo(QString("STARTING OVER: %1 %2").arg(QTime::currentTime().toString("hh:mm:ss.zzz")).arg(tempRate)); staticMouseEventTimer.start(tempRate); //lastMouseTime.restart(); testOldMouseTime.restart(); accelExtraDurationTime.restart(); } } } else if (mode == JoyButtonSlot::JoyPause) { if (!activeSlots.isEmpty()) { if (slotiter->hasPrevious()) { slotiter->previous(); } delaySequence = true; exit = true; } // Segment can be ignored on a 0 interval pause else if (tempcode > 0) { currentPause = slot; pauseHold.restart(); inpauseHold.restart(); pauseWaitTimer.start(0); exit = true; } } else if (mode == JoyButtonSlot::JoyHold) { currentHold = slot; holdTimer.start(0); exit = true; } else if (mode == JoyButtonSlot::JoyDelay) { currentDelay = slot; buttonDelay.restart(); delayTimer.start(0); exit = true; } else if (mode == JoyButtonSlot::JoyCycle) { currentCycle = slot; exit = true; } else if (mode == JoyButtonSlot::JoyDistance) { exit = true; } else if (mode == JoyButtonSlot::JoyRelease) { if (!currentRelease) { findReleaseEventEnd(); } /*else { currentRelease = 0; exit = true; }*/ else if (currentRelease && activeSlots.isEmpty()) { //currentRelease = 0; exit = true; } else if (currentRelease && !activeSlots.isEmpty()) { if (slotiter->hasPrevious()) { slotiter->previous(); } delaySequence = true; exit = true; } } else if (mode == JoyButtonSlot::JoyMouseSpeedMod) { mouseSpeedModifier = tempcode * 0.01; mouseSpeedModList.append(slot); activeSlots.append(slot); } else if (mode == JoyButtonSlot::JoyKeyPress) { if (activeSlots.isEmpty()) { delaySequence = true; currentKeyPress = slot; } else { if (slotiter->hasPrevious()) { slotiter->previous(); } delaySequence = true; exit = true; } } else if (mode == JoyButtonSlot::JoyLoadProfile) { releaseActiveSlots(); slotiter->toBack(); exit = true; QString location = slot->getTextData(); if (!location.isEmpty()) { parentSet->getInputDevice()->sendLoadProfileRequest(location); } } else if (mode == JoyButtonSlot::JoySetChange) { activeSlots.append(slot); } else if (mode == JoyButtonSlot::JoyTextEntry) { sendevent(slot, true); } else if (mode == JoyButtonSlot::JoyExecute) { sendevent(slot, true); } } #ifdef Q_OS_WIN BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); #endif if (delaySequence && !activeSlots.isEmpty()) { keyPressHold.restart(); keyPressEvent(); } #ifdef Q_OS_WIN else if (handler && handler->getIdentifier() == "sendinput" && changeRepeatState && !useTurbo) { InputDevice *device = getParentSet()->getInputDevice(); if (device->isKeyRepeatEnabled()) { if (lastActiveKey && activeSlots.contains(lastActiveKey)) { repeatHelper.setLastActiveKey(lastActiveKey); repeatHelper.setKeyRepeatRate(device->getKeyRepeatRate()); repeatHelper.getRepeatTimer()->start(device->getKeyRepeatDelay()); } else if (repeatHelper.getRepeatTimer()->isActive()) { repeatHelper.setLastActiveKey(0); repeatHelper.getRepeatTimer()->stop(); } } } #endif //emit activeZoneChanged(); activeZoneTimer.start(); } } void JoyButton::slotSetChange() { if (currentSetChangeSlot) { // Get set change slot and then remove reference. unsigned int setChangeIndex = currentSetChangeSlot->getSlotCode(); currentSetChangeSlot = 0; // Ensure that a change to the current set is not attempted. if (setChangeIndex != originset) { emit released(index); emit setChangeActivated(setChangeIndex); } } } /** * @brief Calculate mouse movement coordinates for mouse movement slots * currently active. */ void JoyButton::mouseEvent() { JoyButtonSlot *buttonslot = 0; bool singleShot = false; if (currentMouseEvent) { buttonslot = currentMouseEvent; singleShot = true; } if (buttonslot || !mouseEventQueue.isEmpty()) { updateLastMouseDistance = true; updateStartingMouseDistance = true; updateOldAccelMulti = 0.0; QQueue tempQueue; if (!buttonslot) { buttonslot = mouseEventQueue.dequeue(); } //unsigned int timeElapsed = lastMouseTime.elapsed(); unsigned int timeElapsed = testOldMouseTime.elapsed(); //unsigned int nanoTimeElapsed = lastMouseTime.nsecsElapsed(); // Presumed initial mouse movement. Use full duration rather than // partial. if (staticMouseEventTimer.interval() < mouseRefreshRate) { //unsigned int nanoRemainder = nanoTimeElapsed - (timeElapsed * 1000000); timeElapsed = getMouseRefreshRate() + (timeElapsed - staticMouseEventTimer.interval()); //nanoTimeElapsed = (timeElapsed * 1000000) + (nanoRemainder); } while (buttonslot) { QElapsedTimer* mouseInterval = buttonslot->getMouseInterval(); int mousedirection = buttonslot->getSlotCode(); JoyButton::JoyMouseMovementMode mousemode = getMouseMode(); int mousespeed = 0; bool isActive = activeSlots.contains(buttonslot); if (isActive) { if (mousemode == JoyButton::MouseCursor) { if (mousedirection == JoyButtonSlot::MouseRight) { mousespeed = mouseSpeedX; } else if (mousedirection == JoyButtonSlot::MouseLeft) { mousespeed = mouseSpeedX; } else if (mousedirection == JoyButtonSlot::MouseDown) { mousespeed = mouseSpeedY; } else if (mousedirection == JoyButtonSlot::MouseUp) { mousespeed = mouseSpeedY; } double difference = getMouseDistanceFromDeadZone(); double mouse1 = 0; double mouse2 = 0; double sumDist = buttonslot->getMouseDistance(); JoyMouseCurve currentCurve = getMouseCurve(); switch (currentCurve) { case LinearCurve: { break; } case QuadraticCurve: { difference = difference * difference; break; } case CubicCurve: { difference = difference * difference * difference; break; } case QuadraticExtremeCurve: { double temp = difference; difference = difference * difference; difference = (temp >= 0.95) ? (difference * 1.5) : difference; break; } case PowerCurve: { double tempsensitive = qMin(qMax(sensitivity, 1.0e-3), 1.0e+3); double temp = qMin(qMax(pow(difference, 1.0 / tempsensitive), 0.0), 1.0); difference = temp; break; } case EnhancedPrecisionCurve: { // Perform different forms of acceleration depending on // the range of the element from its assigned dead zone. // Useful for more precise controls with an axis. double temp = difference; if (temp <= 0.4) { // Low slope value for really slow acceleration difference = difference * 0.37; } else if (temp <= 0.75) { // Perform Linear accleration with an appropriate // offset. difference = difference - 0.252; } else if (temp > 0.75) { // Perform mouse acceleration. Make up the difference // due to the previous two segments. Maxes out at 1.0. difference = (difference * 2.008) - 1.008; } break; } case EasingQuadraticCurve: case EasingCubicCurve: { // Perform different forms of acceleration depending on // the range of the element from its assigned dead zone. // Useful for more precise controls with an axis. double temp = difference; if (temp <= 0.4) { // Low slope value for really slow acceleration difference = difference * 0.38; // Out of high end. Reset easing status. if (buttonslot->isEasingActive()) { buttonslot->setEasingStatus(false); buttonslot->getEasingTime()->restart(); } } else if (temp <= 0.75) { // Perform Linear accleration with an appropriate // offset. difference = difference - 0.248; // Out of high end. Reset easing status. if (buttonslot->isEasingActive()) { buttonslot->setEasingStatus(false); buttonslot->getEasingTime()->restart(); } } else if (temp > 0.75) { // Gradually increase the mouse speed until the specified elapsed duration // time has passed. unsigned int easingElapsed = buttonslot->getEasingTime()->elapsed(); double easingDuration = this->easingDuration; // Time in seconds if (!buttonslot->isEasingActive()) { buttonslot->setEasingStatus(true); buttonslot->getEasingTime()->restart(); easingElapsed = 0; } // Determine the multiplier to use for the current maximum mouse speed // based on how much time has passed. double elapsedDiff = 1.0; if (easingDuration > 0.0 && (easingElapsed * .001) < easingDuration) { elapsedDiff = ((easingElapsed * .001) / easingDuration); if (currentCurve == EasingQuadraticCurve) { // Range 1.0 - 1.5 elapsedDiff = (1.5 - 1.0) * elapsedDiff * elapsedDiff + 1.0; } else { // Range 1.0 - 1.5 elapsedDiff = (1.5 - 1.0) * (elapsedDiff * elapsedDiff * elapsedDiff) + 1.0; } } else { elapsedDiff = 1.5; } // Allow gradient control on the high end of an axis. difference = elapsedDiff * difference; // Range 0.502 - 1.5 difference = difference * 1.33067 - 0.496005; } break; } } double distance = 0; difference = (mouseSpeedModifier == 1.0) ? difference : (difference * mouseSpeedModifier); double mintravel = minMouseDistanceAccelThreshold * 0.01; double minstop = qMax(0.05, mintravel); //double currentTravel = getAccelerationDistance() - lastAccelerationDistance; // Last check ensures that acceleration is only applied for the same direction. if (extraAccelerationEnabled && isPartRealAxis() && fabs(getAccelerationDistance() - lastAccelerationDistance) >= mintravel && (getAccelerationDistance() - lastAccelerationDistance >= 0) == (getAccelerationDistance() >= 0)) { double magfactor = extraAccelerationMultiplier; double minfactor = qMax((DEFAULTSTARTACCELMULTIPLIER * 0.001) + 1.0, magfactor * (startAccelMultiplier * 0.01)); double maxtravel = maxMouseDistanceAccelThreshold * 0.01; double slope = (magfactor - minfactor)/(maxtravel - mintravel); double intercept = minfactor - (slope * mintravel); double intermediateTravel = qMin(maxtravel, fabs(getAccelerationDistance() - lastAccelerationDistance)); if (currentAccelMulti > 1.0 && oldAccelMulti == 0.0) { intermediateTravel = qMin(maxtravel, intermediateTravel + mintravel); } double currentAccelMultiTemp = (slope * intermediateTravel + intercept); if (extraAccelCurve == EaseOutSineCurve) { double getMultiDiff2 = ((currentAccelMultiTemp - minfactor) / (extraAccelerationMultiplier - minfactor)); currentAccelMultiTemp = (extraAccelerationMultiplier - minfactor) * sin(getMultiDiff2 * (PI/2.0)) + minfactor; } else if (extraAccelCurve == EaseOutQuadAccelCurve) { double getMultiDiff2 = ((currentAccelMultiTemp - minfactor) / (extraAccelerationMultiplier - minfactor)); currentAccelMultiTemp = -(extraAccelerationMultiplier - minfactor) * (getMultiDiff2 * (getMultiDiff2 - 2)) + minfactor; } else if (extraAccelCurve == EaseOutCubicAccelCurve) { double getMultiDiff = ((currentAccelMultiTemp - minfactor) / (extraAccelerationMultiplier - minfactor)) - 1; currentAccelMultiTemp = (extraAccelerationMultiplier - minfactor) * ((getMultiDiff) * (getMultiDiff) * (getMultiDiff) + 1) + minfactor; } difference = difference * currentAccelMultiTemp; currentAccelMulti = currentAccelMultiTemp; updateOldAccelMulti = currentAccelMulti; accelTravel = intermediateTravel; accelExtraDurationTime.restart(); } else if (extraAccelerationEnabled && isPartRealAxis() && accelDuration > 0.0 && currentAccelMulti > 0.0 && fabs(getAccelerationDistance() - startingAccelerationDistance) < minstop) { //qDebug() << "Keep Trying: " << fabs(getAccelerationDistance() - lastAccelerationDistance); //qDebug() << "MIN TRAVEL: " << mintravel; updateStartingMouseDistance = true; double magfactor = extraAccelerationMultiplier; double minfactor = qMax((DEFAULTSTARTACCELMULTIPLIER * 0.001) + 1.0, magfactor * (startAccelMultiplier * 0.01)); double maxtravel = maxMouseDistanceAccelThreshold * 0.01; double slope = (magfactor - minfactor)/(maxtravel - mintravel); double intercept = minfactor - (slope * mintravel); unsigned int elapsedElapsed = accelExtraDurationTime.elapsed(); double intermediateTravel = accelTravel; if ((getAccelerationDistance() - startingAccelerationDistance >= 0) != (getAccelerationDistance() >= 0)) { // Travelling towards dead zone. Decrease acceleration and duration. intermediateTravel = qMax(intermediateTravel - fabs(getAccelerationDistance() - startingAccelerationDistance), mintravel); } // Linear case double currentAccelMultiTemp = (slope * intermediateTravel + intercept); double elapsedDuration = accelDuration * ((currentAccelMultiTemp - minfactor) / (extraAccelerationMultiplier - minfactor)); if (extraAccelCurve == EaseOutSineCurve) { double multiDiff = ((currentAccelMultiTemp - minfactor) / (extraAccelerationMultiplier - minfactor)); double temp = sin(multiDiff * (PI/2.0)); elapsedDuration = accelDuration * temp + 0; currentAccelMultiTemp = (extraAccelerationMultiplier - minfactor) * sin(multiDiff * (PI/2.0)) + minfactor; } else if (extraAccelCurve == EaseOutQuadAccelCurve) { double getMultiDiff2 = ((currentAccelMultiTemp - minfactor) / (extraAccelerationMultiplier - minfactor)); double temp = (getMultiDiff2 * (getMultiDiff2 - 2)); elapsedDuration = -accelDuration * temp + 0; currentAccelMultiTemp = -(extraAccelerationMultiplier - minfactor) * temp + minfactor; } else if (extraAccelCurve == EaseOutCubicAccelCurve) { double getMultiDiff = ((currentAccelMultiTemp - minfactor) / (extraAccelerationMultiplier - minfactor)) - 1; double temp = ((getMultiDiff) * (getMultiDiff) * (getMultiDiff) + 1); elapsedDuration = accelDuration * temp + 0; currentAccelMultiTemp = (extraAccelerationMultiplier - minfactor) * temp + minfactor; } double tempAccel = currentAccelMultiTemp; double elapsedDiff = 1.0; if (elapsedDuration > 0.0 && (elapsedElapsed * 0.001) < elapsedDuration) { elapsedDiff = ((elapsedElapsed * 0.001) / elapsedDuration); elapsedDiff = (1.0 - tempAccel) * (elapsedDiff * elapsedDiff * elapsedDiff) + tempAccel; difference = elapsedDiff * difference; // As acceleration is applied, do not update last // distance values when not necessary. updateStartingMouseDistance = false; updateOldAccelMulti = currentAccelMulti; } else { elapsedDiff = 1.0; currentAccelMulti = 0.0; updateOldAccelMulti = 0.0; accelTravel = 0.0; } } else if (extraAccelerationEnabled && isPartRealAxis()) { currentAccelMulti = 0.0; updateStartingMouseDistance = true; oldAccelMulti = updateOldAccelMulti = 0.0; accelTravel = 0.0; } sumDist += difference * (mousespeed * JoyButtonSlot::JOYSPEED * timeElapsed) * 0.001; //sumDist = difference * (nanoTimeElapsed * 0.000000001) * mousespeed * JoyButtonSlot::JOYSPEED; distance = sumDist; if (mousedirection == JoyButtonSlot::MouseRight) { mouse1 = distance; } else if (mousedirection == JoyButtonSlot::MouseLeft) { mouse1 = -distance; } else if (mousedirection == JoyButtonSlot::MouseDown) { mouse2 = distance; } else if (mousedirection == JoyButtonSlot::MouseUp) { mouse2 = -distance; } mouseCursorInfo infoX; infoX.code = mouse1; infoX.slot = buttonslot; cursorXSpeeds.append(infoX); mouseCursorInfo infoY; infoY.code = mouse2; infoY.slot = buttonslot; cursorYSpeeds.append(infoY); sumDist = 0; buttonslot->setDistance(sumDist); } else if (mousemode == JoyButton::MouseSpring) { double mouse1 = -2.0; double mouse2 = -2.0; double difference = getMouseDistanceFromDeadZone(); if (mousedirection == JoyButtonSlot::MouseRight) { mouse1 = difference; if (mouseHelper.getFirstSpringStatus()) { mouse2 = 0.0; mouseHelper.setFirstSpringStatus(false); } } else if (mousedirection == JoyButtonSlot::MouseLeft) { mouse1 = -difference; if (mouseHelper.getFirstSpringStatus()) { mouse2 = 0.0; mouseHelper.setFirstSpringStatus(false); } } else if (mousedirection == JoyButtonSlot::MouseDown) { if (mouseHelper.getFirstSpringStatus()) { mouse1 = 0.0; mouseHelper.setFirstSpringStatus(false); } mouse2 = difference; } else if (mousedirection == JoyButtonSlot::MouseUp) { if (mouseHelper.getFirstSpringStatus()) { mouse1 = 0.0; mouseHelper.setFirstSpringStatus(false); } mouse2 = -difference; } PadderCommon::springModeInfo infoX; infoX.displacementX = mouse1; infoX.springDeadX = 0.0; infoX.width = springWidth; infoX.height = springHeight; infoX.relative = relativeSpring; infoX.screen = springModeScreen; springXSpeeds.append(infoX); PadderCommon::springModeInfo infoY; infoY.displacementY = mouse2; infoY.springDeadY = 0.0; infoY.width = springWidth; infoY.height = springHeight; infoY.relative = relativeSpring; infoY.screen = springModeScreen; springYSpeeds.append(infoY); mouseInterval->restart(); } tempQueue.enqueue(buttonslot); } if (!mouseEventQueue.isEmpty() && !singleShot) { buttonslot = mouseEventQueue.dequeue(); } else { buttonslot = 0; } } if (!tempQueue.isEmpty()) { while (!tempQueue.isEmpty()) { JoyButtonSlot *tempslot = tempQueue.dequeue(); mouseEventQueue.enqueue(tempslot); } } } } void JoyButton::wheelEventVertical() { JoyButtonSlot *buttonslot = 0; if (currentWheelVerticalEvent) { buttonslot = currentWheelVerticalEvent; } if (buttonslot && wheelSpeedY != 0) { bool isActive = activeSlots.contains(buttonslot); if (isActive) { sendevent(buttonslot, true); sendevent(buttonslot, false); mouseWheelVerticalEventQueue.enqueue(buttonslot); mouseWheelVerticalEventTimer.start(1000 / wheelSpeedY); } else { mouseWheelVerticalEventTimer.stop(); } } else if (!mouseWheelVerticalEventQueue.isEmpty() && wheelSpeedY != 0) { QQueue tempQueue; while (!mouseWheelVerticalEventQueue.isEmpty()) { buttonslot = mouseWheelVerticalEventQueue.dequeue(); bool isActive = activeSlots.contains(buttonslot); if (isActive) { sendevent(buttonslot, true); sendevent(buttonslot, false); tempQueue.enqueue(buttonslot); } } if (!tempQueue.isEmpty()) { mouseWheelVerticalEventQueue = tempQueue; mouseWheelVerticalEventTimer.start(1000 / wheelSpeedY); } else { mouseWheelVerticalEventTimer.stop(); } } else { mouseWheelVerticalEventTimer.stop(); } } void JoyButton::wheelEventHorizontal() { JoyButtonSlot *buttonslot = 0; if (currentWheelHorizontalEvent) { buttonslot = currentWheelHorizontalEvent; } if (buttonslot && wheelSpeedX != 0) { bool isActive = activeSlots.contains(buttonslot); if (isActive) { sendevent(buttonslot, true); sendevent(buttonslot, false); mouseWheelHorizontalEventQueue.enqueue(buttonslot); mouseWheelHorizontalEventTimer.start(1000 / wheelSpeedX); } else { mouseWheelHorizontalEventTimer.stop(); } } else if (!mouseWheelHorizontalEventQueue.isEmpty() && wheelSpeedX != 0) { QQueue tempQueue; while (!mouseWheelHorizontalEventQueue.isEmpty()) { buttonslot = mouseWheelHorizontalEventQueue.dequeue(); bool isActive = activeSlots.contains(buttonslot); if (isActive) { sendevent(buttonslot, true); sendevent(buttonslot, false); tempQueue.enqueue(buttonslot); } } if (!tempQueue.isEmpty()) { mouseWheelHorizontalEventQueue = tempQueue; mouseWheelHorizontalEventTimer.start(1000 / wheelSpeedX); } else { mouseWheelHorizontalEventTimer.stop(); } } else { mouseWheelHorizontalEventTimer.stop(); } } void JoyButton::setUseTurbo(bool useTurbo) { bool initialState = this->useTurbo; if (useTurbo != this->useTurbo) { if (useTurbo && this->containsSequence()) { this->useTurbo = false; } else { this->useTurbo = useTurbo; } if (initialState != this->useTurbo) { emit turboChanged(this->useTurbo); emit propertyUpdated(); if (this->useTurbo && this->turboInterval == 0) { this->setTurboInterval(ENABLEDTURBODEFAULT); } } } } bool JoyButton::isUsingTurbo() { return useTurbo; } QString JoyButton::getXmlName() { return this->xmlName; } void JoyButton::readConfig(QXmlStreamReader *xml) { if (xml->isStartElement() && xml->name() == getXmlName()) { xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != getXmlName())) { bool found = readButtonConfig(xml); if (!found) { xml->skipCurrentElement(); } else { buildActiveZoneSummaryString(); } xml->readNextStartElement(); } } } void JoyButton::writeConfig(QXmlStreamWriter *xml) { if (!isDefault()) { xml->writeStartElement(getXmlName()); xml->writeAttribute("index", QString::number(getRealJoyNumber())); if (toggle != DEFAULTTOGGLE) { xml->writeTextElement("toggle", toggle ? "true" : "false"); } if (turboInterval != DEFAULTTURBOINTERVAL) { xml->writeTextElement("turbointerval", QString::number(turboInterval)); } if (currentTurboMode != DEFAULTTURBOMODE) { if (currentTurboMode == GradientTurbo) { xml->writeTextElement("turbomode", "gradient"); } else if (currentTurboMode == PulseTurbo) { xml->writeTextElement("turbomode", "pulse"); } } if (useTurbo != DEFAULTUSETURBO) { xml->writeTextElement("useturbo", useTurbo ? "true" : "false"); } if (mouseSpeedX != DEFAULTMOUSESPEEDX) { xml->writeTextElement("mousespeedx", QString::number(mouseSpeedX)); } if (mouseSpeedY != DEFAULTMOUSESPEEDY) { xml->writeTextElement("mousespeedy", QString::number(mouseSpeedY)); } if (mouseMode != DEFAULTMOUSEMODE) { if (mouseMode == MouseCursor) { xml->writeTextElement("mousemode", "cursor"); } else if (mouseMode == MouseSpring) { xml->writeTextElement("mousemode", "spring"); xml->writeTextElement("mousespringwidth", QString::number(springWidth)); xml->writeTextElement("mousespringheight", QString::number(springHeight)); } } if (mouseCurve != DEFAULTMOUSECURVE) { if (mouseCurve == LinearCurve) { xml->writeTextElement("mouseacceleration", "linear"); } else if (mouseCurve == QuadraticCurve) { xml->writeTextElement("mouseacceleration", "quadratic"); } else if (mouseCurve == CubicCurve) { xml->writeTextElement("mouseacceleration", "cubic"); } else if (mouseCurve == QuadraticExtremeCurve) { xml->writeTextElement("mouseacceleration", "quadratic-extreme"); } else if (mouseCurve == PowerCurve) { xml->writeTextElement("mouseacceleration", "power"); xml->writeTextElement("mousesensitivity", QString::number(sensitivity)); } else if (mouseCurve == EnhancedPrecisionCurve) { xml->writeTextElement("mouseacceleration", "precision"); } else if (mouseCurve == EasingQuadraticCurve) { xml->writeTextElement("mouseacceleration", "easing-quadratic"); } else if (mouseCurve == EasingCubicCurve) { xml->writeTextElement("mouseacceleration", "easing-cubic"); } } if (wheelSpeedX != DEFAULTWHEELX) { xml->writeTextElement("wheelspeedx", QString::number(wheelSpeedX)); } if (wheelSpeedY != DEFAULTWHEELY) { xml->writeTextElement("wheelspeedy", QString::number(wheelSpeedY)); } if (!isModifierButton()) { if (setSelectionCondition != SetChangeDisabled) { xml->writeTextElement("setselect", QString::number(setSelection+1)); QString temptext; if (setSelectionCondition == SetChangeOneWay) { temptext = "one-way"; } else if (setSelectionCondition == SetChangeTwoWay) { temptext = "two-way"; } else if (setSelectionCondition == SetChangeWhileHeld) { temptext = "while-held"; } xml->writeTextElement("setselectcondition", temptext); } } if (!actionName.isEmpty()) { xml->writeTextElement("actionname", actionName); } if (cycleResetActive) { xml->writeTextElement("cycleresetactive", "true"); } if (cycleResetInterval >= MINCYCLERESETTIME) { xml->writeTextElement("cycleresetinterval", QString::number(cycleResetInterval)); } if (relativeSpring == true) { xml->writeTextElement("relativespring", "true"); } if (easingDuration != DEFAULTEASINGDURATION) { xml->writeTextElement("easingduration", QString::number(easingDuration)); } if (extraAccelerationEnabled) { xml->writeTextElement("extraacceleration", "true"); } if (extraAccelerationMultiplier != DEFAULTEXTRACCELVALUE) { xml->writeTextElement("accelerationmultiplier", QString::number(extraAccelerationMultiplier)); } if (startAccelMultiplier != DEFAULTSTARTACCELMULTIPLIER) { xml->writeTextElement("startaccelmultiplier", QString::number(startAccelMultiplier)); } if (minMouseDistanceAccelThreshold != DEFAULTMINACCELTHRESHOLD) { xml->writeTextElement("minaccelthreshold", QString::number(minMouseDistanceAccelThreshold)); } if (maxMouseDistanceAccelThreshold != DEFAULTMAXACCELTHRESHOLD) { xml->writeTextElement("maxaccelthreshold", QString::number(maxMouseDistanceAccelThreshold)); } if (accelDuration != DEFAULTACCELEASINGDURATION) { xml->writeTextElement("accelextraduration", QString::number(accelDuration)); } if (springDeadCircleMultiplier != DEFAULTSPRINGRELEASERADIUS) { xml->writeTextElement("springreleaseradius", QString::number(springDeadCircleMultiplier)); } if (extraAccelCurve != DEFAULTEXTRAACCELCURVE) { QString temp; if (extraAccelCurve == LinearAccelCurve) { temp = "linear"; } else if (extraAccelCurve == EaseOutSineCurve) { temp = "easeoutsine"; } else if (extraAccelCurve == EaseOutQuadAccelCurve) { temp = "easeoutquad"; } else if (extraAccelCurve == EaseOutCubicAccelCurve) { temp = "easeoutcubic"; } if (!temp.isEmpty()) { xml->writeTextElement("extraaccelerationcurve", temp); } } // Write information about assigned slots. if (!assignments.isEmpty()) { xml->writeStartElement("slots"); QListIterator iter(assignments); while (iter.hasNext()) { JoyButtonSlot *buttonslot = iter.next(); buttonslot->writeConfig(xml); } xml->writeEndElement(); } xml->writeEndElement(); } } bool JoyButton::readButtonConfig(QXmlStreamReader *xml) { bool found = false; if (xml->name() == "toggle" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); if (temptext == "true") { this->setToggle(true); } } else if (xml->name() == "turbointerval" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); int tempchoice = temptext.toInt(); this->setTurboInterval(tempchoice); } else if (xml->name() == "turbomode" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); if (temptext == "normal") { this->setTurboMode(NormalTurbo); } else if (temptext == "gradient") { this->setTurboMode(GradientTurbo); } else if (temptext == "pulse") { this->setTurboMode(PulseTurbo); } } else if (xml->name() == "useturbo" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); if (temptext == "true") { this->setUseTurbo(true); } } else if (xml->name() == "mousespeedx" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); int tempchoice = temptext.toInt(); this->setMouseSpeedX(tempchoice); } else if (xml->name() == "mousespeedy" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); int tempchoice = temptext.toInt(); this->setMouseSpeedY(tempchoice); } else if (xml->name() == "cycleresetactive" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); if (temptext == "true") { this->setCycleResetStatus(true); } } else if (xml->name() == "cycleresetinterval" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); unsigned int tempchoice = temptext.toInt(); if (tempchoice >= MINCYCLERESETTIME) { this->setCycleResetTime(tempchoice); } } else if (xml->name() == "slots" && xml->isStartElement()) { found = true; xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "slots")) { if (xml->name() == "slot" && xml->isStartElement()) { JoyButtonSlot *buttonslot = new JoyButtonSlot(this); buttonslot->readConfig(xml); bool validSlot = buttonslot->isValidSlot(); if (validSlot) { bool inserted = insertAssignedSlot(buttonslot, false); if (!inserted) { delete buttonslot; buttonslot = 0; } } else { delete buttonslot; buttonslot = 0; } } else { xml->skipCurrentElement(); } xml->readNextStartElement(); } } else if (xml->name() == "setselect" && xml->isStartElement()) { if (!isModifierButton()) { found = true; QString temptext = xml->readElementText(); int tempchoice = temptext.toInt(); if (tempchoice >= 0 && tempchoice <= InputDevice::NUMBER_JOYSETS) { this->setChangeSetSelection(tempchoice - 1, false); } } } else if (xml->name() == "setselectcondition" && xml->isStartElement()) { if (!isModifierButton()) { found = true; QString temptext = xml->readElementText(); SetChangeCondition tempcondition = SetChangeDisabled; if (temptext == "one-way") { tempcondition = SetChangeOneWay; } else if (temptext == "two-way") { tempcondition = SetChangeTwoWay; } else if (temptext == "while-held") { tempcondition = SetChangeWhileHeld; } if (tempcondition != SetChangeDisabled) { this->setChangeSetCondition(tempcondition, false, false); } } } else if (xml->name() == "mousemode" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); if (temptext == "cursor") { setMouseMode(MouseCursor); } else if (temptext == "spring") { setMouseMode(MouseSpring); } } else if (xml->name() == "mouseacceleration" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); if (temptext == "linear") { setMouseCurve(LinearCurve); } else if (temptext == "quadratic") { setMouseCurve(QuadraticCurve); } else if (temptext == "cubic") { setMouseCurve(CubicCurve); } else if (temptext == "quadratic-extreme") { setMouseCurve(QuadraticExtremeCurve); } else if (temptext == "power") { setMouseCurve(PowerCurve); } else if (temptext == "precision") { setMouseCurve(EnhancedPrecisionCurve); } else if (temptext == "easing-quadratic") { setMouseCurve(EasingQuadraticCurve); } else if (temptext == "easing-cubic") { setMouseCurve(EasingCubicCurve); } } else if (xml->name() == "mousespringwidth" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); int tempchoice = temptext.toInt(); setSpringWidth(tempchoice); } else if (xml->name() == "mousespringheight" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); int tempchoice = temptext.toInt(); setSpringHeight(tempchoice); } else if (xml->name() == "mousesensitivity" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); double tempchoice = temptext.toDouble(); setSensitivity(tempchoice); } else if (xml->name() == "actionname" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); if (!temptext.isEmpty()) { setActionName(temptext); } } else if (xml->name() == "wheelspeedx" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); int tempchoice = temptext.toInt(); setWheelSpeedX(tempchoice); } else if (xml->name() == "wheelspeedy" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); int tempchoice = temptext.toInt(); setWheelSpeedY(tempchoice); } else if (xml->name() == "relativespring" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); if (temptext == "true") { this->setSpringRelativeStatus(true); } } else if (xml->name() == "easingduration" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); double tempchoice = temptext.toDouble(); setEasingDuration(tempchoice); } else if (xml->name() == "extraacceleration" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); if (temptext == "true") { setExtraAccelerationStatus(true); } } else if (xml->name() == "accelerationmultiplier" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); double tempchoice = temptext.toDouble(); setExtraAccelerationMultiplier(tempchoice); } else if (xml->name() == "startaccelmultiplier" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); double tempchoice = temptext.toDouble(); setStartAccelMultiplier(tempchoice); } else if (xml->name() == "minaccelthreshold" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); double tempchoice = temptext.toDouble(); setMinAccelThreshold(tempchoice); } else if (xml->name() == "maxaccelthreshold" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); double tempchoice = temptext.toDouble(); setMaxAccelThreshold(tempchoice); } else if (xml->name() == "accelextraduration" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); double tempchoice = temptext.toDouble(); setAccelExtraDuration(tempchoice); } else if (xml->name() == "extraaccelerationcurve" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); JoyExtraAccelerationCurve tempcurve = DEFAULTEXTRAACCELCURVE; if (temptext == "linear") { tempcurve = LinearAccelCurve; } else if (temptext == "easeoutsine") { tempcurve = EaseOutSineCurve; } else if (temptext == "easeoutquad") { tempcurve = EaseOutQuadAccelCurve; } else if (temptext == "easeoutcubic") { tempcurve = EaseOutCubicAccelCurve; } setExtraAccelerationCurve(tempcurve); } else if (xml->name() == "springreleaseradius" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); int tempchoice = temptext.toInt(); if (!relativeSpring) { setSpringDeadCircleMultiplier(tempchoice); } } return found; } QString JoyButton::getName(bool forceFullFormat, bool displayNames) { QString newlabel = getPartialName(forceFullFormat, displayNames); newlabel.append(": "); if (!actionName.isEmpty() && displayNames) { newlabel.append(actionName); } else { newlabel.append(getCalculatedActiveZoneSummary()); } return newlabel; } QString JoyButton::getPartialName(bool forceFullFormat, bool displayNames) { QString temp; if (!buttonName.isEmpty() && displayNames) { if (forceFullFormat) { temp.append(tr("Button")).append(" "); } temp.append(buttonName); } else if (!defaultButtonName.isEmpty()) { if (forceFullFormat) { temp.append(tr("Button")).append(" "); } temp.append(defaultButtonName); } else { temp.append(tr("Button")).append(" ").append(QString::number(getRealJoyNumber())); } return temp; } /** * @brief Generate a string representing a summary of the slots currently * assigned to a button * @return String of currently assigned slots */ QString JoyButton::getSlotsSummary() { QString newlabel; int slotCount = assignments.size(); if (slotCount > 0) { QListIterator iter(assignments); QStringList stringlist; int i = 0; while (iter.hasNext()) { JoyButtonSlot *slot = iter.next(); stringlist.append(slot->getSlotString()); i++; if (i > 4 && iter.hasNext()) { stringlist.append(" ..."); iter.toBack(); } } newlabel = stringlist.join(", "); } else { newlabel = newlabel.append(tr("[NO KEY]")); } return newlabel; } /** * @brief Generate a string that represents slots that will be activated or * slots that are currently active if a button is pressed * @return String of currently applicable slots for a button */ QString JoyButton::getActiveZoneSummary() { QList tempList = getActiveZoneList(); QString temp = buildActiveZoneSummary(tempList); return temp; } QString JoyButton::getCalculatedActiveZoneSummary() { activeZoneStringLock.lockForRead(); QString temp = this->activeZoneString; activeZoneStringLock.unlock(); return temp; } /** * @brief Generate active zone string and notify other objects. */ void JoyButton::buildActiveZoneSummaryString() { activeZoneStringLock.lockForWrite(); this->activeZoneString = getActiveZoneSummary(); activeZoneStringLock.unlock(); emit activeZoneChanged(); } /** * @brief Generate active zone string but do not notify any other object. */ void JoyButton::localBuildActiveZoneSummaryString() { activeZoneStringLock.lockForWrite(); this->activeZoneString = getActiveZoneSummary(); activeZoneStringLock.unlock(); } QString JoyButton::buildActiveZoneSummary(QList &tempList) { QString newlabel; QListIterator iter(tempList); QStringList stringlist; int i = 0; bool slotsActive = !activeSlots.isEmpty(); if (setSelectionCondition == SetChangeOneWay) { newlabel.append(tr("[Set %1 1W]").arg(setSelection+1)); if (iter.hasNext()) { newlabel.append(" "); } } else if (setSelectionCondition == SetChangeTwoWay) { newlabel = newlabel.append(tr("[Set %1 2W]").arg(setSelection+1)); if (iter.hasNext()) { newlabel.append(" "); } } if (setSelectionCondition == SetChangeWhileHeld) { newlabel.append(tr("[Set %1 WH]").arg(setSelection+1)); } else if (iter.hasNext()) { bool behindHold = false; while (iter.hasNext()) { JoyButtonSlot *slot = iter.next(); JoyButtonSlot::JoySlotInputAction mode = slot->getSlotMode(); switch (mode) { case JoyButtonSlot::JoyKeyboard: case JoyButtonSlot::JoyMouseButton: case JoyButtonSlot::JoyMouseMovement: { QString temp = slot->getSlotString(); if (behindHold) { temp.prepend("[H] "); behindHold = false; } stringlist.append(temp); i++; break; } case JoyButtonSlot::JoyKeyPress: { // Skip slot if a press time slot was inserted. break; } case JoyButtonSlot::JoyHold: { if (!slotsActive && i == 0) { // If button is not active and first slot is a hold, // keep processing slots but take note of the hold. behindHold = true; } else { // Move iter to back so loop will end. iter.toBack(); } break; } case JoyButtonSlot::JoyLoadProfile: case JoyButtonSlot::JoySetChange: case JoyButtonSlot::JoyTextEntry: case JoyButtonSlot::JoyExecute: { QString temp = slot->getSlotString(); if (behindHold) { temp.prepend("[H] "); behindHold = false; } stringlist.append(temp); i++; break; } /*case JoyButtonSlot::JoyRelease: { if (!currentRelease) { findReleaseEventIterEnd(iter); } break; } */ /*case JoyButtonSlot::JoyDistance: { iter->toBack(); break; } */ case JoyButtonSlot::JoyDelay: { iter.toBack(); break; } case JoyButtonSlot::JoyCycle: { iter.toBack(); break; } } if (i > 4 && iter.hasNext()) { stringlist.append(" ..."); iter.toBack(); } } newlabel.append(stringlist.join(", ")); } else if (setSelectionCondition == SetChangeDisabled) { newlabel.append(tr("[NO KEY]")); } return newlabel; } QList JoyButton::getActiveZoneList() { QListIterator activeSlotsIter(activeSlots); QListIterator assignmentsIter(assignments); QListIterator *iter = 0; QReadWriteLock *tempLock = 0; activeZoneLock.lockForRead(); int numActiveSlots = activeSlots.size(); activeZoneLock.unlock(); if (numActiveSlots > 0) { tempLock = &activeZoneLock; iter = &activeSlotsIter; } else { tempLock = &assignmentsLock; iter = &assignmentsIter; } QReadLocker tempLocker(tempLock); Q_UNUSED(tempLocker); if (tempLock == &assignmentsLock) { if (previousCycle) { iter->findNext(previousCycle); } } QList tempSlotList; if (setSelectionCondition != SetChangeWhileHeld && iter->hasNext()) { while (iter->hasNext()) { JoyButtonSlot *slot = iter->next(); JoyButtonSlot::JoySlotInputAction mode = slot->getSlotMode(); switch (mode) { case JoyButtonSlot::JoyKeyboard: case JoyButtonSlot::JoyMouseButton: case JoyButtonSlot::JoyMouseMovement: { tempSlotList.append(slot); break; } case JoyButtonSlot::JoyKeyPress: case JoyButtonSlot::JoyHold: case JoyButtonSlot::JoyLoadProfile: case JoyButtonSlot::JoySetChange: case JoyButtonSlot::JoyTextEntry: case JoyButtonSlot::JoyExecute: { tempSlotList.append(slot); break; } case JoyButtonSlot::JoyRelease: { if (!currentRelease) { findReleaseEventIterEnd(iter); } break; } case JoyButtonSlot::JoyDistance: { iter->toBack(); break; } case JoyButtonSlot::JoyCycle: { iter->toBack(); break; } } } } return tempSlotList; } /** * @brief Generate a string representing all the currently assigned slots for * a button * @return String representing all assigned slots for a button */ QString JoyButton::getSlotsString() { QString label; if (assignments.size() > 0) { QListIterator iter(assignments); QStringList stringlist; while (iter.hasNext()) { JoyButtonSlot *slot = iter.next(); stringlist.append(slot->getSlotString()); } label = stringlist.join(", "); } else { label = label.append(tr("[NO KEY]")); } return label; } void JoyButton::setCustomName(QString name) { customName = name; } QString JoyButton::getCustomName() { return customName; } /** * @brief Create new JoyButtonSlot with data provided and append the new slot * an existing to the assignment list. * @param Native virtual code being used. * @param Mode of the slot. * @return Whether the new slot was successfully added to the assignment list. */ bool JoyButton::setAssignedSlot(int code, JoyButtonSlot::JoySlotInputAction mode) { bool slotInserted = false; JoyButtonSlot *slot = new JoyButtonSlot(code, mode, this); if (slot->getSlotMode() == JoyButtonSlot::JoyDistance) { if (slot->getSlotCode() >= 1 && slot->getSlotCode() <= 100) { double tempDistance = getTotalSlotDistance(slot); if (tempDistance <= 1.0) { assignmentsLock.lockForWrite(); assignments.append(slot); assignmentsLock.unlock(); buildActiveZoneSummaryString(); slotInserted = true; } } } else if (slot->getSlotCode() >= 0) { assignmentsLock.lockForWrite(); assignments.append(slot); assignmentsLock.unlock(); buildActiveZoneSummaryString(); slotInserted = true; } if (slotInserted) { checkTurboCondition(slot); emit slotsChanged(); } else { if (slot) { delete slot; slot = 0; } } return slotInserted; } /** * @brief Create new JoyButtonSlot with data provided and append the new slot * an existing to the assignment list. * @param Native virtual code being used. * @param Qt key alias used for abstracting native virtual code. * @param Mode of the slot. * @return Whether the new slot was successfully added to the assignment list. */ bool JoyButton::setAssignedSlot(int code, unsigned int alias, JoyButtonSlot::JoySlotInputAction mode) { bool slotInserted = false; JoyButtonSlot *slot = new JoyButtonSlot(code, alias, mode, this); if (slot->getSlotMode() == JoyButtonSlot::JoyDistance) { if (slot->getSlotCode() >= 1 && slot->getSlotCode() <= 100) { double tempDistance = getTotalSlotDistance(slot); if (tempDistance <= 1.0) { assignmentsLock.lockForWrite(); assignments.append(slot); assignmentsLock.unlock(); buildActiveZoneSummaryString(); slotInserted = true; } } } else if (slot->getSlotCode() >= 0) { assignmentsLock.lockForWrite(); assignments.append(slot); assignmentsLock.unlock(); buildActiveZoneSummaryString(); slotInserted = true; } if (slotInserted) { checkTurboCondition(slot); emit slotsChanged(); } else { if (slot) { delete slot; slot = 0; } } return slotInserted; } /** * @brief Create new JoyButtonSlot with data provided and replace an existing * slot in the assignment list if one exists. * @param Native virtual code being used. * @param Qt key alias used for abstracting native virtual code. * @param Index number in the list. * @param Mode of the slot. * @return Whether the new slot was successfully added to the assignment list. */ bool JoyButton::setAssignedSlot(int code, unsigned int alias, int index, JoyButtonSlot::JoySlotInputAction mode) { bool permitSlot = true; JoyButtonSlot *slot = new JoyButtonSlot(code, alias, mode, this); if (slot->getSlotMode() == JoyButtonSlot::JoyDistance) { if (slot->getSlotCode() >= 1 && slot->getSlotCode() <= 100) { double tempDistance = getTotalSlotDistance(slot); if (tempDistance > 1.0) { permitSlot = false; } } else { permitSlot = false; } } else if (slot->getSlotCode() < 0) { permitSlot = false; } if (permitSlot) { assignmentsLock.lockForWrite(); if (index >= 0 && index < assignments.count()) { // Insert slot and move existing slots. JoyButtonSlot *temp = assignments.at(index); if (temp) { delete temp; temp = 0; } assignments.replace(index, slot); } else if (index >= assignments.count()) { // Append code into a new slot assignments.append(slot); } checkTurboCondition(slot); assignmentsLock.unlock(); buildActiveZoneSummaryString(); emit slotsChanged(); } else { if (slot) { delete slot; slot = 0; } } return permitSlot; } /** * @brief Create new JoyButtonSlot with data provided and insert it into * assignments list if it is valid. * @param Native virtual code being used. * @param Qt key alias used for abstracting native virtual code. * @param Index number in the list. * @param Mode of the slot. * @return Whether the new slot was successfully added to the assignment list. */ bool JoyButton::insertAssignedSlot(int code, unsigned int alias, int index, JoyButtonSlot::JoySlotInputAction mode) { bool permitSlot = true; JoyButtonSlot *slot = new JoyButtonSlot(code, alias, mode, this); if (slot->getSlotMode() == JoyButtonSlot::JoyDistance) { if (slot->getSlotCode() >= 1 && slot->getSlotCode() <= 100) { double tempDistance = getTotalSlotDistance(slot); if (tempDistance > 1.0) { permitSlot = false; } } else { permitSlot = false; } } else if (slot->getSlotCode() < 0) { permitSlot = false; } if (permitSlot) { assignmentsLock.lockForWrite(); if (index >= 0 && index < assignments.count()) { // Insert new slot into list. Move old slots if needed. assignments.insert(index, slot); } else if (index >= assignments.count()) { // Append new slot into list. assignments.append(slot); } checkTurboCondition(slot); assignmentsLock.unlock(); buildActiveZoneSummaryString(); emit slotsChanged(); } else { if (slot) { delete slot; slot = 0; } } return permitSlot; } bool JoyButton::insertAssignedSlot(JoyButtonSlot *newSlot, bool updateActiveString) { bool permitSlot = false; if (newSlot->getSlotMode() == JoyButtonSlot::JoyDistance) { if (newSlot->getSlotCode() >= 1 && newSlot->getSlotCode() <= 100) { double tempDistance = getTotalSlotDistance(newSlot); if (tempDistance <= 1.0) { permitSlot = true; } } } else if (newSlot->getSlotMode() == JoyButtonSlot::JoyLoadProfile) { permitSlot = true; } else if (newSlot->getSlotMode() == JoyButtonSlot::JoyTextEntry && !newSlot->getTextData().isEmpty()) { permitSlot = true; } else if (newSlot->getSlotMode() == JoyButtonSlot::JoyExecute && !newSlot->getTextData().isEmpty()) { permitSlot = true; } else if (newSlot->getSlotCode() >= 0) { permitSlot = true; } if (permitSlot) { assignmentsLock.lockForWrite(); checkTurboCondition(newSlot); assignments.append(newSlot); assignmentsLock.unlock(); if (updateActiveString) { buildActiveZoneSummaryString(); } emit slotsChanged(); } return permitSlot; } bool JoyButton::setAssignedSlot(JoyButtonSlot *otherSlot, int index) { bool permitSlot = false; JoyButtonSlot *newslot = new JoyButtonSlot(otherSlot, this); if (newslot->getSlotMode() == JoyButtonSlot::JoyDistance) { if (newslot->getSlotCode() >= 1 && newslot->getSlotCode() <= 100) { double tempDistance = getTotalSlotDistance(newslot); if (tempDistance <= 1.0) { permitSlot = true; } } } else if (newslot->getSlotMode() == JoyButtonSlot::JoyLoadProfile) { permitSlot = true; } else if (newslot->getSlotMode() == JoyButtonSlot::JoyTextEntry && !newslot->getTextData().isEmpty()) { permitSlot = true; } else if (newslot->getSlotMode() == JoyButtonSlot::JoyExecute && !newslot->getTextData().isEmpty()) { permitSlot = true; } else if (newslot->getSlotCode() >= 0) { permitSlot = true; } if (permitSlot) { assignmentsLock.lockForWrite(); checkTurboCondition(newslot); if (index >= 0 && index < assignments.count()) { // Slot already exists. Override code and place into desired slot JoyButtonSlot *temp = assignments.at(index); if (temp) { delete temp; temp = 0; //assignments.insert(index, temp); } assignments.replace(index, newslot); } else if (index >= assignments.count()) { // Append code into a new slot assignments.append(newslot); } assignmentsLock.unlock(); buildActiveZoneSummaryString(); emit slotsChanged(); } else { delete newslot; newslot = 0; } return permitSlot; } QList* JoyButton::getAssignedSlots() { QList *newassign = &assignments; return newassign; } void JoyButton::setMouseSpeedX(int speed) { if (speed >= 1 && speed <= 300) { mouseSpeedX = speed; emit propertyUpdated(); } } int JoyButton::getMouseSpeedX() { return mouseSpeedX; } void JoyButton::setMouseSpeedY(int speed) { if (speed >= 1 && speed <= 300) { mouseSpeedY = speed; emit propertyUpdated(); } } int JoyButton::getMouseSpeedY() { return mouseSpeedY; } void JoyButton::setChangeSetSelection(int index, bool updateActiveString) { if (index >= -1 && index <= 7) { setSelection = index; if (updateActiveString) { buildActiveZoneSummaryString(); } emit propertyUpdated(); } } int JoyButton::getSetSelection() { return setSelection; } void JoyButton::setChangeSetCondition(SetChangeCondition condition, bool passive, bool updateActiveString) { SetChangeCondition oldCondition = setSelectionCondition; if (condition != setSelectionCondition && !passive) { if (condition == SetChangeWhileHeld || condition == SetChangeTwoWay) { // Set new condition emit setAssignmentChanged(index, setSelection, condition); } else if (setSelectionCondition == SetChangeWhileHeld || setSelectionCondition == SetChangeTwoWay) { // Remove old condition emit setAssignmentChanged(index, setSelection, SetChangeDisabled); } setSelectionCondition = condition; } else if (passive) { setSelectionCondition = condition; } if (setSelectionCondition == SetChangeDisabled) { setChangeSetSelection(-1); } if (setSelectionCondition != oldCondition) { if (updateActiveString) { buildActiveZoneSummaryString(); } emit propertyUpdated(); } } JoyButton::SetChangeCondition JoyButton::getChangeSetCondition() { return setSelectionCondition; } bool JoyButton::getButtonState() { return isButtonPressed; } int JoyButton::getOriginSet() { return originset; } void JoyButton::pauseWaitEvent() { if (currentPause) { if (!isButtonPressedQueue.isEmpty() && createDeskTimer.isActive()) { if (slotiter) { slotiter->toBack(); bool lastIgnoreSetState = ignoreSetQueue.last(); bool lastIsButtonPressed = isButtonPressedQueue.last(); ignoreSetQueue.clear(); isButtonPressedQueue.clear(); ignoreSetQueue.enqueue(lastIgnoreSetState); isButtonPressedQueue.enqueue(lastIsButtonPressed); currentPause = 0; //JoyButtonSlot *oldCurrentRelease = currentRelease; currentRelease = 0; //createDeskTimer.stop(); releaseDeskTimer.stop(); pauseWaitTimer.stop(); slotiter->toFront(); if (previousCycle) { slotiter->findNext(previousCycle); } quitEvent = true; keyPressHold.restart(); //waitForDeskEvent(); // Assuming that if this is the case, a pause from // a release slot was previously active. setChangeTimer // should not be active at this point. //if (oldCurrentRelease && setChangeTimer.isActive()) //{ // setChangeTimer.stop(); //} } } } if (currentPause) { // If release timer is active, temporarily // disable it if (releaseDeskTimer.isActive()) { releaseDeskTimer.stop(); } if (inpauseHold.elapsed() < currentPause->getSlotCode()) { int proposedInterval = currentPause->getSlotCode() - inpauseHold.elapsed(); proposedInterval = proposedInterval > 0 ? proposedInterval : 0; int newTimerInterval = qMin(10, proposedInterval); pauseWaitTimer.start(newTimerInterval); } else { pauseWaitTimer.stop(); createDeskTimer.stop(); currentPause = 0; createDeskEvent(); // If release timer was disabled but if the button // is not pressed, restart the release timer. if (!releaseDeskTimer.isActive() && (isButtonPressedQueue.isEmpty() || !isButtonPressedQueue.last())) { waitForReleaseDeskEvent(); } } } else { pauseWaitTimer.stop(); } } void JoyButton::checkForSetChange() { if (!ignoreSetQueue.isEmpty() && !isButtonPressedQueue.isEmpty()) { bool tempFinalState = isButtonPressedQueue.last(); bool tempFinalIgnoreSetsState = ignoreSetQueue.last(); if (!tempFinalIgnoreSetsState) { if (!tempFinalState && setSelectionCondition == SetChangeOneWay && setSelection > -1) { // If either timer is currently active, // stop the timer if (createDeskTimer.isActive()) { createDeskTimer.stop(); } if (releaseDeskTimer.isActive()) { releaseDeskTimer.stop(); } isButtonPressedQueue.clear(); ignoreSetQueue.clear(); emit released(index); emit setChangeActivated(setSelection); } else if (!tempFinalState && setSelectionCondition == SetChangeTwoWay && setSelection > -1) { // If either timer is currently active, // stop the timer if (createDeskTimer.isActive()) { createDeskTimer.stop(); } if (releaseDeskTimer.isActive()) { releaseDeskTimer.stop(); } isButtonPressedQueue.clear(); ignoreSetQueue.clear(); emit released(index); emit setChangeActivated(setSelection); } else if (setSelectionCondition == SetChangeWhileHeld && setSelection > -1) { if (tempFinalState) { whileHeldStatus = true; } else if (!tempFinalState) { whileHeldStatus = false; } // If either timer is currently active, // stop the timer if (createDeskTimer.isActive()) { createDeskTimer.stop(); } if (releaseDeskTimer.isActive()) { releaseDeskTimer.stop(); } isButtonPressedQueue.clear(); ignoreSetQueue.clear(); emit released(index); emit setChangeActivated(setSelection); } } // Clear queue except for a press if it is last in if (!isButtonPressedQueue.isEmpty()) { isButtonPressedQueue.clear(); if (tempFinalState) { isButtonPressedQueue.enqueue(tempFinalState); } } // Clear queue except for a press if it is last in if (!ignoreSetQueue.isEmpty()) { bool tempFinalIgnoreSetsState = ignoreSetQueue.last(); ignoreSetQueue.clear(); if (tempFinalState) { ignoreSetQueue.enqueue(tempFinalIgnoreSetsState); } } } } void JoyButton::waitForDeskEvent() { if (quitEvent && !isButtonPressedQueue.isEmpty() && isButtonPressedQueue.last()) { if (createDeskTimer.isActive()) { keyPressTimer.stop(); createDeskTimer.stop(); releaseDeskTimer.stop(); createDeskEvent(); } else { keyPressTimer.stop(); releaseDeskTimer.stop(); createDeskEvent(); } /*else { createDeskTimer.start(0); releaseDeskTimer.stop(); keyDelayHold.restart(); }*/ } else if (!createDeskTimer.isActive()) { #ifdef Q_CC_MSVC createDeskTimer.start(5); releaseDeskTimer.stop(); #else createDeskTimer.start(0); releaseDeskTimer.stop(); #endif } else if (createDeskTimer.isActive()) { // Decrease timer interval of active timer. createDeskTimer.start(0); releaseDeskTimer.stop(); } } void JoyButton::waitForReleaseDeskEvent() { if (quitEvent && !keyPressTimer.isActive()) { if (releaseDeskTimer.isActive()) { releaseDeskTimer.stop(); } createDeskTimer.stop(); keyPressTimer.stop(); releaseDeskEvent(); } else if (!releaseDeskTimer.isActive()) { #ifdef Q_CC_MSVC releaseDeskTimer.start(1); createDeskTimer.stop(); #else releaseDeskTimer.start(1); createDeskTimer.stop(); #endif } else if (releaseDeskTimer.isActive()) { createDeskTimer.stop(); } } bool JoyButton::containsSequence() { bool result = false; assignmentsLock.lockForRead(); QListIterator tempiter(assignments); while (tempiter.hasNext()) { JoyButtonSlot *slot = tempiter.next(); JoyButtonSlot::JoySlotInputAction mode = slot->getSlotMode(); if (mode == JoyButtonSlot::JoyPause || mode == JoyButtonSlot::JoyHold || mode == JoyButtonSlot::JoyDistance ) { result = true; tempiter.toBack(); } } assignmentsLock.unlock(); return result; } void JoyButton::holdEvent() { if (currentHold) { bool currentlyPressed = false; if (!isButtonPressedQueue.isEmpty()) { currentlyPressed = isButtonPressedQueue.last(); } // Activate hold event if (currentlyPressed && buttonHold.elapsed() > currentHold->getSlotCode()) { releaseActiveSlots(); currentHold = 0; holdTimer.stop(); buttonHold.restart(); createDeskEvent(); } // Elapsed time has not occurred else if (currentlyPressed) { unsigned int holdTime = currentHold->getSlotCode(); int proposedInterval = holdTime - buttonHold.elapsed(); proposedInterval = proposedInterval > 0 ? proposedInterval : 0; int newTimerInterval = qMin(10, proposedInterval); holdTimer.start(newTimerInterval); } // Pre-emptive release else { currentHold = 0; holdTimer.stop(); if (slotiter) { findHoldEventEnd(); createDeskEvent(); } } } else { holdTimer.stop(); } } void JoyButton::delayEvent() { if (currentDelay) { bool currentlyPressed = false; if (!isButtonPressedQueue.isEmpty()) { currentlyPressed = isButtonPressedQueue.last(); } // Delay time has elapsed. Continue processing slots. if (currentDelay && buttonDelay.elapsed() > currentDelay->getSlotCode()) { currentDelay = 0; delayTimer.stop(); buttonDelay.restart(); createDeskEvent(); } // Elapsed time has not occurred else if (currentlyPressed) { unsigned int delayTime = currentDelay->getSlotCode(); int proposedInterval = delayTime - buttonDelay.elapsed(); proposedInterval = proposedInterval > 0 ? proposedInterval : 0; int newTimerInterval = qMin(10, proposedInterval); delayTimer.start(newTimerInterval); } // Pre-emptive release else { currentDelay = 0; delayTimer.stop(); } } else { delayTimer.stop(); } } void JoyButton::releaseDeskEvent(bool skipsetchange) { quitEvent = false; pauseWaitTimer.stop(); holdTimer.stop(); createDeskTimer.stop(); keyPressTimer.stop(); delayTimer.stop(); #ifdef Q_OS_WIN repeatHelper.getRepeatTimer()->stop(); #endif setChangeTimer.stop(); releaseActiveSlots(); if (!isButtonPressedQueue.isEmpty() && !currentRelease) { releaseSlotEvent(); } else if (currentRelease) { currentRelease = 0; } if (!skipsetchange && setSelectionCondition != SetChangeDisabled && !isButtonPressedQueue.isEmpty() && !currentRelease) { bool tempButtonPressed = isButtonPressedQueue.last(); bool tempFinalIgnoreSetsState = ignoreSetQueue.last(); if (!tempButtonPressed && !tempFinalIgnoreSetsState) { if (setSelectionCondition == SetChangeWhileHeld && whileHeldStatus) { setChangeTimer.start(0); } else if (setSelectionCondition != SetChangeWhileHeld) { setChangeTimer.start(); } } else { bool tempFinalState = false; if (!isButtonPressedQueue.isEmpty()) { tempFinalState = isButtonPressedQueue.last(); isButtonPressedQueue.clear(); if (tempFinalState) { isButtonPressedQueue.enqueue(tempFinalState); } } if (!ignoreSetQueue.isEmpty()) { bool tempFinalIgnoreSetsState = ignoreSetQueue.last(); ignoreSetQueue.clear(); if (tempFinalState) { ignoreSetQueue.enqueue(tempFinalIgnoreSetsState); } } } } else { bool tempFinalState = false; if (!isButtonPressedQueue.isEmpty()) { tempFinalState = isButtonPressedQueue.last(); isButtonPressedQueue.clear(); if (tempFinalState || currentRelease) { isButtonPressedQueue.enqueue(tempFinalState); } } if (!ignoreSetQueue.isEmpty()) { bool tempFinalIgnoreSetsState = ignoreSetQueue.last(); ignoreSetQueue.clear(); if (tempFinalState || currentRelease) { ignoreSetQueue.enqueue(tempFinalIgnoreSetsState); } } } if (!currentRelease) { lastAccelerationDistance = 0.0; currentAccelMulti = 0.0; currentAccelerationDistance = 0.0; startingAccelerationDistance = 0.0; oldAccelMulti = updateOldAccelMulti = 0.0; accelTravel = 0.0; accelExtraDurationTime.restart(); lastMouseDistance = 0.0; currentMouseDistance = 0.0; updateStartingMouseDistance = true; if (slotiter && !slotiter->hasNext()) { // At the end of the list of assignments. currentCycle = 0; previousCycle = 0; slotiter->toFront(); } else if (slotiter && slotiter->hasNext() && currentCycle) { // Cycle at the end of a segment. slotiter->toFront(); slotiter->findNext(currentCycle); } else if (slotiter && slotiter->hasPrevious() && slotiter->hasNext() && !currentCycle) { // Check if there is a cycle action slot after // current slot. Useful after dealing with pause // actions. JoyButtonSlot *tempslot = 0; bool exit = false; while (slotiter->hasNext() && !exit) { tempslot = slotiter->next(); if (tempslot->getSlotMode() == JoyButtonSlot::JoyCycle) { currentCycle = tempslot; exit = true; } } // Didn't find any cycle. Move iterator // to the front. if (!currentCycle) { slotiter->toFront(); previousCycle = 0; } } if (currentCycle) { previousCycle = currentCycle; currentCycle = 0; } else if (slotiter && slotiter->hasNext() && containsReleaseSlots()) { currentCycle = 0; previousCycle = 0; slotiter->toFront(); } this->currentDistance = 0; this->currentKeyPress = 0; quitEvent = true; } } /** * @brief Get the distance that an element is away from its assigned * dead zone * @return Normalized distance away from dead zone */ double JoyButton::getDistanceFromDeadZone() { double distance = 0.0; if (isButtonPressed) { distance = 1.0; } return distance; } double JoyButton::getAccelerationDistance() { return this->getDistanceFromDeadZone(); } /** * @brief Get the distance factor that should be used for mouse movement * @return Distance factor that should be used for mouse movement */ double JoyButton::getMouseDistanceFromDeadZone() { return this->getDistanceFromDeadZone(); } double JoyButton::getTotalSlotDistance(JoyButtonSlot *slot) { double tempDistance = 0.0; QListIterator iter(assignments); while (iter.hasNext()) { JoyButtonSlot *currentSlot = iter.next(); int tempcode = currentSlot->getSlotCode(); JoyButtonSlot::JoySlotInputAction mode = currentSlot->getSlotMode(); if (mode == JoyButtonSlot::JoyDistance) { tempDistance += tempcode / 100.0; if (slot == currentSlot) { // Current slot found. Go to end of iterator // so loop will exit iter.toBack(); } } // Reset tempDistance else if (mode == JoyButtonSlot::JoyCycle) { tempDistance = 0.0; } } return tempDistance; } bool JoyButton::containsDistanceSlots() { bool result = false; QListIterator iter(assignments); while (iter.hasNext()) { JoyButtonSlot *slot = iter.next(); if (slot->getSlotMode() == JoyButtonSlot::JoyDistance) { result = true; iter.toBack(); } } return result; } void JoyButton::clearAssignedSlots(bool signalEmit) { QListIterator iter(assignments); while (iter.hasNext()) { JoyButtonSlot *slot = iter.next(); if (slot) { delete slot; slot = 0; } } assignments.clear(); if (signalEmit) { emit slotsChanged(); } } void JoyButton::removeAssignedSlot(int index) { QWriteLocker tempAssignLocker(&assignmentsLock); if (index >= 0 && index < assignments.size()) { JoyButtonSlot *slot = assignments.takeAt(index); if (slot) { delete slot; slot = 0; } tempAssignLocker.unlock(); buildActiveZoneSummaryString(); emit slotsChanged(); } } void JoyButton::clearSlotsEventReset(bool clearSignalEmit) { QWriteLocker tempAssignLocker(&assignmentsLock); turboTimer.stop(); pauseWaitTimer.stop(); createDeskTimer.stop(); releaseDeskTimer.stop(); holdTimer.stop(); mouseWheelVerticalEventTimer.stop(); mouseWheelHorizontalEventTimer.stop(); setChangeTimer.stop(); keyPressTimer.stop(); delayTimer.stop(); activeZoneTimer.stop(); #ifdef Q_OS_WIN repeatHelper.getRepeatTimer()->stop(); #endif if (slotiter) { delete slotiter; slotiter = 0; } releaseActiveSlots(); clearAssignedSlots(clearSignalEmit); isButtonPressedQueue.clear(); ignoreSetQueue.clear(); mouseEventQueue.clear(); mouseWheelVerticalEventQueue.clear(); mouseWheelHorizontalEventQueue.clear(); currentCycle = 0; previousCycle = 0; currentPause = 0; currentHold = 0; currentDistance = 0; currentRawValue = 0; currentMouseEvent = 0; currentRelease = 0; currentWheelVerticalEvent = 0; currentWheelHorizontalEvent = 0; currentKeyPress = 0; currentDelay = 0; isKeyPressed = isButtonPressed = false; //buildActiveZoneSummaryString(); activeZoneTimer.start(); quitEvent = true; } void JoyButton::eventReset() { QWriteLocker tempAssignLocker(&assignmentsLock); turboTimer.stop(); pauseWaitTimer.stop(); createDeskTimer.stop(); releaseDeskTimer.stop(); holdTimer.stop(); mouseWheelVerticalEventTimer.stop(); mouseWheelHorizontalEventTimer.stop(); setChangeTimer.stop(); keyPressTimer.stop(); delayTimer.stop(); activeZoneTimer.stop(); #ifdef Q_OS_WIN repeatHelper.getRepeatTimer()->stop(); #endif if (slotiter) { delete slotiter; slotiter = 0; } isButtonPressedQueue.clear(); ignoreSetQueue.clear(); mouseEventQueue.clear(); mouseWheelVerticalEventQueue.clear(); mouseWheelHorizontalEventQueue.clear(); currentCycle = 0; previousCycle = 0; currentPause = 0; currentHold = 0; currentDistance = 0; currentRawValue = 0; currentMouseEvent = 0; currentRelease = 0; currentWheelVerticalEvent = 0; currentWheelHorizontalEvent = 0; currentKeyPress = 0; currentDelay = 0; isKeyPressed = isButtonPressed = false; releaseActiveSlots(); quitEvent = true; } void JoyButton::releaseActiveSlots() { if (!activeSlots.isEmpty()) { QWriteLocker tempLocker(&activeZoneLock); bool changeRepeatState = false; QListIterator iter(activeSlots); iter.toBack(); while (iter.hasPrevious()) { JoyButtonSlot *slot = iter.previous(); int tempcode = slot->getSlotCode(); JoyButtonSlot::JoySlotInputAction mode = slot->getSlotMode(); if (mode == JoyButtonSlot::JoyKeyboard) { int referencecount = activeKeys.value(tempcode, 1) - 1; if (referencecount <= 0) { sendevent(slot, false); activeKeys.remove(tempcode); changeRepeatState = true; } else { activeKeys.insert(tempcode, referencecount); } if (lastActiveKey == slot && referencecount <= 0) { lastActiveKey = 0; } } else if (mode == JoyButtonSlot::JoyMouseButton) { if (tempcode != JoyButtonSlot::MouseWheelUp && tempcode != JoyButtonSlot::MouseWheelDown && tempcode != JoyButtonSlot::MouseWheelLeft && tempcode != JoyButtonSlot::MouseWheelRight) { int referencecount = activeMouseButtons.value(tempcode, 1) - 1; if (referencecount <= 0) { sendevent(slot, false); activeMouseButtons.remove(tempcode); } else { activeMouseButtons.insert(tempcode, referencecount); } } else if (tempcode == JoyButtonSlot::MouseWheelUp || tempcode == JoyButtonSlot::MouseWheelDown) { mouseWheelVerticalEventQueue.removeAll(slot); } else if (tempcode == JoyButtonSlot::MouseWheelLeft || tempcode == JoyButtonSlot::MouseWheelRight) { mouseWheelHorizontalEventQueue.removeAll(slot); } slot->setDistance(0.0); slot->getMouseInterval()->restart(); } else if (mode == JoyButtonSlot::JoyMouseMovement) { JoyMouseMovementMode mousemode = getMouseMode(); if (mousemode == MouseCursor) { QListIterator iterX(cursorXSpeeds); unsigned int i = cursorXSpeeds.length(); QList indexesToRemove; while (iterX.hasNext()) { mouseCursorInfo info = iterX.next(); if (info.slot == slot) { indexesToRemove.append(i); } i++; } QListIterator removeXIter(indexesToRemove); while (removeXIter.hasPrevious()) { int index = removeXIter.previous(); cursorXSpeeds.removeAt(index); } indexesToRemove.clear(); i = cursorYSpeeds.length(); QListIterator iterY(cursorYSpeeds); while (iterY.hasNext()) { mouseCursorInfo info = iterY.next(); if (info.slot == slot) { indexesToRemove.append(i); } i++; } QListIterator removeYIter(indexesToRemove); while (removeYIter.hasPrevious()) { int index = removeYIter.previous(); cursorYSpeeds.removeAt(index); } indexesToRemove.clear(); slot->getEasingTime()->restart(); slot->setEasingStatus(false); } else if (mousemode == JoyButton::MouseSpring) { double mouse1 = (tempcode == JoyButtonSlot::MouseLeft || tempcode == JoyButtonSlot::MouseRight) ? 0.0 : -2.0; double mouse2 = (tempcode == JoyButtonSlot::MouseUp || tempcode == JoyButtonSlot::MouseDown) ? 0.0 : -2.0; double springDeadCircleX = 0.0; if (getSpringDeadCircleMultiplier() > 0) { if (tempcode == JoyButtonSlot::MouseLeft) { double temp = getCurrentSpringDeadCircle(); if (temp > getLastMouseDistanceFromDeadZone()) { springDeadCircleX = -getLastMouseDistanceFromDeadZone(); } else { springDeadCircleX = -temp; } } else if (tempcode == JoyButtonSlot::MouseRight) { double temp = getCurrentSpringDeadCircle(); if (temp > getLastMouseDistanceFromDeadZone()) { springDeadCircleX = getLastMouseDistanceFromDeadZone(); } else { springDeadCircleX = temp; } } } double springDeadCircleY = 0.0; if (getSpringDeadCircleMultiplier() > 0) { if (tempcode == JoyButtonSlot::MouseUp) { double temp = getCurrentSpringDeadCircle(); if (temp > getLastMouseDistanceFromDeadZone()) { springDeadCircleY = -getLastMouseDistanceFromDeadZone(); } else { springDeadCircleY = -temp; } } else if (tempcode == JoyButtonSlot::MouseDown) { double temp = getCurrentSpringDeadCircle(); if (temp > getLastMouseDistanceFromDeadZone()) { springDeadCircleY = getLastMouseDistanceFromDeadZone(); } else { springDeadCircleY = temp; } } } PadderCommon::springModeInfo infoX; infoX.displacementX = mouse1; infoX.displacementY = -2.0; infoX.springDeadX = springDeadCircleX; infoX.springDeadY = springDeadCircleY; infoX.width = springWidth; infoX.height = springHeight; infoX.relative = relativeSpring; infoX.screen = springModeScreen; springXSpeeds.append(infoX); PadderCommon::springModeInfo infoY; infoY.displacementX = -2.0; infoY.displacementY = mouse2; infoY.springDeadX = springDeadCircleX; infoY.springDeadY = springDeadCircleY; infoY.width = springWidth; infoY.height = springHeight; infoY.relative = relativeSpring; infoY.screen = springModeScreen; springYSpeeds.append(infoY); } mouseEventQueue.removeAll(slot); slot->setDistance(0.0); slot->getMouseInterval()->restart(); } else if (mode == JoyButtonSlot::JoyMouseSpeedMod) { int queueLength = mouseSpeedModList.length(); if (!mouseSpeedModList.isEmpty()) { mouseSpeedModList.removeAll(slot); queueLength -= 1; } if (queueLength <= 0) { mouseSpeedModifier = DEFAULTMOUSESPEEDMOD; } } else if (mode == JoyButtonSlot::JoySetChange) { currentSetChangeSlot = slot; slotSetChangeTimer.start(); } } activeSlots.clear(); currentMouseEvent = 0; if (!mouseEventQueue.isEmpty()) { mouseEventQueue.clear(); } pendingMouseButtons.removeAll(this); currentWheelVerticalEvent = 0; currentWheelHorizontalEvent = 0; mouseWheelVerticalEventTimer.stop(); mouseWheelHorizontalEventTimer.stop(); if (!mouseWheelVerticalEventQueue.isEmpty()) { mouseWheelVerticalEventQueue.clear(); lastWheelVerticalDistance = getMouseDistanceFromDeadZone(); wheelVerticalTime.restart(); } if (!mouseWheelHorizontalEventQueue.isEmpty()) { mouseWheelHorizontalEventQueue.clear(); lastWheelHorizontalDistance = getMouseDistanceFromDeadZone(); wheelHorizontalTime.restart(); } // Check if mouse remainder should be zero. // Only need to check one list from cursor speeds and spring speeds // since the correspond Y lists will be the same size. if (pendingMouseButtons.length() == 0 && cursorXSpeeds.length() == 0 && springXSpeeds.length() == 0) { //staticMouseEventTimer.setInterval(IDLEMOUSEREFRESHRATE); cursorRemainderX = 0; cursorRemainderY = 0; } //emit activeZoneChanged(); activeZoneTimer.start(); #ifdef Q_OS_WIN BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); if (handler && handler->getIdentifier() == "sendinput" && changeRepeatState && lastActiveKey && !useTurbo) { InputDevice *device = getParentSet()->getInputDevice(); if (device->isKeyRepeatEnabled()) { if (lastActiveKey) { repeatHelper.setLastActiveKey(lastActiveKey); repeatHelper.setKeyRepeatRate(device->getKeyRepeatRate()); repeatHelper.getRepeatTimer()->start(device->getKeyRepeatDelay()); } else if (repeatHelper.getRepeatTimer()->isActive()) { repeatHelper.setLastActiveKey(0); repeatHelper.getRepeatTimer()->stop(); } } } #endif } } bool JoyButton::containsReleaseSlots() { bool result = false; QListIterator iter(assignments); while (iter.hasNext()) { JoyButtonSlot *slot = iter.next(); if (slot->getSlotMode() == JoyButtonSlot::JoyRelease) { result = true; iter.toBack(); } } return result; } void JoyButton::releaseSlotEvent() { JoyButtonSlot *temp = 0; int timeElapsed = buttonHeldRelease.elapsed(); int tempElapsed = 0; if (containsReleaseSlots()) { QListIterator iter(assignments); if (previousCycle) { iter.findNext(previousCycle); } while (iter.hasNext()) { JoyButtonSlot *currentSlot = iter.next(); int tempcode = currentSlot->getSlotCode(); JoyButtonSlot::JoySlotInputAction mode = currentSlot->getSlotMode(); if (mode == JoyButtonSlot::JoyRelease) { tempElapsed += tempcode; if (tempElapsed <= timeElapsed) { temp = currentSlot; } else if (tempElapsed > timeElapsed) { iter.toBack(); } } else if (mode == JoyButtonSlot::JoyCycle) { tempElapsed = 0; iter.toBack(); } } if (temp && slotiter) { slotiter->toFront(); slotiter->findNext(temp); currentRelease = temp; activateSlots(); if (!keyPressTimer.isActive() && !pauseWaitTimer.isActive()) { releaseActiveSlots(); currentRelease = 0; } // Stop hold timer here to be sure that // a hold timer that could be activated // during a release event is stopped. holdTimer.stop(); if (currentHold) { currentHold = 0; } } } } void JoyButton::findReleaseEventEnd() { bool found = false; while (!found && slotiter->hasNext()) { JoyButtonSlot *currentSlot = slotiter->next(); JoyButtonSlot::JoySlotInputAction mode = currentSlot->getSlotMode(); if (mode == JoyButtonSlot::JoyRelease) { found = true; } else if (mode == JoyButtonSlot::JoyCycle) { found = true; } else if (mode == JoyButtonSlot::JoyHold) { found = true; } } if (found && slotiter->hasPrevious()) { slotiter->previous(); } } void JoyButton::findReleaseEventIterEnd(QListIterator *tempiter) { bool found = false; if (tempiter) { while (!found && tempiter->hasNext()) { JoyButtonSlot *currentSlot = tempiter->next(); JoyButtonSlot::JoySlotInputAction mode = currentSlot->getSlotMode(); if (mode == JoyButtonSlot::JoyRelease) { found = true; } else if (mode == JoyButtonSlot::JoyCycle) { found = true; } else if (mode == JoyButtonSlot::JoyHold) { found = true; } } if (found && tempiter->hasPrevious()) { tempiter->previous(); } } } void JoyButton::findHoldEventEnd() { bool found = false; while (!found && slotiter->hasNext()) { JoyButtonSlot *currentSlot = slotiter->next(); JoyButtonSlot::JoySlotInputAction mode = currentSlot->getSlotMode(); if (mode == JoyButtonSlot::JoyRelease) { found = true; } else if (mode == JoyButtonSlot::JoyCycle) { found = true; } else if (mode == JoyButtonSlot::JoyHold) { found = true; } } if (found && slotiter->hasPrevious()) { slotiter->previous(); } } void JoyButton::setVDPad(VDPad *vdpad) { joyEvent(false, true); this->vdpad = vdpad; emit propertyUpdated(); } bool JoyButton::isPartVDPad() { return (this->vdpad != 0); } VDPad* JoyButton::getVDPad() { return this->vdpad; } void JoyButton::removeVDPad() { this->vdpad = 0; emit propertyUpdated(); } /** * @brief Check if button properties are at their default values * @return Status of possible property edits */ bool JoyButton::isDefault() { bool value = true; value = value && (toggle == DEFAULTTOGGLE); value = value && (turboInterval == DEFAULTTURBOINTERVAL); value = value && (currentTurboMode == NormalTurbo); value = value && (useTurbo == DEFAULTUSETURBO); value = value && (mouseSpeedX == DEFAULTMOUSESPEEDX); value = value && (mouseSpeedY == DEFAULTMOUSESPEEDY); value = value && (setSelection == DEFAULTSETSELECTION); value = value && (setSelectionCondition == DEFAULTSETCONDITION); value = value && (assignments.isEmpty()); value = value && (mouseMode == DEFAULTMOUSEMODE); value = value && (mouseCurve == DEFAULTMOUSECURVE); value = value && (springWidth == DEFAULTSPRINGWIDTH); value = value && (springHeight == DEFAULTSPRINGHEIGHT); value = value && (sensitivity == DEFAULTSENSITIVITY); value = value && (actionName.isEmpty()); //value = value && (buttonName.isEmpty()); value = value && (wheelSpeedX == DEFAULTWHEELX); value = value && (wheelSpeedY == DEFAULTWHEELY); value = value && (cycleResetActive == DEFAULTCYCLERESETACTIVE); value = value && (cycleResetInterval == DEFAULTCYCLERESET); value = value && (relativeSpring == DEFAULTRELATIVESPRING); value = value && (easingDuration == DEFAULTEASINGDURATION); value = value && (extraAccelerationEnabled == false); value = value && (extraAccelerationMultiplier == DEFAULTEXTRACCELVALUE); value = value && (minMouseDistanceAccelThreshold == DEFAULTMINACCELTHRESHOLD); value = value && (maxMouseDistanceAccelThreshold == DEFAULTMAXACCELTHRESHOLD); value = value && (startAccelMultiplier == DEFAULTSTARTACCELMULTIPLIER); value = value && (accelDuration == DEFAULTACCELEASINGDURATION); value = value && (springDeadCircleMultiplier == DEFAULTSPRINGRELEASERADIUS); value = value && (extraAccelCurve == DEFAULTEXTRAACCELCURVE); return value; } void JoyButton::setIgnoreEventState(bool ignore) { ignoreEvents = ignore; } bool JoyButton::getIgnoreEventState() { return ignoreEvents; } void JoyButton::setMouseMode(JoyMouseMovementMode mousemode) { this->mouseMode = mousemode; emit propertyUpdated(); } JoyButton::JoyMouseMovementMode JoyButton::getMouseMode() { return mouseMode; } void JoyButton::setMouseCurve(JoyMouseCurve selectedCurve) { mouseCurve = selectedCurve; emit propertyUpdated(); } JoyButton::JoyMouseCurve JoyButton::getMouseCurve() { return mouseCurve; } void JoyButton::setSpringWidth(int value) { if (value >= 0) { springWidth = value; emit propertyUpdated(); } } int JoyButton::getSpringWidth() { return springWidth; } void JoyButton::setSpringHeight(int value) { if (springHeight >= 0) { springHeight = value; emit propertyUpdated(); } } int JoyButton::getSpringHeight() { return springHeight; } void JoyButton::setSensitivity(double value) { if (value >= 0.001 && value <= 1000) { sensitivity = value; emit propertyUpdated(); } } double JoyButton::getSensitivity() { return sensitivity; } bool JoyButton::getWhileHeldStatus() { return whileHeldStatus; } void JoyButton::setWhileHeldStatus(bool status) { whileHeldStatus = status; } void JoyButton::setActionName(QString tempName) { if (tempName.length() <= 50 && tempName != actionName) { actionName = tempName; emit actionNameChanged(); emit propertyUpdated(); } } QString JoyButton::getActionName() { return actionName; } void JoyButton::setButtonName(QString tempName) { if (tempName.length() <= 20 && tempName != buttonName) { buttonName = tempName; emit buttonNameChanged(); emit propertyUpdated(); } } QString JoyButton::getButtonName() { return buttonName; } void JoyButton::setWheelSpeedX(int speed) { if (speed >= 1 && speed <= 100) { wheelSpeedX = speed; emit propertyUpdated(); } } void JoyButton::setWheelSpeedY(int speed) { if (speed >= 1 && speed <= 100) { wheelSpeedY = speed; emit propertyUpdated(); } } int JoyButton::getWheelSpeedX() { return wheelSpeedX; } int JoyButton::getWheelSpeedY() { return wheelSpeedY; } void JoyButton::setDefaultButtonName(QString tempname) { defaultButtonName = tempname; } QString JoyButton::getDefaultButtonName() { return defaultButtonName; } /** * @brief Take cursor mouse information provided by all buttons and * send a cursor mode mouse event to the display server. */ void JoyButton::moveMouseCursor(int &movedX, int &movedY, int &movedElapsed) { movedX = 0; movedY = 0; double finalx = 0.0; double finaly = 0.0; //int elapsedTime = lastMouseTime.elapsed(); int elapsedTime = testOldMouseTime.elapsed(); movedElapsed = elapsedTime; if (staticMouseEventTimer.interval() < mouseRefreshRate) { elapsedTime = mouseRefreshRate + (elapsedTime - staticMouseEventTimer.interval()); movedElapsed = elapsedTime; } if (mouseHistoryX.size() >= mouseHistorySize) { mouseHistoryX.removeLast(); } if (mouseHistoryY.size() >= mouseHistorySize) { mouseHistoryY.removeLast(); } /* * Combine all mouse events to find the distance to move the mouse * along the X and Y axis. If necessary, perform mouse smoothing. * The mouse smoothing technique used is an interpretation of the method * outlined at http://flipcode.net/archives/Smooth_Mouse_Filtering.shtml. */ if (cursorXSpeeds.length() == cursorYSpeeds.length() && cursorXSpeeds.length() > 0) { int queueLength = cursorXSpeeds.length(); for (int i=0; i < queueLength; i++) { mouseCursorInfo infoX = cursorXSpeeds.takeFirst(); mouseCursorInfo infoY = cursorYSpeeds.takeFirst(); if (infoX.code != 0) { finalx = (infoX.code < 0) ? qMin(infoX.code, finalx) : qMax(infoX.code, finalx); } if (infoY.code != 0) { finaly = (infoY.code < 0) ? qMin(infoY.code, finaly) : qMax(infoY.code, finaly); } infoX.slot->getMouseInterval()->restart(); infoY.slot->getMouseInterval()->restart(); } // Only apply remainder if both current displacement and remainder // follow the same direction. if ((cursorRemainderX >= 0) == (finalx >= 0)) { finalx += cursorRemainderX; } // Cap maximum relative mouse movement. if (abs(finalx) > 127) { finalx = (finalx < 0) ? -127 : 127; } mouseHistoryX.prepend(finalx); // Only apply remainder if both current displacement and remainder // follow the same direction. if ((cursorRemainderY >= 0) == (finaly >= 0)) { finaly += cursorRemainderY; } // Cap maximum relative mouse movement. if (abs(finaly) > 127) { finaly = (finaly < 0) ? -127 : 127; } mouseHistoryY.prepend(finaly); cursorRemainderX = 0; cursorRemainderY = 0; double adjustedX = 0; double adjustedY = 0; QListIterator iterX(mouseHistoryX); double currentWeight = 1.0; double weightModifier = JoyButton::weightModifier; double finalWeight = 0.0; while (iterX.hasNext()) { double temp = iterX.next(); adjustedX += temp * currentWeight; finalWeight += currentWeight; currentWeight *= weightModifier; } if (fabs(adjustedX) > 0) { adjustedX = adjustedX / static_cast(finalWeight); if (adjustedX > 0) { double oldX = adjustedX; adjustedX = static_cast(floor(adjustedX)); //adjustedX = (int)floor(adjustedX + 0.5); // Old rounding behavior cursorRemainderX = oldX - adjustedX; } else { double oldX = adjustedX; adjustedX = static_cast(ceil(adjustedX)); //adjustedX = (int)ceil(adjustedX - 0.5); // Old rounding behavior cursorRemainderX = oldX - adjustedX; } } QListIterator iterY(mouseHistoryY); currentWeight = 1.0; finalWeight = 0.0; while (iterY.hasNext()) { double temp = iterY.next(); adjustedY += temp * currentWeight; finalWeight += currentWeight; currentWeight *= weightModifier; } if (fabs(adjustedY) > 0) { adjustedY = adjustedY / static_cast(finalWeight); if (adjustedY > 0) { double oldY = adjustedY; adjustedY = static_cast(floor(adjustedY)); //adjustedY = (int)floor(adjustedY + 0.5); // Old rounding behavior cursorRemainderY = oldY - adjustedY; } else { double oldY = adjustedY; adjustedY = static_cast(ceil(adjustedY)); //adjustedY = (int)ceil(adjustedY - 0.5); // Old rounding behavior cursorRemainderY = oldY - adjustedY; } } // This check is more of a precaution than anything. No need to cause // a sync to happen when not needed. if (adjustedX != 0 || adjustedY != 0) { sendevent(adjustedX, adjustedY); } //Logger::LogInfo(QString("FINAL X: %1").arg(adjustedX)); //Logger::LogInfo(QString("FINAL Y: %1\n").arg(adjustedY)); //Logger::LogInfo(QString("ELAPSED: %1\n").arg(elapsedTime)); //Logger::LogInfo(QString("REMAINDER X: %1").arg(cursorRemainderX)); movedX = static_cast(adjustedX); movedY = static_cast(adjustedY); } else { mouseHistoryX.prepend(0); mouseHistoryY.prepend(0); } //lastMouseTime.restart(); // Check if mouse event timer should use idle time. if (pendingMouseButtons.length() == 0) { if (staticMouseEventTimer.interval() != IDLEMOUSEREFRESHRATE) { staticMouseEventTimer.start(IDLEMOUSEREFRESHRATE); // Clear current mouse history mouseHistoryX.clear(); mouseHistoryY.clear(); // Fill history with zeroes. for (int i=0; i < mouseHistorySize; i++) { mouseHistoryX.append(0); mouseHistoryY.append(0); } } cursorRemainderX = 0; cursorRemainderY = 0; } else { if (staticMouseEventTimer.interval() != mouseRefreshRate) { // Restore intended QTimer interval. staticMouseEventTimer.start(mouseRefreshRate); } } cursorXSpeeds.clear(); cursorYSpeeds.clear(); } /** * @brief Take spring mouse information provided by all buttons and * send a spring mode mouse event to the display server. */ void JoyButton::moveSpringMouse(int &movedX, int &movedY, bool &hasMoved) { PadderCommon::springModeInfo fullSpring = { -2.0, -2.0, 0, 0, false, springModeScreen, 0.0, 0.0 }; PadderCommon::springModeInfo relativeSpring = { -2.0, -2.0, 0, 0, false, springModeScreen, 0.0, 0.0 }; int realMouseX = movedX = 0; int realMouseY = movedY = 0; hasMoved = false; if (springXSpeeds.length() == springYSpeeds.length() && springXSpeeds.length() > 0) { int queueLength = springXSpeeds.length(); bool complete = false; for (int i=queueLength-1; i >= 0 && !complete; i--) { double tempx = -2.0; double tempy = -2.0; double tempSpringDeadX = 0.0; double tempSpringDeadY = 0.0; PadderCommon::springModeInfo infoX; PadderCommon::springModeInfo infoY; infoX = springXSpeeds.takeLast(); infoY = springYSpeeds.takeLast(); tempx = infoX.displacementX; tempy = infoY.displacementY; tempSpringDeadX = infoX.springDeadX; tempSpringDeadY = infoY.springDeadY; if (infoX.relative) { if (relativeSpring.displacementX == -2.0) { relativeSpring.displacementX = tempx; } relativeSpring.relative = true; // Use largest found width for spring // mode dimensions. relativeSpring.width = qMax(infoX.width, relativeSpring.width); } else { if (fullSpring.displacementX == -2.0) { fullSpring.displacementX = tempx; } if (fullSpring.springDeadX == 0.0) { fullSpring.springDeadX = tempSpringDeadX; } // Use largest found width for spring // mode dimensions. fullSpring.width = qMax(infoX.width, fullSpring.width); } if (infoY.relative) { if (relativeSpring.displacementY == -2.0) { relativeSpring.displacementY = tempy; } relativeSpring.relative = true; // Use largest found height for spring // mode dimensions. relativeSpring.height = qMax(infoX.height, relativeSpring.height); } else { if (fullSpring.displacementY == -2.0) { fullSpring.displacementY = tempy; } if (fullSpring.springDeadY == 0.0) { fullSpring.springDeadY = tempSpringDeadY; } // Use largest found height for spring // mode dimensions. fullSpring.height = qMax(infoX.height, fullSpring.height); } if ((relativeSpring.displacementX != -2.0 && relativeSpring.displacementY != -2.0) && (fullSpring.displacementX != -2.0 && fullSpring.displacementY != -2.0)) { complete = true; } else if ((relativeSpring.springDeadX != 0.0 && relativeSpring.springDeadY != 0.0) && (fullSpring.springDeadX != 0.0 && fullSpring.springDeadY != 0.0)) { complete = true; } } fullSpring.screen = springModeScreen; relativeSpring.screen = springModeScreen; if (relativeSpring.relative) { sendSpringEvent(&fullSpring, &relativeSpring, &realMouseX, &realMouseY); } else { if (!hasFutureSpringEvents()) { if (fullSpring.springDeadX != 0.0) { fullSpring.displacementX = fullSpring.springDeadX; } if (fullSpring.springDeadY != 0.0) { fullSpring.displacementY = fullSpring.springDeadY; } sendSpringEvent(&fullSpring, 0, &realMouseX, &realMouseY); } else { sendSpringEvent(&fullSpring, 0, &realMouseX, &realMouseY); } } movedX = realMouseX; movedY = realMouseY; hasMoved = true; } //lastMouseTime.restart(); // Check if mouse event timer should use idle time. if (pendingMouseButtons.length() == 0) { staticMouseEventTimer.start(IDLEMOUSEREFRESHRATE); } else { if (staticMouseEventTimer.interval() != mouseRefreshRate) { // Restore intended QTimer interval. staticMouseEventTimer.start(mouseRefreshRate); } } springXSpeeds.clear(); springYSpeeds.clear(); } void JoyButton::keyPressEvent() { //qDebug() << "RADIO EDIT: " << keyDelayHold.elapsed(); if (keyPressTimer.isActive() && keyPressHold.elapsed() >= getPreferredKeyPressTime()) { currentKeyPress = 0; keyPressTimer.stop(); keyPressHold.restart(); releaseActiveSlots(); createDeskTimer.stop(); if (currentRelease) { releaseDeskTimer.stop(); createDeskEvent(); waitForReleaseDeskEvent(); } else { createDeskEvent(); } } else { createDeskTimer.stop(); //releaseDeskTimer.stop(); unsigned int preferredDelay = getPreferredKeyPressTime(); int proposedInterval = preferredDelay - keyPressHold.elapsed(); proposedInterval = proposedInterval > 0 ? proposedInterval : 0; int newTimerInterval = qMin(10, proposedInterval); keyPressTimer.start(newTimerInterval); // If release timer is active, push next run until // after keyDelayTimer will timeout again. Helps // reduce CPU usage of an excessively repeating timer. if (releaseDeskTimer.isActive()) { releaseDeskTimer.start(proposedInterval); } } } /** * @brief TODO: CHECK IF METHOD WOULD BE USEFUL. CURRENTLY NOT USED. * @return Result */ bool JoyButton::checkForDelaySequence() { bool result = false; QListIterator tempiter(assignments); // Move iterator to start of cycle. if (previousCycle) { tempiter.findNext(previousCycle); } while (tempiter.hasNext()) { JoyButtonSlot *slot = tempiter.next(); JoyButtonSlot::JoySlotInputAction mode = slot->getSlotMode(); if (mode == JoyButtonSlot::JoyPause || mode == JoyButtonSlot::JoyRelease) { result = true; tempiter.toBack(); } else if (mode == JoyButtonSlot::JoyCycle) { result = false; tempiter.toBack(); } } return result; } SetJoystick* JoyButton::getParentSet() { return parentSet; } void JoyButton::checkForPressedSetChange() { if (!isButtonPressedQueue.isEmpty()) { bool tempButtonPressed = isButtonPressedQueue.last(); bool tempFinalIgnoreSetsState = ignoreSetQueue.last(); if (!whileHeldStatus) { if (tempButtonPressed && !tempFinalIgnoreSetsState && setSelectionCondition == SetChangeWhileHeld && !currentRelease) { setChangeTimer.start(0); quitEvent = true; } } } } /** * @brief Obtain the appropriate key press time for the current event. * Order of preference: active key press time slot value -> * profile value -> program default value. * @return Appropriate key press time for current event. */ unsigned int JoyButton::getPreferredKeyPressTime() { unsigned int tempPressTime = InputDevice::DEFAULTKEYPRESSTIME; if (currentKeyPress && currentKeyPress->getSlotCode() > 0) { tempPressTime = static_cast(currentKeyPress->getSlotCode()); } else if (parentSet->getInputDevice()->getDeviceKeyPressTime() > 0) { tempPressTime = parentSet->getInputDevice()->getDeviceKeyPressTime(); } return tempPressTime; } void JoyButton::setCycleResetTime(unsigned int interval) { if (interval >= MINCYCLERESETTIME) { unsigned int ceiling = MAXCYCLERESETTIME; unsigned int temp = qBound(MINCYCLERESETTIME, interval, ceiling); cycleResetInterval = temp; emit propertyUpdated(); } else { interval = 0; cycleResetActive = false; emit propertyUpdated(); } } unsigned int JoyButton::getCycleResetTime() { return cycleResetInterval; } void JoyButton::setCycleResetStatus(bool enabled) { cycleResetActive = enabled; emit propertyUpdated(); } bool JoyButton::isCycleResetActive() { return cycleResetActive; } void JoyButton::establishPropertyUpdatedConnections() { connect(this, SIGNAL(slotsChanged()), parentSet->getInputDevice(), SLOT(profileEdited())); connect(this, SIGNAL(propertyUpdated()), parentSet->getInputDevice(), SLOT(profileEdited())); } void JoyButton::disconnectPropertyUpdatedConnections() { disconnect(this, SIGNAL(slotsChanged()), 0, 0); disconnect(this, SIGNAL(propertyUpdated()), parentSet->getInputDevice(), SLOT(profileEdited())); } /** * @brief Change initial settings used for mouse event timer being used by * the application. */ void JoyButton::establishMouseTimerConnections() { #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (staticMouseEventTimer.timerType() != Qt::PreciseTimer) { staticMouseEventTimer.setTimerType(Qt::PreciseTimer); } #endif // Only one connection will be made for each. connect(&staticMouseEventTimer, SIGNAL(timeout()), &mouseHelper, SLOT(mouseEvent()), Qt::UniqueConnection); if (staticMouseEventTimer.interval() != IDLEMOUSEREFRESHRATE) { staticMouseEventTimer.setInterval(IDLEMOUSEREFRESHRATE); } /*if (!staticMouseEventTimer.isActive()) { lastMouseTime.start(); staticMouseEventTimer.start(IDLEMOUSEREFRESHRATE); } */ } void JoyButton::setSpringRelativeStatus(bool value) { if (value != relativeSpring) { if (value) { setSpringDeadCircleMultiplier(0); } relativeSpring = value; emit propertyUpdated(); } } bool JoyButton::isRelativeSpring() { return relativeSpring; } /** * @brief Copy assignments and properties from one button to another. * Used for set copying. * @param Button instance that should be modified. */ void JoyButton::copyAssignments(JoyButton *destButton) { destButton->eventReset(); destButton->assignmentsLock.lockForWrite(); destButton->assignments.clear(); destButton->assignmentsLock.unlock(); assignmentsLock.lockForWrite(); QListIterator iter(assignments); while (iter.hasNext()) { JoyButtonSlot *slot = iter.next(); JoyButtonSlot *newslot = new JoyButtonSlot(slot, destButton); destButton->insertAssignedSlot(newslot, false); } assignmentsLock.unlock(); destButton->toggle = toggle; destButton->turboInterval = turboInterval; destButton->useTurbo = useTurbo; destButton->mouseSpeedX = mouseSpeedX; destButton->mouseSpeedY = mouseSpeedY; destButton->wheelSpeedX = wheelSpeedX; destButton->wheelSpeedY = wheelSpeedY; destButton->mouseMode = mouseMode; destButton->mouseCurve = mouseCurve; destButton->springWidth = springWidth; destButton->springHeight = springHeight; destButton->sensitivity = sensitivity; //destButton->setSelection = setSelection; //destButton->setSelectionCondition = setSelectionCondition; destButton->buttonName = buttonName; destButton->actionName = actionName; destButton->cycleResetActive = cycleResetActive; destButton->cycleResetInterval = cycleResetInterval; destButton->relativeSpring = relativeSpring; destButton->currentTurboMode = currentTurboMode; destButton->easingDuration = easingDuration; destButton->extraAccelerationEnabled = extraAccelerationEnabled; destButton->extraAccelerationMultiplier = extraAccelerationMultiplier; destButton->minMouseDistanceAccelThreshold = minMouseDistanceAccelThreshold; destButton->maxMouseDistanceAccelThreshold = maxMouseDistanceAccelThreshold; destButton->startAccelMultiplier = startAccelMultiplier; destButton->springDeadCircleMultiplier = springDeadCircleMultiplier; destButton->extraAccelCurve = extraAccelCurve; destButton->buildActiveZoneSummaryString(); if (!destButton->isDefault()) { emit propertyUpdated(); } } /** * @brief Set the turbo mode that the button should use * @param Mode that should be used */ void JoyButton::setTurboMode(TurboMode mode) { currentTurboMode = mode; } /** * @brief Get currently assigned turbo mode * @return Currently assigned turbo mode */ JoyButton::TurboMode JoyButton::getTurboMode() { return currentTurboMode; } /** * @brief Check if button should be considered a part of a real controller * axis. Needed for some dialogs so the program won't have to resort to * type checking. * @return Status of being part of a real controller axis */ bool JoyButton::isPartRealAxis() { return false; } /** * @brief Calculate maximum mouse speed when using a given mouse curve. * @param Mouse curve * @param Mouse speed value * @return Final mouse speed */ int JoyButton::calculateFinalMouseSpeed(JoyMouseCurve curve, int value) { int result = JoyAxis::JOYSPEED * value; switch (curve) { case QuadraticExtremeCurve: case EasingQuadraticCurve: case EasingCubicCurve: { result *= 1.5; break; } } return result; } void JoyButton::setEasingDuration(double value) { if (value >= MINIMUMEASINGDURATION && value <= MAXIMUMEASINGDURATION && value != easingDuration) { easingDuration = value; emit propertyUpdated(); } } double JoyButton::getEasingDuration() { return easingDuration; } JoyButtonMouseHelper* JoyButton::getMouseHelper() { return &mouseHelper; } /** * @brief Get the list of buttons that have a pending mouse movement event. * @return QList* */ QList* JoyButton::getPendingMouseButtons() { return &pendingMouseButtons; } bool JoyButton::hasCursorEvents() { return (cursorXSpeeds.length() != 0) || (cursorYSpeeds.length() != 0); } bool JoyButton::hasSpringEvents() { return (springXSpeeds.length() != 0) || (springYSpeeds.length() != 0); } /** * @brief Get the weight modifier being used for mouse smoothing. * @return Weight modifier in the range of 0.0 - 1.0. */ double JoyButton::getWeightModifier() { return weightModifier; } /** * @brief Set the weight modifier to use for mouse smoothing. * @param Weight modifier in the range of 0.0 - 1.0. */ void JoyButton::setWeightModifier(double modifier) { if (modifier >= 0.0 && modifier <= MAXIMUMWEIGHTMODIFIER) { weightModifier = modifier; } } /** * @brief Get mouse history buffer size. * @return Mouse history buffer size */ int JoyButton::getMouseHistorySize() { return mouseHistorySize; } /** * @brief Set mouse history buffer size used for mouse smoothing. * @param Mouse history buffer size */ void JoyButton::setMouseHistorySize(int size) { if (size >= 1 && size <= MAXIMUMMOUSEHISTORYSIZE) { mouseHistoryX.clear(); mouseHistoryY.clear(); mouseHistorySize = size; } } /** * @brief Get active mouse movement refresh rate. * @return */ int JoyButton::getMouseRefreshRate() { return mouseRefreshRate; } /** * @brief Set the mouse refresh rate when a mouse slot is active. * @param Refresh rate in ms. */ void JoyButton::setMouseRefreshRate(int refresh) { if (refresh >= 1 && refresh <= 16) { mouseRefreshRate = refresh; int temp = IDLEMOUSEREFRESHRATE; //IDLEMOUSEREFRESHRATE = mouseRefreshRate * 20; if (staticMouseEventTimer.isActive()) { testOldMouseTime.restart(); //lastMouseTime.restart(); int tempInterval = staticMouseEventTimer.interval(); if (tempInterval != temp && tempInterval != 0) { QMetaObject::invokeMethod(&staticMouseEventTimer, "start", Q_ARG(int, mouseRefreshRate)); } else { // Restart QTimer to keep QTimer in line with QTime QMetaObject::invokeMethod(&staticMouseEventTimer, "start", Q_ARG(int, temp)); } // Clear current mouse history mouseHistoryX.clear(); mouseHistoryY.clear(); } else { staticMouseEventTimer.setInterval(IDLEMOUSEREFRESHRATE); } mouseHelper.carryMouseRefreshRateUpdate(mouseRefreshRate); } } /** * @brief Get the gamepad poll rate used by the application. * @return Poll rate in ms. */ int JoyButton::getGamepadRefreshRate() { return gamepadRefreshRate; } /** * @brief Set the gamepad poll rate to be used in the application. * @param Poll rate in ms. */ void JoyButton::setGamepadRefreshRate(int refresh) { if (refresh >= 1 && refresh <= 16) { gamepadRefreshRate = refresh; mouseHelper.carryGamePollRateUpdate(gamepadRefreshRate); } } /** * @brief Check if turbo should be disabled for a slot * @param JoyButtonSlot to check */ void JoyButton::checkTurboCondition(JoyButtonSlot *slot) { JoyButtonSlot::JoySlotInputAction mode = slot->getSlotMode(); switch (mode) { case JoyButtonSlot::JoyPause: case JoyButtonSlot::JoyHold: case JoyButtonSlot::JoyDistance: case JoyButtonSlot::JoyRelease: case JoyButtonSlot::JoyLoadProfile: case JoyButtonSlot::JoySetChange: { setUseTurbo(false); break; } } } void JoyButton::resetProperties() { currentCycle = 0; previousCycle = 0; currentPause = 0; currentHold = 0; currentDistance = 0; currentRawValue = 0; currentMouseEvent = 0; currentRelease = 0; currentWheelVerticalEvent = 0; currentWheelHorizontalEvent = 0; currentKeyPress = 0; currentDelay = 0; currentSetChangeSlot = 0; isKeyPressed = isButtonPressed = false; quitEvent = true; toggle = false; turboInterval = 0; isDown = false; toggleActiveState = false; useTurbo = false; mouseSpeedX = 50; mouseSpeedY = 50; wheelSpeedX = 20; wheelSpeedY = 20; mouseMode = MouseCursor; mouseCurve = DEFAULTMOUSECURVE; springWidth = 0; springHeight = 0; sensitivity = 1.0; setSelection = -1; setSelectionCondition = SetChangeDisabled; ignoresets = false; ignoreEvents = false; whileHeldStatus = false; buttonName.clear(); actionName.clear(); cycleResetActive = false; cycleResetInterval = 0; relativeSpring = false; lastDistance = 0.0; currentAccelMulti = 0.0; lastAccelerationDistance = 0.0; lastMouseDistance = 0.0; currentMouseDistance = 0.0; updateLastMouseDistance = false; updateStartingMouseDistance = false; updateOldAccelMulti = 0.0; updateInitAccelValues = true; currentAccelerationDistance = 0.0; startingAccelerationDistance = 0.0; lastWheelVerticalDistance = 0.0; lastWheelHorizontalDistance = 0.0; tempTurboInterval = 0; //currentTurboMode = GradientTurbo; oldAccelMulti = 0.0; accelTravel = 0.0; currentTurboMode = DEFAULTTURBOMODE; easingDuration = DEFAULTEASINGDURATION; springDeadCircleMultiplier = DEFAULTSPRINGRELEASERADIUS; pendingEvent = false; pendingPress = false; pendingIgnoreSets = false; extraAccelerationEnabled = false; extraAccelerationMultiplier = DEFAULTEXTRACCELVALUE; minMouseDistanceAccelThreshold = DEFAULTMINACCELTHRESHOLD; maxMouseDistanceAccelThreshold = DEFAULTMAXACCELTHRESHOLD; startAccelMultiplier = DEFAULTSTARTACCELMULTIPLIER; accelDuration = DEFAULTACCELEASINGDURATION; extraAccelCurve = LinearAccelCurve; activeZoneStringLock.lockForWrite(); activeZoneString = tr("[NO KEY]"); activeZoneStringLock.unlock(); } bool JoyButton::isModifierButton() { return false; } void JoyButton::resetActiveButtonMouseDistances() { mouseHelper.resetButtonMouseDistances(); } void JoyButton::resetAccelerationDistances() { if (updateLastMouseDistance) { lastAccelerationDistance = currentAccelerationDistance; lastMouseDistance = currentMouseDistance; updateLastMouseDistance = false; } if (updateStartingMouseDistance) { startingAccelerationDistance = lastAccelerationDistance; updateStartingMouseDistance = false; } if (updateOldAccelMulti >= 0.0) { oldAccelMulti = updateOldAccelMulti; updateOldAccelMulti = 0.0; } currentAccelerationDistance = getAccelerationDistance(); currentMouseDistance = getMouseDistanceFromDeadZone(); } void JoyButton::initializeDistanceValues() { lastAccelerationDistance = getLastAccelerationDistance(); currentAccelerationDistance = getAccelerationDistance(); startingAccelerationDistance = lastAccelerationDistance; lastMouseDistance = getLastMouseDistanceFromDeadZone(); currentMouseDistance = getMouseDistanceFromDeadZone(); } double JoyButton::getLastMouseDistanceFromDeadZone() { return lastMouseDistance; } double JoyButton::getLastAccelerationDistance() { return lastAccelerationDistance; } void JoyButton::copyLastMouseDistanceFromDeadZone(JoyButton *srcButton) { this->lastMouseDistance = srcButton->lastMouseDistance; } void JoyButton::copyLastAccelerationDistance(JoyButton *srcButton) { this->lastAccelerationDistance = srcButton->lastAccelerationDistance; } bool JoyButton::isExtraAccelerationEnabled() { return extraAccelerationEnabled; } double JoyButton::getExtraAccelerationMultiplier() { return extraAccelerationMultiplier; } void JoyButton::setExtraAccelerationStatus(bool status) { if (isPartRealAxis()) { extraAccelerationEnabled = status; emit propertyUpdated(); } else { extraAccelerationEnabled = false; } } void JoyButton::setExtraAccelerationMultiplier(double value) { if (value >= 1.0 && value <= 200.0) { extraAccelerationMultiplier = value; emit propertyUpdated(); } } void JoyButton::setMinAccelThreshold(double value) { if (value >= 1.0 && value <= 100.0 && value <= maxMouseDistanceAccelThreshold) { minMouseDistanceAccelThreshold = value; emit propertyUpdated(); } } double JoyButton::getMinAccelThreshold() { return minMouseDistanceAccelThreshold; } void JoyButton::setMaxAccelThreshold(double value) { if (value >= 1.0 && value <= 100.0 && value >= minMouseDistanceAccelThreshold) { maxMouseDistanceAccelThreshold = value; emit propertyUpdated(); } } double JoyButton::getMaxAccelThreshold() { return maxMouseDistanceAccelThreshold; } void JoyButton::setStartAccelMultiplier(double value) { if (value >= 0.0 && value <= 100.0) { startAccelMultiplier = value; emit propertyUpdated(); } } double JoyButton::getStartAccelMultiplier() { return startAccelMultiplier; } int JoyButton::getSpringModeScreen() { return springModeScreen; } void JoyButton::setSpringModeScreen(int screen) { if (screen >= -1) { springModeScreen = screen; } } void JoyButton::setAccelExtraDuration(double value) { if (value >= 0.0 && value <= 5.0) { accelDuration = value; emit propertyUpdated(); } } double JoyButton::getAccelExtraDuration() { return accelDuration; } bool JoyButton::hasFutureSpringEvents() { bool result = false; QListIterator iter(pendingMouseButtons); while (iter.hasNext()) { JoyButton *temp = iter.next(); if (temp->getMouseMode() == MouseSpring) { result = true; iter.toBack(); } } return result; } void JoyButton::setSpringDeadCircleMultiplier(int value) { if (value >= 0 && value <= 100) { springDeadCircleMultiplier = value; emit propertyUpdated(); } } int JoyButton::getSpringDeadCircleMultiplier() { return springDeadCircleMultiplier; } double JoyButton::getCurrentSpringDeadCircle() { return (springDeadCircleMultiplier * 0.01); } void JoyButton::restartLastMouseTime() { testOldMouseTime.restart(); //lastMouseTime.restart(); } void JoyButton::setStaticMouseThread(QThread *thread) { int oldInterval = staticMouseEventTimer.interval(); if (oldInterval == 0) { oldInterval = IDLEMOUSEREFRESHRATE; } staticMouseEventTimer.moveToThread(thread); mouseHelper.moveToThread(thread); QMetaObject::invokeMethod(&staticMouseEventTimer, "start", Q_ARG(int, oldInterval)); //lastMouseTime.start(); testOldMouseTime.start(); #ifdef Q_OS_WIN repeatHelper.moveToThread(thread); #endif } void JoyButton::indirectStaticMouseThread(QThread *thread) { QMetaObject::invokeMethod(&staticMouseEventTimer, "stop"); #ifdef Q_OS_WIN QMetaObject::invokeMethod(repeatHelper.getRepeatTimer(), "stop"); #endif QMetaObject::invokeMethod(&mouseHelper, "changeThread", Q_ARG(QThread*, thread)); } bool JoyButton::shouldInvokeMouseEvents() { bool result = false; if (pendingMouseButtons.size() > 0 && staticMouseEventTimer.isActive()) { int timerInterval = staticMouseEventTimer.interval(); if (timerInterval == 0) { result = true; } //else if (lastMouseTime.elapsed() >= timerInterval) //else if (lastMouseTime.hasExpired(timerInterval)) else if (testOldMouseTime.elapsed() >= timerInterval) { result = true; } } return result; } void JoyButton::invokeMouseEvents() { mouseHelper.mouseEvent(); } bool JoyButton::hasActiveSlots() { return !activeSlots.isEmpty(); } void JoyButton::setExtraAccelerationCurve(JoyExtraAccelerationCurve curve) { extraAccelCurve = curve; emit propertyUpdated(); } JoyButton::JoyExtraAccelerationCurve JoyButton::getExtraAccelerationCurve() { return extraAccelCurve; } void JoyButton::copyExtraAccelerationState(JoyButton *srcButton) { this->currentAccelMulti = srcButton->currentAccelMulti; this->oldAccelMulti = srcButton->oldAccelMulti; this->accelTravel = srcButton->accelTravel; this->startingAccelerationDistance = srcButton->startingAccelerationDistance; this->lastAccelerationDistance = srcButton->lastAccelerationDistance; this->lastMouseDistance = srcButton->lastMouseDistance; this->accelExtraDurationTime.setHMS(srcButton->accelExtraDurationTime.hour(), srcButton->accelExtraDurationTime.minute(), srcButton->accelExtraDurationTime.second(), srcButton->accelExtraDurationTime.msec()); this->updateOldAccelMulti = srcButton->updateOldAccelMulti; this->updateStartingMouseDistance = srcButton->updateStartingMouseDistance; this->updateLastMouseDistance = srcButton->lastMouseDistance; } void JoyButton::setUpdateInitAccel(bool state) { this->updateInitAccelValues = state; } antimicro-2.23/src/joybutton.h000066400000000000000000000443261300750276700164420ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYBUTTON_H #define JOYBUTTON_H #include #include #include #include #include #include #include #include #include #include #include #include "joybuttonslot.h" #include "springmousemoveinfo.h" #include "joybuttonmousehelper.h" #ifdef Q_OS_WIN #include "joykeyrepeathelper.h" #endif class VDPad; class SetJoystick; class JoyButton : public QObject { Q_OBJECT public: explicit JoyButton(int index, int originset, SetJoystick *parentSet, QObject *parent=0); ~JoyButton(); enum SetChangeCondition {SetChangeDisabled=0, SetChangeOneWay, SetChangeTwoWay, SetChangeWhileHeld}; enum JoyMouseMovementMode {MouseCursor=0, MouseSpring}; enum JoyMouseCurve {EnhancedPrecisionCurve=0, LinearCurve, QuadraticCurve, CubicCurve, QuadraticExtremeCurve, PowerCurve, EasingQuadraticCurve, EasingCubicCurve}; enum JoyExtraAccelerationCurve {LinearAccelCurve, EaseOutSineCurve, EaseOutQuadAccelCurve, EaseOutCubicAccelCurve}; enum TurboMode {NormalTurbo=0, GradientTurbo, PulseTurbo}; void joyEvent(bool pressed, bool ignoresets=false); void queuePendingEvent(bool pressed, bool ignoresets=false); void activatePendingEvent(); bool hasPendingEvent(); void clearPendingEvent(); int getJoyNumber(); virtual int getRealJoyNumber(); void setJoyNumber(int index); bool getToggleState(); int getTurboInterval(); bool isUsingTurbo(); void setCustomName(QString name); QString getCustomName(); QList *getAssignedSlots(); virtual void readConfig(QXmlStreamReader *xml); virtual void writeConfig(QXmlStreamWriter *xml); virtual QString getPartialName(bool forceFullFormat=false, bool displayNames=false); virtual QString getSlotsSummary(); virtual QString getSlotsString(); virtual QList getActiveZoneList(); virtual QString getActiveZoneSummary(); virtual QString getCalculatedActiveZoneSummary(); virtual QString getName(bool forceFullFormat=false, bool displayNames=false); virtual QString getXmlName(); int getMouseSpeedX(); int getMouseSpeedY(); int getWheelSpeedX(); int getWheelSpeedY(); void setChangeSetSelection(int index, bool updateActiveString=true); int getSetSelection(); virtual void setChangeSetCondition(SetChangeCondition condition, bool passive=false, bool updateActiveString=true); SetChangeCondition getChangeSetCondition(); bool getButtonState(); int getOriginSet(); bool containsSequence(); bool containsDistanceSlots(); bool containsReleaseSlots(); virtual double getDistanceFromDeadZone(); virtual double getMouseDistanceFromDeadZone(); virtual double getLastMouseDistanceFromDeadZone(); // Don't use direct assignment but copying from a current button. virtual void copyLastMouseDistanceFromDeadZone(JoyButton *srcButton); virtual void copyLastAccelerationDistance(JoyButton *srcButton); void copyExtraAccelerationState(JoyButton *srcButton); void setUpdateInitAccel(bool state); virtual void setVDPad(VDPad *vdpad); void removeVDPad(); bool isPartVDPad(); VDPad* getVDPad(); virtual bool isDefault(); void setIgnoreEventState(bool ignore); bool getIgnoreEventState(); void setMouseMode(JoyMouseMovementMode mousemode); JoyMouseMovementMode getMouseMode(); void setMouseCurve(JoyMouseCurve selectedCurve); JoyMouseCurve getMouseCurve(); int getSpringWidth(); int getSpringHeight(); double getSensitivity(); bool getWhileHeldStatus(); void setWhileHeldStatus(bool status); QString getActionName(); QString getButtonName(); virtual void setDefaultButtonName(QString tempname); virtual QString getDefaultButtonName(); SetJoystick* getParentSet(); void setCycleResetTime(unsigned int interval); unsigned int getCycleResetTime(); void setCycleResetStatus(bool enabled); bool isCycleResetActive(); bool isRelativeSpring(); void copyAssignments(JoyButton *destButton); virtual void setTurboMode(TurboMode mode); TurboMode getTurboMode(); virtual bool isPartRealAxis(); virtual bool isModifierButton(); bool hasActiveSlots(); static int calculateFinalMouseSpeed(JoyMouseCurve curve, int value); double getEasingDuration(); static void moveMouseCursor(int &movedX, int &movedY, int &movedElapsed); static void moveSpringMouse(int &movedX, int &movedY, bool &hasMoved); static JoyButtonMouseHelper* getMouseHelper(); static QList* getPendingMouseButtons(); static bool hasCursorEvents(); static bool hasSpringEvents(); static double getWeightModifier(); static void setWeightModifier(double modifier); static int getMouseHistorySize(); static void setMouseHistorySize(int size); static int getMouseRefreshRate(); static void setMouseRefreshRate(int refresh); static int getSpringModeScreen(); static void setSpringModeScreen(int screen); static void resetActiveButtonMouseDistances(); void resetAccelerationDistances(); void setExtraAccelerationStatus(bool status); void setExtraAccelerationMultiplier(double value); bool isExtraAccelerationEnabled(); double getExtraAccelerationMultiplier(); virtual void initializeDistanceValues(); void setMinAccelThreshold(double value); double getMinAccelThreshold(); void setMaxAccelThreshold(double value); double getMaxAccelThreshold(); void setStartAccelMultiplier(double value); double getStartAccelMultiplier(); void setAccelExtraDuration(double value); double getAccelExtraDuration(); void setExtraAccelerationCurve(JoyExtraAccelerationCurve curve); JoyExtraAccelerationCurve getExtraAccelerationCurve(); virtual double getAccelerationDistance(); virtual double getLastAccelerationDistance(); void setSpringDeadCircleMultiplier(int value); int getSpringDeadCircleMultiplier(); static int getGamepadRefreshRate(); static void setGamepadRefreshRate(int refresh); static void restartLastMouseTime(); static void setStaticMouseThread(QThread *thread); static void indirectStaticMouseThread(QThread *thread); static bool shouldInvokeMouseEvents(); static void invokeMouseEvents(); static const QString xmlName; // Define default values for many properties. static const int ENABLEDTURBODEFAULT; static const double DEFAULTMOUSESPEEDMOD; static const unsigned int DEFAULTKEYREPEATDELAY; static const unsigned int DEFAULTKEYREPEATRATE; static const JoyMouseCurve DEFAULTMOUSECURVE; static const bool DEFAULTTOGGLE; static const int DEFAULTTURBOINTERVAL; static const bool DEFAULTUSETURBO; static const int DEFAULTMOUSESPEEDX; static const int DEFAULTMOUSESPEEDY; static const int DEFAULTSETSELECTION; static const SetChangeCondition DEFAULTSETCONDITION; static const JoyMouseMovementMode DEFAULTMOUSEMODE; static const int DEFAULTSPRINGWIDTH; static const int DEFAULTSPRINGHEIGHT; static const double DEFAULTSENSITIVITY; static const int DEFAULTWHEELX; static const int DEFAULTWHEELY; static const bool DEFAULTCYCLERESETACTIVE; static const int DEFAULTCYCLERESET; static const bool DEFAULTRELATIVESPRING; static const TurboMode DEFAULTTURBOMODE; static const double DEFAULTEASINGDURATION; static const double MINIMUMEASINGDURATION; static const double MAXIMUMEASINGDURATION; static const int DEFAULTMOUSEHISTORYSIZE; static const double DEFAULTWEIGHTMODIFIER; static const int MAXIMUMMOUSEHISTORYSIZE; static const double MAXIMUMWEIGHTMODIFIER; static const int MAXIMUMMOUSEREFRESHRATE; static const int DEFAULTIDLEMOUSEREFRESHRATE; static int IDLEMOUSEREFRESHRATE; static const unsigned int MINCYCLERESETTIME; static const unsigned int MAXCYCLERESETTIME; static const double DEFAULTEXTRACCELVALUE; static const double DEFAULTMINACCELTHRESHOLD; static const double DEFAULTMAXACCELTHRESHOLD; static const double DEFAULTSTARTACCELMULTIPLIER; static const double DEFAULTACCELEASINGDURATION; static const JoyExtraAccelerationCurve DEFAULTEXTRAACCELCURVE; static const int DEFAULTSPRINGRELEASERADIUS; static QList mouseHistoryX; static QList mouseHistoryY; static double cursorRemainderX; static double cursorRemainderY; protected: double getTotalSlotDistance(JoyButtonSlot *slot); bool distanceEvent(); void clearAssignedSlots(bool signalEmit=true); void releaseSlotEvent(); void findReleaseEventEnd(); void findReleaseEventIterEnd(QListIterator *tempiter); void findHoldEventEnd(); bool checkForDelaySequence(); void checkForPressedSetChange(); bool insertAssignedSlot(JoyButtonSlot *newSlot, bool updateActiveString=true); unsigned int getPreferredKeyPressTime(); void checkTurboCondition(JoyButtonSlot *slot); static bool hasFutureSpringEvents(); virtual double getCurrentSpringDeadCircle(); void vdpadPassEvent(bool pressed, bool ignoresets=false); QString buildActiveZoneSummary(QList &tempList); void localBuildActiveZoneSummaryString(); virtual bool readButtonConfig(QXmlStreamReader *xml); typedef struct _mouseCursorInfo { JoyButtonSlot *slot; double code; } mouseCursorInfo; // Used to denote whether the actual joypad button is pressed bool isButtonPressed; // Used to denote whether the virtual key is pressed bool isKeyPressed; bool toggle; bool quitEvent; // Used to denote the SDL index of the actual joypad button int index; int turboInterval; QTimer turboTimer; QTimer pauseTimer; QTimer holdTimer; QTimer pauseWaitTimer; QTimer createDeskTimer; QTimer releaseDeskTimer; QTimer mouseWheelVerticalEventTimer; QTimer mouseWheelHorizontalEventTimer; QTimer setChangeTimer; QTimer keyPressTimer; QTimer delayTimer; QTimer slotSetChangeTimer; static QTimer staticMouseEventTimer; bool isDown; bool toggleActiveState; bool useTurbo; QList assignments; QList activeSlots; QString customName; int mouseSpeedX; int mouseSpeedY; int wheelSpeedX; int wheelSpeedY; int setSelection; SetChangeCondition setSelectionCondition; int originset; QListIterator *slotiter; JoyButtonSlot *currentPause; JoyButtonSlot *currentHold; JoyButtonSlot *currentCycle; JoyButtonSlot *previousCycle; JoyButtonSlot *currentDistance; JoyButtonSlot *currentMouseEvent; JoyButtonSlot *currentRelease; JoyButtonSlot *currentWheelVerticalEvent; JoyButtonSlot *currentWheelHorizontalEvent; JoyButtonSlot *currentKeyPress; JoyButtonSlot *currentDelay; JoyButtonSlot *currentSetChangeSlot; bool ignoresets; QTime buttonHold; QTime pauseHold; QTime inpauseHold; QTime buttonHeldRelease; QTime keyPressHold; QTime buttonDelay; QTime turboHold; QTime wheelVerticalTime; QTime wheelHorizontalTime; //static QElapsedTimer lastMouseTime; static QTime testOldMouseTime; QQueue ignoreSetQueue; QQueue isButtonPressedQueue; QQueue mouseEventQueue; QQueue mouseWheelVerticalEventQueue; QQueue mouseWheelHorizontalEventQueue; int currentRawValue; VDPad *vdpad; bool ignoreEvents; JoyMouseMovementMode mouseMode; JoyMouseCurve mouseCurve; int springWidth; int springHeight; double sensitivity; bool smoothing; bool whileHeldStatus; double lastDistance; double lastWheelVerticalDistance; double lastWheelHorizontalDistance; int tempTurboInterval; // Keep track of the previous mouse distance from the previous gamepad // poll. double lastMouseDistance; // Keep track of the previous full distance from the previous gamepad // poll. double lastAccelerationDistance; // Multiplier and time used for acceleration easing. double currentAccelMulti; QTime accelExtraDurationTime; double accelDuration; double oldAccelMulti; double accelTravel; // Track travel when accel started // Should lastMouseDistance be updated. Set after mouse event. bool updateLastMouseDistance; // Should startingMouseDistance be updated. Set after acceleration // has finally been applied. bool updateStartingMouseDistance; double updateOldAccelMulti; bool updateInitAccelValues; // Keep track of the current mouse distance after a poll. Used // to update lastMouseDistance later. double currentMouseDistance; // Keep track of the current mouse distance after a poll. Used // to update lastMouseDistance later. double currentAccelerationDistance; // Take into account when mouse acceleration started double startingAccelerationDistance; double minMouseDistanceAccelThreshold; double maxMouseDistanceAccelThreshold; double startAccelMultiplier; JoyExtraAccelerationCurve extraAccelCurve; QString actionName; QString buttonName; // User specified button name QString defaultButtonName; // Name used by the system SetJoystick *parentSet; // Pointer to set that button is assigned to. bool cycleResetActive; unsigned int cycleResetInterval; QTime cycleResetHold; bool relativeSpring; TurboMode currentTurboMode; double easingDuration; bool extraAccelerationEnabled; double extraAccelerationMultiplier; int springDeadCircleMultiplier; bool pendingPress; bool pendingEvent; bool pendingIgnoreSets; QReadWriteLock activeZoneLock; QReadWriteLock assignmentsLock; QReadWriteLock activeZoneStringLock; QString activeZoneString; QTimer activeZoneTimer; static double mouseSpeedModifier; static QList mouseSpeedModList; static QList cursorXSpeeds; static QList cursorYSpeeds; static QList springXSpeeds; static QList springYSpeeds; static QList pendingMouseButtons; static QHash activeKeys; static QHash activeMouseButtons; #ifdef Q_OS_WIN static JoyKeyRepeatHelper repeatHelper; #endif static JoyButtonSlot *lastActiveKey; static JoyButtonMouseHelper mouseHelper; static double weightModifier; static int mouseHistorySize; static int mouseRefreshRate; static int springModeScreen; static int gamepadRefreshRate; signals: void clicked (int index); void released (int index); void keyChanged(int keycode); void mouseChanged(int mousecode); void setChangeActivated(int index); void setAssignmentChanged(int current_button, int associated_set, int mode); void finishedPause(); void turboChanged(bool state); void toggleChanged(bool state); void turboIntervalChanged(int interval); void slotsChanged(); void actionNameChanged(); void buttonNameChanged(); void propertyUpdated(); void activeZoneChanged(); public slots: void setTurboInterval (int interval); void setToggle (bool toggle); void setUseTurbo(bool useTurbo); void setMouseSpeedX(int speed); void setMouseSpeedY(int speed); void setWheelSpeedX(int speed); void setWheelSpeedY(int speed); void setSpringWidth(int value); void setSpringHeight(int value); void setSensitivity(double value); void setSpringRelativeStatus(bool value); void setActionName(QString tempName); void setButtonName(QString tempName); void setEasingDuration(double value); virtual void reset(); virtual void reset(int index); virtual void resetProperties(); virtual void clearSlotsEventReset(bool clearSignalEmit=true); virtual void eventReset(); bool setAssignedSlot(int code, unsigned int alias, int index, JoyButtonSlot::JoySlotInputAction mode=JoyButtonSlot::JoyKeyboard); bool setAssignedSlot(int code, JoyButtonSlot::JoySlotInputAction mode=JoyButtonSlot::JoyKeyboard); bool setAssignedSlot(int code, unsigned int alias, JoyButtonSlot::JoySlotInputAction mode=JoyButtonSlot::JoyKeyboard); bool setAssignedSlot(JoyButtonSlot *otherSlot, int index); bool insertAssignedSlot(int code, unsigned int alias, int index, JoyButtonSlot::JoySlotInputAction mode=JoyButtonSlot::JoyKeyboard); void removeAssignedSlot(int index); static void establishMouseTimerConnections(); void establishPropertyUpdatedConnections(); void disconnectPropertyUpdatedConnections(); virtual void mouseEvent(); protected slots: virtual void turboEvent(); virtual void wheelEventVertical(); virtual void wheelEventHorizontal(); void createDeskEvent(); void releaseDeskEvent(bool skipsetchange=false); void buildActiveZoneSummaryString(); private slots: void releaseActiveSlots(); void activateSlots(); void waitForDeskEvent(); void waitForReleaseDeskEvent(); void holdEvent(); void delayEvent(); void pauseWaitEvent(); void checkForSetChange(); void keyPressEvent(); void slotSetChange(); }; #endif // JOYBUTTON_H antimicro-2.23/src/joybuttoncontextmenu.cpp000066400000000000000000000131211300750276700212540ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include "joybuttoncontextmenu.h" #include "inputdevice.h" #include "common.h" JoyButtonContextMenu::JoyButtonContextMenu(JoyButton *button, QWidget *parent) : QMenu(parent) { this->button = button; connect(this, SIGNAL(aboutToHide()), this, SLOT(deleteLater())); } void JoyButtonContextMenu::buildMenu() { QAction *action = 0; PadderCommon::inputDaemonMutex.lock(); action = this->addAction(tr("Toggle")); action->setCheckable(true); action->setChecked(button->getToggleState()); connect(action, SIGNAL(triggered()), this, SLOT(switchToggle())); action = this->addAction(tr("Turbo")); action->setCheckable(true); action->setChecked(button->isUsingTurbo()); connect(action, SIGNAL(triggered()), this, SLOT(switchToggle())); this->addSeparator(); action = this->addAction(tr("Clear")); action->setCheckable(false); connect(action, SIGNAL(triggered()), this, SLOT(clearButton())); this->addSeparator(); QMenu *setSectionMenu = this->addMenu(tr("Set Select")); action = setSectionMenu->addAction(tr("Disabled")); if (button->getChangeSetCondition() == JoyButton::SetChangeDisabled) { action->setCheckable(true); action->setChecked(true); } connect(action, SIGNAL(triggered()), this, SLOT(disableSetMode())); setSectionMenu->addSeparator(); for (int i=0; i < InputDevice::NUMBER_JOYSETS; i++) { QMenu *tempSetMenu = setSectionMenu->addMenu(tr("Set %1").arg(i+1)); int setSelection = i*3; if (i == button->getSetSelection()) { QFont tempFont = tempSetMenu->menuAction()->font(); tempFont.setBold(true); tempSetMenu->menuAction()->setFont(tempFont); } QActionGroup *tempGroup = new QActionGroup(tempSetMenu); action = tempSetMenu->addAction(tr("Set %1 1W").arg(i+1)); action->setData(QVariant(setSelection + 0)); action->setCheckable(true); if (button->getSetSelection() == i && button->getChangeSetCondition() == JoyButton::SetChangeOneWay) { action->setChecked(true); } connect(action, SIGNAL(triggered()), this, SLOT(switchSetMode())); tempGroup->addAction(action); action = tempSetMenu->addAction(tr("Set %1 2W").arg(i+1)); action->setData(QVariant(setSelection + 1)); action->setCheckable(true); if (button->getSetSelection() == i && button->getChangeSetCondition() == JoyButton::SetChangeTwoWay) { action->setChecked(true); } connect(action, SIGNAL(triggered()), this, SLOT(switchSetMode())); tempGroup->addAction(action); action = tempSetMenu->addAction(tr("Set %1 WH").arg(i+1)); action->setData(QVariant(setSelection + 2)); action->setCheckable(true); if (button->getSetSelection() == i && button->getChangeSetCondition() == JoyButton::SetChangeWhileHeld) { action->setChecked(true); } connect(action, SIGNAL(triggered()), this, SLOT(switchSetMode())); tempGroup->addAction(action); if (i == button->getParentSet()->getIndex()) { tempSetMenu->setEnabled(false); } } PadderCommon::inputDaemonMutex.unlock(); } void JoyButtonContextMenu::switchToggle() { PadderCommon::inputDaemonMutex.lock(); button->setToggle(!button->getToggleState()); PadderCommon::inputDaemonMutex.unlock(); } void JoyButtonContextMenu::switchTurbo() { PadderCommon::inputDaemonMutex.lock(); button->setToggle(!button->isUsingTurbo()); PadderCommon::inputDaemonMutex.unlock(); } void JoyButtonContextMenu::switchSetMode() { QAction *action = static_cast(sender()); int item = action->data().toInt(); int setSelection = item / 3; int setChangeCondition = item % 3; JoyButton::SetChangeCondition temp; if (setChangeCondition == 0) { temp = JoyButton::SetChangeOneWay; } else if (setChangeCondition == 1) { temp = JoyButton::SetChangeTwoWay; } else if (setChangeCondition == 2) { temp = JoyButton::SetChangeWhileHeld; } PadderCommon::inputDaemonMutex.lock(); // First, remove old condition for the button in both sets. // After that, make the new assignment. button->setChangeSetCondition(JoyButton::SetChangeDisabled); button->setChangeSetSelection(setSelection); button->setChangeSetCondition(temp); PadderCommon::inputDaemonMutex.unlock(); } void JoyButtonContextMenu::disableSetMode() { PadderCommon::inputDaemonMutex.lock(); button->setChangeSetCondition(JoyButton::SetChangeDisabled); PadderCommon::inputDaemonMutex.unlock(); } void JoyButtonContextMenu::clearButton() { QMetaObject::invokeMethod(button, "clearSlotsEventReset"); } antimicro-2.23/src/joybuttoncontextmenu.h000066400000000000000000000023361300750276700207270ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYBUTTONCONTEXTMENU_H #define JOYBUTTONCONTEXTMENU_H #include #include "joybutton.h" class JoyButtonContextMenu : public QMenu { Q_OBJECT public: explicit JoyButtonContextMenu(JoyButton *button, QWidget *parent = 0); void buildMenu(); protected: JoyButton *button; signals: private slots: void switchToggle(); void switchTurbo(); void switchSetMode(); void disableSetMode(); void clearButton(); }; #endif // JOYBUTTONCONTEXTMENU_H antimicro-2.23/src/joybuttonmousehelper.cpp000066400000000000000000000060231300750276700212360ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include "joybutton.h" #include "joybuttonmousehelper.h" JoyButtonMouseHelper::JoyButtonMouseHelper(QObject *parent) : QObject(parent) { firstSpringEvent = false; } /** * @brief Perform mouse movement in cursor mode. */ void JoyButtonMouseHelper::moveMouseCursor() { int finalx = 0; int finaly = 0; int elapsedTime = 5; JoyButton::moveMouseCursor(finalx, finaly, elapsedTime); if (finalx != 0 || finaly != 0) { emit mouseCursorMoved(finalx, finaly, elapsedTime); } } /** * @brief Perform mouse movement in spring mode. */ void JoyButtonMouseHelper::moveSpringMouse() { int finalx = 0; int finaly = 0; bool hasMoved = false; JoyButton::moveSpringMouse(finalx, finaly, hasMoved); if (hasMoved) { emit mouseSpringMoved(finalx, finaly); } } /** * @brief Perform mouse events for all buttons and slots. */ void JoyButtonMouseHelper::mouseEvent() { if (!JoyButton::hasCursorEvents() && !JoyButton::hasSpringEvents()) { QList *buttonList = JoyButton::getPendingMouseButtons(); QListIterator iter(*buttonList); while (iter.hasNext()) { JoyButton *temp = iter.next(); temp->mouseEvent(); } } moveMouseCursor(); if (JoyButton::hasSpringEvents()) { moveSpringMouse(); } JoyButton::restartLastMouseTime(); firstSpringEvent = false; } void JoyButtonMouseHelper::resetButtonMouseDistances() { QList *buttonList = JoyButton::getPendingMouseButtons(); QListIterator iter(*buttonList); while (iter.hasNext()) { JoyButton *temp = iter.next(); temp->resetAccelerationDistances(); } } void JoyButtonMouseHelper::setFirstSpringStatus(bool status) { firstSpringEvent = status; } bool JoyButtonMouseHelper::getFirstSpringStatus() { return firstSpringEvent; } void JoyButtonMouseHelper::carryGamePollRateUpdate(unsigned int pollRate) { emit gamepadRefreshRateUpdated(pollRate); } void JoyButtonMouseHelper::carryMouseRefreshRateUpdate(unsigned int refreshRate) { emit mouseRefreshRateUpdated(refreshRate); } void JoyButtonMouseHelper::changeThread(QThread *thread) { JoyButton::setStaticMouseThread(thread); } antimicro-2.23/src/joybuttonmousehelper.h000066400000000000000000000032071300750276700207040ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYBUTTONMOUSEHELPER_H #define JOYBUTTONMOUSEHELPER_H #include #include class JoyButtonMouseHelper : public QObject { Q_OBJECT public: explicit JoyButtonMouseHelper(QObject *parent = 0); void resetButtonMouseDistances(); void setFirstSpringStatus(bool status); bool getFirstSpringStatus(); void carryGamePollRateUpdate(unsigned int pollRate); void carryMouseRefreshRateUpdate(unsigned int refreshRate); protected: bool firstSpringEvent; signals: void mouseCursorMoved(int mouseX, int mouseY, int elapsed); void mouseSpringMoved(int mouseX, int mouseY); void gamepadRefreshRateUpdated(unsigned int pollRate); void mouseRefreshRateUpdated(unsigned int refreshRate); public slots: void moveMouseCursor(); void moveSpringMouse(); void mouseEvent(); void changeThread(QThread *thread); }; #endif // JOYBUTTONMOUSEHELPER_H antimicro-2.23/src/joybuttonslot.cpp000066400000000000000000000511051300750276700176700ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include "inputdevice.h" #include "joybuttonslot.h" #include "antkeymapper.h" #include "event.h" const int JoyButtonSlot::JOYSPEED = 20; const QString JoyButtonSlot::xmlName = "slot"; const int JoyButtonSlot::MAXTEXTENTRYDISPLAYLENGTH = 40; JoyButtonSlot::JoyButtonSlot(QObject *parent) : QObject(parent), extraData() { deviceCode = 0; mode = JoyKeyboard; distance = 0.0; previousDistance = 0.0; qkeyaliasCode = 0; easingActive = false; } JoyButtonSlot::JoyButtonSlot(int code, JoySlotInputAction mode, QObject *parent) : QObject(parent), extraData() { deviceCode = 0; qkeyaliasCode = 0; if (code > 0) { deviceCode = code; } this->mode = mode; distance = 0.0; easingActive = false; } JoyButtonSlot::JoyButtonSlot(int code, unsigned int alias, JoySlotInputAction mode, QObject *parent) : QObject(parent), extraData() { deviceCode = 0; qkeyaliasCode = 0; if (code > 0) { deviceCode = code; } if (alias > 0) { qkeyaliasCode = alias; } this->mode = mode; distance = 0.0; easingActive = false; } JoyButtonSlot::JoyButtonSlot(JoyButtonSlot *slot, QObject *parent) : QObject(parent), extraData() { deviceCode = slot->deviceCode; qkeyaliasCode = slot->qkeyaliasCode; mode = slot->mode; distance = slot->distance; easingActive = false; textData = slot->getTextData(); extraData = slot->getExtraData(); } JoyButtonSlot::JoyButtonSlot(QString text, JoySlotInputAction mode, QObject *parent) : QObject(parent), extraData() { deviceCode = 0; qkeyaliasCode = 0; this->mode = mode; distance = 0.0; easingActive = false; if (mode == JoyLoadProfile || mode == JoyTextEntry || mode == JoyExecute) { textData = text; } } void JoyButtonSlot::setSlotCode(int code) { if (code >= 0) { deviceCode = code; qkeyaliasCode = 0; } } void JoyButtonSlot::setSlotCode(int code, unsigned int alias) { if (mode == JoyButtonSlot::JoyKeyboard && code > 0) { deviceCode = code; qkeyaliasCode = alias; } else if (code >= 0) { deviceCode = code; qkeyaliasCode = 0; } } unsigned int JoyButtonSlot::getSlotCodeAlias() { return qkeyaliasCode; } int JoyButtonSlot::getSlotCode() { return deviceCode; } void JoyButtonSlot::setSlotMode(JoySlotInputAction selectedMode) { mode = selectedMode; } JoyButtonSlot::JoySlotInputAction JoyButtonSlot::getSlotMode() { return mode; } QString JoyButtonSlot::movementString() { QString newlabel; if (mode == JoyMouseMovement) { newlabel.append(tr("Mouse")).append(" "); if (deviceCode == JoyButtonSlot::MouseUp) { newlabel.append(tr("Up")); } else if (deviceCode == JoyButtonSlot::MouseDown) { newlabel.append(tr("Down")); } else if (deviceCode == JoyButtonSlot::MouseLeft) { newlabel.append(tr("Left")); } else if (deviceCode == JoyButtonSlot::MouseRight) { newlabel.append(tr("Right")); } } return newlabel; } void JoyButtonSlot::setDistance(double distance) { this->distance = distance; } double JoyButtonSlot::getMouseDistance() { return distance; } QElapsedTimer* JoyButtonSlot::getMouseInterval() { return &mouseInterval; } void JoyButtonSlot::restartMouseInterval() { mouseInterval.restart(); } void JoyButtonSlot::readConfig(QXmlStreamReader *xml) { if (xml->isStartElement() && xml->name() == "slot") { QString profile; QString tempStringData; QString extraStringData; xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "slot")) { if (xml->name() == "code" && xml->isStartElement()) { QString temptext = xml->readElementText(); bool ok = false; unsigned int tempchoice = temptext.toInt(&ok, 0); if (ok) { this->setSlotCode(tempchoice); } } else if (xml->name() == "profile" && xml->isStartElement()) { QString temptext = xml->readElementText(); profile = temptext; } else if (xml->name() == "text" && xml->isStartElement()) { QString temptext = xml->readElementText(); tempStringData = temptext; } else if (xml->name() == "path" && xml->isStartElement()) { QString temptext = xml->readElementText(); tempStringData = temptext; } else if (xml->name() == "arguments" && xml->isStartElement()) { QString temptext = xml->readElementText(); extraStringData = temptext; } else if (xml->name() == "mode" && xml->isStartElement()) { QString temptext = xml->readElementText(); if (temptext == "keyboard") { this->setSlotMode(JoyKeyboard); } else if (temptext == "mousebutton") { this->setSlotMode(JoyMouseButton); } else if (temptext == "mousemovement") { this->setSlotMode(JoyMouseMovement); } else if (temptext == "pause") { this->setSlotMode(JoyPause); } else if (temptext == "hold") { this->setSlotMode(JoyHold); } else if (temptext == "cycle") { this->setSlotMode(JoyCycle); } else if (temptext == "distance") { this->setSlotMode(JoyDistance); } else if (temptext == "release") { this->setSlotMode(JoyRelease); } else if (temptext == "mousespeedmod") { this->setSlotMode(JoyMouseSpeedMod); } else if (temptext == "keypress") { this->setSlotMode(JoyKeyPress); } else if (temptext == "delay") { this->setSlotMode(JoyDelay); } else if (temptext == "loadprofile") { this->setSlotMode(JoyLoadProfile); } else if (temptext == "setchange") { this->setSlotMode(JoySetChange); } else if (temptext == "textentry") { this->setSlotMode(JoyTextEntry); } else if (temptext == "execute") { this->setSlotMode(JoyExecute); } } else { xml->skipCurrentElement(); } xml->readNextStartElement(); } if (this->getSlotMode() == JoyButtonSlot::JoyKeyboard) { unsigned int virtualkey = AntKeyMapper::getInstance()->returnVirtualKey(this->getSlotCode()); unsigned int tempkey = this->getSlotCode(); if (virtualkey) { // Mapping found a valid native keysym. this->setSlotCode(virtualkey, tempkey); } else if ((unsigned int)this->getSlotCode() > QtKeyMapperBase::nativeKeyPrefix) { // Value is in the native key range. Remove prefix and use // new value as a native keysym. unsigned int temp = this->getSlotCode() - QtKeyMapperBase::nativeKeyPrefix; this->setSlotCode(temp); } } else if (this->getSlotMode() == JoyButtonSlot::JoyLoadProfile && !profile.isEmpty()) { QFileInfo profileInfo(profile); if (!profileInfo.exists() || !(profileInfo.suffix() == "amgp" || profileInfo.suffix() == "xml")) { this->setTextData(""); } else { this->setTextData(profile); } } else if (this->getSlotMode() == JoySetChange) { if (!this->getSlotCode() >= 0 && !this->getSlotCode() < InputDevice::NUMBER_JOYSETS) { this->setSlotCode(-1); } } else if (this->getSlotMode() == JoyTextEntry && !tempStringData.isEmpty()) { this->setTextData(tempStringData); } else if (this->getSlotMode() == JoyExecute && !tempStringData.isEmpty()) { QFileInfo tempFile(tempStringData); if (tempFile.exists() && tempFile.isExecutable()) { this->setTextData(tempStringData); if (!extraStringData.isEmpty()) { this->setExtraData(QVariant(extraStringData)); } } } } } void JoyButtonSlot::writeConfig(QXmlStreamWriter *xml) { xml->writeStartElement(getXmlName()); if (mode == JoyKeyboard) { unsigned int basekey = AntKeyMapper::getInstance()->returnQtKey(deviceCode); unsigned int qtkey = this->getSlotCodeAlias(); if (qtkey > 0 || basekey > 0) { // Did not add an alias to slot. If a possible Qt key value // was found, use it. if (qtkey == 0 && basekey > 0) { qtkey = basekey; } // Found a valid abstract keysym. //qDebug() << "ANT KEY: " << QString::number(qtkey, 16); xml->writeTextElement("code", QString("0x%1").arg(qtkey, 0, 16)); } else if (deviceCode > 0) { // No abstraction provided for key. Add prefix to native keysym. unsigned int tempkey = deviceCode | QtKeyMapperBase::nativeKeyPrefix; //qDebug() << "ANT KEY: " << QString::number(tempkey, 16); xml->writeTextElement("code", QString("0x%1").arg(tempkey, 0, 16)); } } else if (mode == JoyLoadProfile && !textData.isEmpty()) { xml->writeTextElement("profile", textData); } else if (mode == JoyTextEntry && !textData.isEmpty()) { xml->writeTextElement("text", textData); } else if (mode == JoyExecute && !textData.isEmpty()) { xml->writeTextElement("path", textData); if (!extraData.isNull() && extraData.canConvert()) { xml->writeTextElement("arguments", extraData.toString()); } } else { xml->writeTextElement("code", QString::number(deviceCode)); } xml->writeStartElement("mode"); if (mode == JoyKeyboard) { xml->writeCharacters("keyboard"); } else if (mode == JoyMouseButton) { xml->writeCharacters("mousebutton"); } else if (mode == JoyMouseMovement) { xml->writeCharacters("mousemovement"); } else if (mode == JoyPause) { xml->writeCharacters("pause"); } else if (mode == JoyHold) { xml->writeCharacters("hold"); } else if (mode == JoyCycle) { xml->writeCharacters("cycle"); } else if (mode == JoyDistance) { xml->writeCharacters("distance"); } else if (mode == JoyRelease) { xml->writeCharacters("release"); } else if (mode == JoyMouseSpeedMod) { xml->writeCharacters("mousespeedmod"); } else if (mode == JoyKeyPress) { xml->writeCharacters("keypress"); } else if (mode == JoyDelay) { xml->writeCharacters("delay"); } else if (mode == JoyLoadProfile) { xml->writeCharacters("loadprofile"); } else if (mode == JoySetChange) { xml->writeCharacters("setchange"); } else if (mode == JoyTextEntry) { xml->writeCharacters("textentry"); } else if (mode == JoyExecute) { xml->writeCharacters("execute"); } xml->writeEndElement(); xml->writeEndElement(); } QString JoyButtonSlot::getXmlName() { return this->xmlName; } QString JoyButtonSlot::getSlotString() { QString newlabel; if (deviceCode >= 0) { if (mode == JoyButtonSlot::JoyKeyboard) { unsigned int tempDeviceCode = deviceCode; #ifdef Q_OS_WIN QtKeyMapperBase *nativeWinKeyMapper = AntKeyMapper::getInstance()->getNativeKeyMapper(); if (nativeWinKeyMapper) { tempDeviceCode = nativeWinKeyMapper->returnVirtualKey(qkeyaliasCode); } #endif newlabel = newlabel.append(keysymToKeyString(tempDeviceCode, qkeyaliasCode).toUpper()); } else if (mode == JoyButtonSlot::JoyMouseButton) { newlabel.append(tr("Mouse")).append(" "); switch (deviceCode) { case 1: newlabel.append(tr("LB")); break; case 2: newlabel.append(tr("MB")); break; case 3: newlabel.append(tr("RB")); break; #ifdef Q_OS_WIN case 8: newlabel.append(tr("B4")); break; case 9: newlabel.append(tr("B5")); break; #endif default: newlabel.append(QString::number(deviceCode)); break; } } else if (mode == JoyMouseMovement) { newlabel.append(movementString()); } else if (mode == JoyPause) { int minutes = deviceCode / 1000 / 60; int seconds = (deviceCode / 1000 % 60); int hundredths = deviceCode % 1000 / 10; newlabel.append(tr("Pause")).append(" "); if (minutes > 0) { newlabel.append(QString("%1:").arg(minutes, 2, 10, QChar('0'))); } newlabel.append(QString("%1.%2") .arg(seconds, 2, 10, QChar('0')) .arg(hundredths, 2, 10, QChar('0'))); } else if (mode == JoyHold) { int minutes = deviceCode / 1000 / 60; int seconds = (deviceCode / 1000 % 60); int hundredths = deviceCode % 1000 / 10; newlabel.append(tr("Hold")).append(" "); if (minutes > 0) { newlabel.append(QString("%1:").arg(minutes, 2, 10, QChar('0'))); } newlabel.append(QString("%1.%2") .arg(seconds, 2, 10, QChar('0')) .arg(hundredths, 2, 10, QChar('0'))); } else if (mode == JoyButtonSlot::JoyCycle) { newlabel.append(tr("Cycle")); } else if (mode == JoyDistance) { QString temp(tr("Distance")); temp.append(" ").append(QString::number(deviceCode).append("%")); newlabel.append(temp); } else if (mode == JoyRelease) { int minutes = deviceCode / 1000 / 60; int seconds = (deviceCode / 1000 % 60); int hundredths = deviceCode % 1000 / 10; newlabel.append(tr("Release")).append(" "); if (minutes > 0) { newlabel.append(QString("%1:").arg(minutes, 2, 10, QChar('0'))); } newlabel.append(QString("%1.%2") .arg(seconds, 2, 10, QChar('0')) .arg(hundredths, 2, 10, QChar('0'))); } else if (mode == JoyMouseSpeedMod) { QString temp; temp.append(tr("Mouse Mod")).append(" "); temp.append(QString::number(deviceCode).append("%")); newlabel.append(temp); } else if (mode == JoyKeyPress) { int minutes = deviceCode / 1000 / 60; int seconds = (deviceCode / 1000 % 60); int hundredths = deviceCode % 1000 / 10; QString temp; temp.append(tr("Press Time")).append(" "); if (minutes > 0) { temp.append(QString("%1:").arg(minutes, 2, 10, QChar('0'))); } temp.append(QString("%1.%2") .arg(seconds, 2, 10, QChar('0')) .arg(hundredths, 2, 10, QChar('0'))); newlabel.append(temp); } else if (mode == JoyDelay) { int minutes = deviceCode / 1000 / 60; int seconds = (deviceCode / 1000 % 60); int hundredths = deviceCode % 1000 / 10; QString temp; temp.append(tr("Delay")).append(" "); if (minutes > 0) { temp.append(QString("%1:").arg(minutes, 2, 10, QChar('0'))); } temp.append(QString("%1.%2") .arg(seconds, 2, 10, QChar('0')) .arg(hundredths, 2, 10, QChar('0'))); newlabel.append(temp); } else if (mode == JoyLoadProfile) { if (!textData.isEmpty()) { QFileInfo profileInfo(textData); QString temp; temp.append(tr("Load %1").arg(PadderCommon::getProfileName(profileInfo))); newlabel.append(temp); } } else if (mode == JoySetChange) { newlabel.append(tr("Set Change %1").arg(deviceCode+1)); } else if (mode == JoyTextEntry) { QString temp = textData; if (temp.length() > MAXTEXTENTRYDISPLAYLENGTH) { temp.truncate(MAXTEXTENTRYDISPLAYLENGTH - 3); temp.append("..."); } newlabel.append(tr("[Text] %1").arg(temp)); } else if (mode == JoyExecute) { QString temp; if (!textData.isEmpty()) { QFileInfo tempFileInfo(textData); temp.append(tempFileInfo.fileName()); } newlabel.append(tr("[Exec] %1").arg(temp)); } } else { newlabel = newlabel.append(tr("[NO KEY]")); } return newlabel; } void JoyButtonSlot::setPreviousDistance(double distance) { previousDistance = distance; } double JoyButtonSlot::getPreviousDistance() { return previousDistance; } bool JoyButtonSlot::isModifierKey() { bool modifier = false; if (mode == JoyKeyboard && AntKeyMapper::getInstance()->isModifierKey(qkeyaliasCode)) { modifier = true; } return modifier; } bool JoyButtonSlot::isEasingActive() { return easingActive; } void JoyButtonSlot::setEasingStatus(bool isActive) { easingActive = isActive; } QTime* JoyButtonSlot::getEasingTime() { return &easingTime; } void JoyButtonSlot::setTextData(QString textData) { this->textData = textData; } QString JoyButtonSlot::getTextData() { return textData; } void JoyButtonSlot::setExtraData(QVariant data) { this->extraData = data; } QVariant JoyButtonSlot::getExtraData() { return extraData; } bool JoyButtonSlot::isValidSlot() { bool result = true; switch (mode) { case JoyLoadProfile: case JoyTextEntry: case JoyExecute: { if (textData.isEmpty()) { result = false; } break; } case JoySetChange: { if (deviceCode < 0) { result = false; } break; } } return result; } antimicro-2.23/src/joybuttonslot.h000066400000000000000000000066771300750276700173530ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYBUTTONSLOT_H #define JOYBUTTONSLOT_H #include #include #include #include #include #include #include class JoyButtonSlot : public QObject { Q_OBJECT public: enum JoySlotInputAction {JoyKeyboard=0, JoyMouseButton, JoyMouseMovement, JoyPause, JoyHold, JoyCycle, JoyDistance, JoyRelease, JoyMouseSpeedMod, JoyKeyPress, JoyDelay, JoyLoadProfile, JoySetChange, JoyTextEntry, JoyExecute}; enum JoySlotMouseDirection {MouseUp=1, MouseDown, MouseLeft, MouseRight}; enum JoySlotMouseWheelButton {MouseWheelUp=4, MouseWheelDown=5, MouseWheelLeft=6, MouseWheelRight=7}; enum JoySlotMouseButton {MouseLB=1, MouseMB, MouseRB}; explicit JoyButtonSlot(QObject *parent = 0); explicit JoyButtonSlot(int code, JoySlotInputAction mode, QObject *parent=0); explicit JoyButtonSlot(int code, unsigned int alias, JoySlotInputAction mode, QObject *parent=0); explicit JoyButtonSlot(JoyButtonSlot *slot, QObject *parent=0); explicit JoyButtonSlot(QString text, JoySlotInputAction mode, QObject *parent=0); void setSlotCode(int code); int getSlotCode(); void setSlotMode(JoySlotInputAction selectedMode); JoySlotInputAction getSlotMode(); QString movementString(); void setMouseSpeed(int value); void setDistance(double distance); double getMouseDistance(); QElapsedTimer* getMouseInterval(); void restartMouseInterval(); QString getXmlName(); QString getSlotString(); void setSlotCode(int code, unsigned int alias); unsigned int getSlotCodeAlias(); void setPreviousDistance(double distance); double getPreviousDistance(); bool isModifierKey(); bool isEasingActive(); void setEasingStatus(bool isActive); QTime* getEasingTime(); void setTextData(QString textData); QString getTextData(); void setExtraData(QVariant data); QVariant getExtraData(); bool isValidSlot(); virtual void readConfig(QXmlStreamReader *xml); virtual void writeConfig(QXmlStreamWriter *xml); static const int JOYSPEED; static const QString xmlName; protected: int deviceCode; unsigned int qkeyaliasCode; JoySlotInputAction mode; double distance; double previousDistance; QElapsedTimer mouseInterval; QTime easingTime; bool easingActive; QString textData; QVariant extraData; static const int MAXTEXTENTRYDISPLAYLENGTH; signals: public slots: }; Q_DECLARE_METATYPE(JoyButtonSlot*) Q_DECLARE_METATYPE(JoyButtonSlot::JoySlotInputAction) #endif // JOYBUTTONSLOT_H antimicro-2.23/src/joybuttonstatusbox.cpp000066400000000000000000000031261300750276700207430ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "joybuttonstatusbox.h" JoyButtonStatusBox::JoyButtonStatusBox(JoyButton *button, QWidget *parent) : QPushButton(parent) { this->button = button; isflashing = false; setText(QString::number(button->getRealJoyNumber())); connect(button, SIGNAL(clicked(int)), this, SLOT(flash())); connect(button, SIGNAL(released(int)), this, SLOT(unflash())); } JoyButton* JoyButtonStatusBox::getJoyButton() { return button; } bool JoyButtonStatusBox::isButtonFlashing() { return isflashing; } void JoyButtonStatusBox::flash() { isflashing = true; this->style()->unpolish(this); this->style()->polish(this); emit flashed(isflashing); } void JoyButtonStatusBox::unflash() { isflashing = false; this->style()->unpolish(this); this->style()->polish(this); emit flashed(isflashing); } antimicro-2.23/src/joybuttonstatusbox.h000066400000000000000000000024341300750276700204110ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYBUTTONSTATUSBOX_H #define JOYBUTTONSTATUSBOX_H #include #include "joybutton.h" class JoyButtonStatusBox : public QPushButton { Q_OBJECT Q_PROPERTY(bool isflashing READ isButtonFlashing) public: explicit JoyButtonStatusBox(JoyButton *button, QWidget *parent = 0); JoyButton* getJoyButton(); bool isButtonFlashing(); protected: JoyButton *button; bool isflashing; signals: void flashed(bool flashing); private slots: void flash(); void unflash(); }; #endif // JOYBUTTONSTATUSBOX_H antimicro-2.23/src/joybuttontypes/000077500000000000000000000000001300750276700173455ustar00rootroot00000000000000antimicro-2.23/src/joybuttontypes/joyaxisbutton.cpp000066400000000000000000000123531300750276700227770ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include "joyaxisbutton.h" #include "joyaxis.h" #include "event.h" const QString JoyAxisButton::xmlName = "axisbutton"; JoyAxisButton::JoyAxisButton(JoyAxis *axis, int index, int originset, SetJoystick *parentSet, QObject *parent) : JoyGradientButton(index, originset, parentSet, parent) { this->axis = axis; } QString JoyAxisButton::getPartialName(bool forceFullFormat, bool displayNames) { QString temp = QString(axis->getPartialName(forceFullFormat, displayNames)); temp.append(": "); if (!buttonName.isEmpty() && displayNames) { if (forceFullFormat) { temp.append(tr("Button")).append(" "); } temp.append(buttonName); } else if (!defaultButtonName.isEmpty() && displayNames) { if (forceFullFormat) { temp.append(tr("Button")).append(" "); } temp.append(defaultButtonName); } else { QString buttontype; if (index == 0) { buttontype = tr("Negative"); } else if (index == 1) { buttontype = tr("Positive"); } else { buttontype = tr("Unknown"); } temp.append(tr("Button")).append(" ").append(buttontype); } return temp; } QString JoyAxisButton::getXmlName() { return this->xmlName; } void JoyAxisButton::setChangeSetCondition(SetChangeCondition condition, bool passive, bool updateActiveString) { SetChangeCondition oldCondition = setSelectionCondition; if (condition != setSelectionCondition && !passive) { if (condition == SetChangeWhileHeld || condition == SetChangeTwoWay) { // Set new condition emit setAssignmentChanged(index, this->axis->getIndex(), setSelection, condition); } else if (setSelectionCondition == SetChangeWhileHeld || setSelectionCondition == SetChangeTwoWay) { // Remove old condition emit setAssignmentChanged(index, this->axis->getIndex(), setSelection, SetChangeDisabled); } setSelectionCondition = condition; } else if (passive) { setSelectionCondition = condition; } if (setSelectionCondition == SetChangeDisabled) { setChangeSetSelection(-1); } if (setSelectionCondition != oldCondition) { if (updateActiveString) { buildActiveZoneSummaryString(); } emit propertyUpdated(); } } /** * @brief Get the distance that an element is away from its assigned * dead zone * @return Normalized distance away from dead zone */ double JoyAxisButton::getDistanceFromDeadZone() { return axis->getDistanceFromDeadZone(); } /** * @brief Get the distance factor that should be used for mouse movement * @return Distance factor that should be used for mouse movement */ double JoyAxisButton::getMouseDistanceFromDeadZone() { return this->getDistanceFromDeadZone(); } void JoyAxisButton::setVDPad(VDPad *vdpad) { if (axis->isPartControlStick()) { axis->removeControlStick(); } JoyButton::setVDPad(vdpad); } JoyAxis* JoyAxisButton::getAxis() { return this->axis; } /** * @brief Set the turbo mode that the button should use * @param Mode that should be used */ void JoyAxisButton::setTurboMode(TurboMode mode) { if (isPartRealAxis()) { currentTurboMode = mode; } } /** * @brief Check if button should be considered a part of a real controller * axis. Needed for some dialogs so the program won't have to resort to * type checking. * @return Status of being part of a real controller axis */ bool JoyAxisButton::isPartRealAxis() { return true; } double JoyAxisButton::getAccelerationDistance() { double distance = 0.0; distance = axis->getRawDistance(axis->getCurrentThrottledValue()); return distance; } double JoyAxisButton::getLastAccelerationDistance() { double distance = 0.0; distance = axis->getRawDistance(axis->getLastKnownThrottleValue()); /*if (axis->getAxisButtonByValue(axis->getLastKnownThrottleValue()) == this) { distance = axis->getRawDistance(axis->getLastKnownThrottleValue()); } */ return distance; } double JoyAxisButton::getLastMouseDistanceFromDeadZone() { double distance = 0.0; if (axis->getAxisButtonByValue(axis->getLastKnownThrottleValue()) == this) { distance = axis->getDistanceFromDeadZone(axis->getLastKnownThrottleValue()); } return distance; } antimicro-2.23/src/joybuttontypes/joyaxisbutton.h000066400000000000000000000036431300750276700224460ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYAXISBUTTON_H #define JOYAXISBUTTON_H #include #include "joybuttontypes/joygradientbutton.h" class JoyAxis; class JoyAxisButton : public JoyGradientButton { Q_OBJECT public: explicit JoyAxisButton(JoyAxis *axis, int index, int originset, SetJoystick *parentSet, QObject *parent=0); virtual QString getPartialName(bool forceFullFormat=false, bool displayNames=false); virtual QString getXmlName(); virtual double getDistanceFromDeadZone(); virtual double getMouseDistanceFromDeadZone(); virtual double getLastMouseDistanceFromDeadZone(); virtual void setChangeSetCondition(SetChangeCondition condition, bool passive=false, bool updateActiveString=true); JoyAxis* getAxis(); virtual void setVDPad(VDPad *vdpad); virtual void setTurboMode(TurboMode mode); virtual bool isPartRealAxis(); virtual double getAccelerationDistance(); virtual double getLastAccelerationDistance(); static const QString xmlName; protected: JoyAxis *axis; signals: void setAssignmentChanged(int current_button, int axis_index, int associated_set, int mode); }; #endif // JOYAXISBUTTON_H antimicro-2.23/src/joybuttontypes/joycontrolstickbutton.cpp000066400000000000000000000176661300750276700245650ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include "joycontrolstickbutton.h" #include "joycontrolstick.h" #include "event.h" const QString JoyControlStickButton::xmlName = "stickbutton"; JoyControlStickButton::JoyControlStickButton(JoyControlStick *stick, int index, int originset, SetJoystick *parentSet, QObject *parent) : JoyGradientButton(index, originset, parentSet, parent) { this->stick = stick; } JoyControlStickButton::JoyControlStickButton(JoyControlStick *stick, JoyStickDirectionsType::JoyStickDirections index, int originset, SetJoystick *parentSet, QObject *parent) : JoyGradientButton((int)index, originset, parentSet, parent) { this->stick = stick; } QString JoyControlStickButton::getDirectionName() { QString label = QString(); if (index == JoyControlStick::StickUp) { label.append(tr("Up")); } else if (index == JoyControlStick::StickDown) { label.append(tr("Down")); } else if (index == JoyControlStick::StickLeft) { label.append(tr("Left")); } else if (index == JoyControlStick::StickRight) { label.append(tr("Right")); } else if (index == JoyControlStick::StickLeftUp) { label.append(tr("Up")).append("+").append(tr("Left")); } else if (index == JoyControlStick::StickLeftDown) { label.append(tr("Down")).append("+").append(tr("Left")); } else if (index == JoyControlStick::StickRightUp) { label.append(tr("Up")).append("+").append(tr("Right")); } else if (index == JoyControlStick::StickRightDown) { label.append(tr("Down")).append("+").append(tr("Right")); } return label; } QString JoyControlStickButton::getPartialName(bool forceFullFormat, bool displayNames) { QString temp = stick->getPartialName(forceFullFormat, displayNames); temp.append(": "); if (!buttonName.isEmpty() && displayNames) { if (forceFullFormat) { temp.append(tr("Button")).append(" "); } temp.append(buttonName); } else if (!defaultButtonName.isEmpty()) { if (forceFullFormat) { temp.append(tr("Button")).append(" "); } temp.append(defaultButtonName); } else { temp.append(tr("Button")).append(" "); temp.append(getDirectionName()); } return temp; } QString JoyControlStickButton::getXmlName() { return this->xmlName; } /** * @brief Get the distance that an element is away from its assigned * dead zone * @return Normalized distance away from dead zone */ double JoyControlStickButton::getDistanceFromDeadZone() { return stick->calculateDirectionalDistance(); } /** * @brief Get the distance factor that should be used for mouse movement * @return Distance factor that should be used for mouse movement */ double JoyControlStickButton::getMouseDistanceFromDeadZone() { return stick->calculateMouseDirectionalDistance(this); } void JoyControlStickButton::setChangeSetCondition(SetChangeCondition condition, bool passive) { SetChangeCondition oldCondition = setSelectionCondition; if (condition != setSelectionCondition && !passive) { if (condition == SetChangeWhileHeld || condition == SetChangeTwoWay) { // Set new condition emit setAssignmentChanged(index, this->stick->getIndex(), setSelection, condition); } else if (setSelectionCondition == SetChangeWhileHeld || setSelectionCondition == SetChangeTwoWay) { // Remove old condition emit setAssignmentChanged(index, this->stick->getIndex(), setSelection, SetChangeDisabled); } setSelectionCondition = condition; } else if (passive) { setSelectionCondition = condition; } if (setSelectionCondition == SetChangeDisabled) { setChangeSetSelection(-1); } if (setSelectionCondition != oldCondition) { buildActiveZoneSummaryString(); emit propertyUpdated(); } } int JoyControlStickButton::getRealJoyNumber() { return index; } JoyControlStick* JoyControlStickButton::getStick() { return stick; } JoyStickDirectionsType::JoyStickDirections JoyControlStickButton::getDirection() { return static_cast(index); } /** * @brief Set the turbo mode that the button should use * @param Mode that should be used */ void JoyControlStickButton::setTurboMode(TurboMode mode) { if (isPartRealAxis()) { currentTurboMode = mode; } } /** * @brief Check if button should be considered a part of a real controller * axis. Needed for some dialogs so the program won't have to resort to * type checking. * @return Status of being part of a real controller axis */ bool JoyControlStickButton::isPartRealAxis() { return true; } double JoyControlStickButton::getLastAccelerationDistance() { double temp = stick->calculateLastAccelerationButtonDistance(this); return temp; } double JoyControlStickButton::getAccelerationDistance() { double temp = stick->calculateAccelerationDistance(this); return temp; } /** * @brief Generate a string that represents slots that will be activated or * slots that are currently active if a button is pressed * @return String of currently applicable slots for a button */ QString JoyControlStickButton::getActiveZoneSummary() { QList tempList; JoyControlStickModifierButton *tempButton = stick->getModifierButton(); /*if (tempButton && tempButton->getButtonState() && tempButton->hasActiveSlots() && getButtonState()) { QList activeModifierSlots = tempButton->getActiveZoneList(); tempList.append(activeModifierSlots); } */ tempList.append(getActiveZoneList()); QString temp = buildActiveZoneSummary(tempList); return temp; } QString JoyControlStickButton::getCalculatedActiveZoneSummary() { JoyControlStickModifierButton *tempButton = stick->getModifierButton(); QString temp; QStringList stringlist; if (tempButton && tempButton->getButtonState() && tempButton->hasActiveSlots() && getButtonState()) { stringlist.append(tempButton->getCalculatedActiveZoneSummary()); } stringlist.append(JoyButton::getCalculatedActiveZoneSummary()); temp = stringlist.join(", "); return temp; } double JoyControlStickButton::getLastMouseDistanceFromDeadZone() { return stick->calculateLastMouseDirectionalDistance(this); } double JoyControlStickButton::getCurrentSpringDeadCircle() { double result = (springDeadCircleMultiplier * 0.01); if (index == JoyControlStick::StickLeft || index == JoyControlStick::StickRight) { result = stick->getSpringDeadCircleX() * (springDeadCircleMultiplier * 0.01); } else if (index == JoyControlStick::StickUp || index == JoyControlStick::StickDown) { result = stick->getSpringDeadCircleY() * (springDeadCircleMultiplier * 0.01); } else if (index == JoyControlStick::StickRightUp || index == JoyControlStick::StickRightDown || index == JoyControlStick::StickLeftDown || index == JoyControlStick::StickLeftUp) { result = 0.0; } return result; } antimicro-2.23/src/joybuttontypes/joycontrolstickbutton.h000066400000000000000000000045571300750276700242250ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYCONTROLSTICKBUTTON_H #define JOYCONTROLSTICKBUTTON_H\ #include #include "joybuttontypes/joygradientbutton.h" #include "joycontrolstickdirectionstype.h" class JoyControlStick; class JoyControlStickButton : public JoyGradientButton { Q_OBJECT public: explicit JoyControlStickButton(JoyControlStick *stick, int index, int originset, SetJoystick *parentSet, QObject *parent = 0); explicit JoyControlStickButton(JoyControlStick *stick, JoyStickDirectionsType::JoyStickDirections index, int originset, SetJoystick *parentSet, QObject *parent = 0); virtual int getRealJoyNumber(); virtual QString getPartialName(bool forceFullFormat=false, bool displayNames=false); virtual QString getXmlName(); QString getDirectionName(); JoyStickDirectionsType::JoyStickDirections getDirection(); virtual double getDistanceFromDeadZone(); virtual double getMouseDistanceFromDeadZone(); virtual double getLastMouseDistanceFromDeadZone(); virtual void setChangeSetCondition(SetChangeCondition condition, bool passive=false); JoyControlStick *getStick(); virtual void setTurboMode(TurboMode mode); virtual bool isPartRealAxis(); virtual QString getActiveZoneSummary(); virtual QString getCalculatedActiveZoneSummary(); virtual double getAccelerationDistance(); virtual double getLastAccelerationDistance(); static const QString xmlName; protected: virtual double getCurrentSpringDeadCircle(); JoyControlStick *stick; signals: void setAssignmentChanged(int current_button, int axis_index, int associated_set, int mode); }; #endif // JOYCONTROLSTICKBUTTON_H antimicro-2.23/src/joybuttontypes/joycontrolstickmodifierbutton.cpp000066400000000000000000000074061300750276700262730ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include "joycontrolstick.h" #include "joycontrolstickmodifierbutton.h" const QString JoyControlStickModifierButton::xmlName = "stickmodifierbutton"; JoyControlStickModifierButton::JoyControlStickModifierButton(JoyControlStick *stick, int originset, SetJoystick *parentSet, QObject *parent) : JoyGradientButton(0, originset, parentSet, parent) { this->stick = stick; } QString JoyControlStickModifierButton::getPartialName(bool forceFullFormat, bool displayNames) { QString temp = stick->getPartialName(forceFullFormat, displayNames); temp.append(": "); if (!buttonName.isEmpty() && displayNames) { if (forceFullFormat) { temp.append(tr("Modifier")).append(" "); } temp.append(buttonName); } else if (!defaultButtonName.isEmpty()) { if (forceFullFormat) { temp.append(tr("Modifier")).append(" "); } temp.append(defaultButtonName); } else { temp.append(tr("Modifier")); } return temp; } QString JoyControlStickModifierButton::getXmlName() { return this->xmlName; } /** * @brief Get the distance that an element is away from its assigned * dead zone * @return Normalized distance away from dead zone */ double JoyControlStickModifierButton::getDistanceFromDeadZone() { return stick->calculateDirectionalDistance(); } /** * @brief Get the distance factor that should be used for mouse movement * @return Distance factor that should be used for mouse movement */ double JoyControlStickModifierButton::getMouseDistanceFromDeadZone() { return getDistanceFromDeadZone(); } void JoyControlStickModifierButton::setChangeSetCondition(SetChangeCondition condition, bool passive) { Q_UNUSED(condition); Q_UNUSED(passive); } /*int JoyControlStickModifierButton::getRealJoyNumber() { return index; } */ JoyControlStick* JoyControlStickModifierButton::getStick() { return stick; } /** * @brief Set the turbo mode that the button should use * @param Mode that should be used */ void JoyControlStickModifierButton::setTurboMode(TurboMode mode) { if (isPartRealAxis()) { currentTurboMode = mode; } } /** * @brief Check if button should be considered a part of a real controller * axis. Needed for some dialogs so the program won't have to resort to * type checking. * @return Status of being part of a real controller axis */ bool JoyControlStickModifierButton::isPartRealAxis() { return true; } bool JoyControlStickModifierButton::isModifierButton() { return true; } double JoyControlStickModifierButton::getAccelerationDistance() { double temp = stick->getAbsoluteRawDistance(); return temp; } double JoyControlStickModifierButton::getLastAccelerationDistance() { double temp = stick->calculateLastAccelerationDirectionalDistance(); return temp; } double JoyControlStickModifierButton::getLastMouseDistanceFromDeadZone() { return stick->calculateLastDirectionalDistance(); } antimicro-2.23/src/joybuttontypes/joycontrolstickmodifierbutton.h000066400000000000000000000035521300750276700257360ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYCONTROLSTICKMODIFIERBUTTON_H #define JOYCONTROLSTICKMODIFIERBUTTON_H #include "joybuttontypes/joygradientbutton.h" class JoyControlStick; class JoyControlStickModifierButton : public JoyGradientButton { Q_OBJECT public: explicit JoyControlStickModifierButton(JoyControlStick *stick, int originset, SetJoystick *parentSet, QObject *parent = 0); //virtual int getRealJoyNumber(); virtual QString getPartialName(bool forceFullFormat=false, bool displayNames=false); virtual QString getXmlName(); virtual double getDistanceFromDeadZone(); virtual double getMouseDistanceFromDeadZone(); virtual double getLastMouseDistanceFromDeadZone(); virtual void setChangeSetCondition(SetChangeCondition condition, bool passive=false); JoyControlStick *getStick(); virtual void setTurboMode(TurboMode mode); virtual bool isPartRealAxis(); virtual bool isModifierButton(); virtual double getAccelerationDistance(); virtual double getLastAccelerationDistance(); static const QString xmlName; protected: JoyControlStick *stick; }; #endif // JOYCONTROLSTICKMODIFIERBUTTON_H antimicro-2.23/src/joybuttontypes/joydpadbutton.cpp000066400000000000000000000101011300750276700227300ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "joydpadbutton.h" #include "joydpad.h" #include "event.h" const QString JoyDPadButton::xmlName = "dpadbutton"; // Initially, qualify direction as the button's index JoyDPadButton::JoyDPadButton(int direction, int originset, JoyDPad* dpad, SetJoystick *parentSet, QObject *parent) : JoyButton(direction, originset, parentSet, parent) { this->direction = direction; this->dpad = dpad; } QString JoyDPadButton::getDirectionName() { QString label = QString (); if (direction == DpadUp) { label.append(tr("Up")); } else if (direction == DpadDown) { label.append(tr("Down")); } else if (direction == DpadLeft) { label.append(tr("Left")); } else if (direction == DpadRight) { label.append(tr("Right")); } else if (direction == DpadLeftUp) { label.append(tr("Up")).append("+").append(tr("Left")); } else if (direction == DpadLeftDown) { label.append(tr("Down")).append("+").append(tr("Left")); } else if (direction == DpadRightUp) { label.append(tr("Up")).append("+").append(tr("Right")); } else if (direction == DpadRightDown) { label.append(tr("Down")).append("+").append(tr("Right")); } return label; } QString JoyDPadButton::getXmlName() { return this->xmlName; } int JoyDPadButton::getRealJoyNumber() { return index; } QString JoyDPadButton::getPartialName(bool forceFullFormat, bool displayNames) { QString temp = dpad->getName().append(" - "); if (!buttonName.isEmpty() && displayNames) { if (forceFullFormat) { temp.append(tr("Button")).append(" "); } temp.append(buttonName); } else if (!defaultButtonName.isEmpty() && displayNames) { if (forceFullFormat) { temp.append(tr("Button")).append(" "); } temp.append(defaultButtonName); } else { temp.append(tr("Button")).append(" "); temp.append(getDirectionName()); } return temp; } void JoyDPadButton::reset() { JoyButton::reset(); } void JoyDPadButton::reset(int index) { Q_UNUSED(index); reset(); } void JoyDPadButton::setChangeSetCondition(SetChangeCondition condition, bool passive) { SetChangeCondition oldCondition = setSelectionCondition; if (condition != setSelectionCondition && !passive) { if (condition == SetChangeWhileHeld || condition == SetChangeTwoWay) { // Set new condition emit setAssignmentChanged(index, this->dpad->getJoyNumber(), setSelection, condition); } else if (setSelectionCondition == SetChangeWhileHeld || setSelectionCondition == SetChangeTwoWay) { // Remove old condition emit setAssignmentChanged(index, this->dpad->getJoyNumber(), setSelection, SetChangeDisabled); } setSelectionCondition = condition; } else if (passive) { setSelectionCondition = condition; } if (setSelectionCondition == SetChangeDisabled) { setChangeSetSelection(-1); } if (setSelectionCondition != oldCondition) { buildActiveZoneSummaryString(); emit propertyUpdated(); } } JoyDPad* JoyDPadButton::getDPad() { return dpad; } int JoyDPadButton::getDirection() { return direction; } antimicro-2.23/src/joybuttontypes/joydpadbutton.h000066400000000000000000000034661300750276700224150ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYDPADBUTTON_H #define JOYDPADBUTTON_H #include "joybutton.h" class JoyDPad; class JoyDPadButton : public JoyButton { Q_OBJECT public: JoyDPadButton(int direction, int originset, JoyDPad* dpad, SetJoystick *parentSet, QObject *parent=0); QString getDirectionName(); int getDirection(); virtual int getRealJoyNumber(); virtual QString getPartialName(bool forceFullFormat=false, bool displayNames=false); virtual QString getXmlName(); JoyDPad *getDPad(); virtual void setChangeSetCondition(SetChangeCondition condition, bool passive=false); enum JoyDPadDirections { DpadCentered = 0, DpadUp = 1, DpadRight = 2, DpadDown = 4, DpadLeft = 8, DpadRightUp = 3, DpadRightDown = 6, DpadLeftUp = 9, DpadLeftDown = 12 }; static const QString xmlName; protected: int direction; JoyDPad *dpad; signals: void setAssignmentChanged(int current_button, int dpad_index, int associated_set, int mode); public slots: virtual void reset(); virtual void reset(int index); }; #endif // JOYDPADBUTTON_H antimicro-2.23/src/joybuttontypes/joygradientbutton.cpp000066400000000000000000000403501300750276700236260ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include "joygradientbutton.h" #include "event.h" JoyGradientButton::JoyGradientButton(int index, int originset, SetJoystick *parentSet, QObject *parent) : JoyButton(index, originset, parentSet, parent) { } /** * @brief Activate a turbo event on a button. */ void JoyGradientButton::turboEvent() { if (currentTurboMode == NormalTurbo) { JoyButton::turboEvent(); } else if (currentTurboMode == GradientTurbo || currentTurboMode == PulseTurbo) { double diff = fabs(getMouseDistanceFromDeadZone() - lastDistance); //qDebug() << "DIFF: " << QString::number(diff); bool changeState = false; int checkmate = 0; if (!turboTimer.isActive() && !isButtonPressed) { changeState = true; } else if (currentTurboMode == GradientTurbo && diff > 0 && getMouseDistanceFromDeadZone() >= 1.0) { if (isKeyPressed) { changeState = false; if (!turboTimer.isActive() || turboTimer.interval() != 5) { turboTimer.start(5); } turboHold.restart(); lastDistance = 1.0; } else { changeState = true; } } else if (turboHold.isNull() || lastDistance == 0.0 || turboHold.elapsed() > tempTurboInterval) { changeState = true; } else if (diff >= 0.1) { int tempInterval2 = 0; if (isKeyPressed) { if (currentTurboMode == GradientTurbo) { tempInterval2 = (int)floor((getMouseDistanceFromDeadZone() * turboInterval) + 0.5); } else { tempInterval2 = (int)floor((turboInterval * 0.5) + 0.5); } } else { if (currentTurboMode == GradientTurbo) { tempInterval2 = (int)floor(((1 - getMouseDistanceFromDeadZone()) * turboInterval) + 0.5); } else { double distance = getMouseDistanceFromDeadZone(); if (distance > 0.0) { tempInterval2 = (int)floor(((turboInterval / getMouseDistanceFromDeadZone()) * 0.5) + 0.5); } else { tempInterval2 = 0; } } } if (turboHold.elapsed() < tempInterval2) { // Still some valid time left. Continue current action with // remaining time left. tempTurboInterval = tempInterval2 - turboHold.elapsed(); int timerInterval = qMin(tempTurboInterval, 5); if (!turboTimer.isActive() || turboTimer.interval() != timerInterval) { turboTimer.start(timerInterval); } turboHold.restart(); changeState = false; lastDistance = getMouseDistanceFromDeadZone(); //qDebug() << "diff tmpTurbo press: " << QString::number(tempTurboInterval); //qDebug() << "diff timer press: " << QString::number(timerInterval); } else { // Elapsed time is greater than new interval. Change state. //if (isKeyPressed) //{ // checkmate = turboHold.elapsed(); //} changeState = true; //qDebug() << "YOU GOT CHANGE"; } } if (changeState) { if (!isKeyPressed) { if (!isButtonPressedQueue.isEmpty()) { ignoreSetQueue.clear(); isButtonPressedQueue.clear(); ignoreSetQueue.enqueue(false); isButtonPressedQueue.enqueue(isButtonPressed); } createDeskEvent(); isKeyPressed = true; if (turboTimer.isActive()) { if (currentTurboMode == GradientTurbo) { tempTurboInterval = (int)floor((getMouseDistanceFromDeadZone() * turboInterval) + 0.5); } else { tempTurboInterval = (int)floor((turboInterval * 0.5) + 0.5); } int timerInterval = qMin(tempTurboInterval, 5); //qDebug() << "tmpTurbo press: " << QString::number(tempTurboInterval); //qDebug() << "timer press: " << QString::number(timerInterval); if (turboTimer.interval() != timerInterval) { turboTimer.start(timerInterval); } turboHold.restart(); } } else { if (!isButtonPressedQueue.isEmpty()) { ignoreSetQueue.enqueue(false); isButtonPressedQueue.enqueue(!isButtonPressed); } releaseDeskEvent(); isKeyPressed = false; if (turboTimer.isActive()) { if (currentTurboMode == GradientTurbo) { tempTurboInterval = (int)floor(((1 - getMouseDistanceFromDeadZone()) * turboInterval) + 0.5); } else { double distance = getMouseDistanceFromDeadZone(); if (distance > 0.0) { tempTurboInterval = (int)floor(((turboInterval / getMouseDistanceFromDeadZone()) * 0.5) + 0.5); } else { tempTurboInterval = 0; } } int timerInterval = qMin(tempTurboInterval, 5); //qDebug() << "tmpTurbo release: " << QString::number(tempTurboInterval); //qDebug() << "timer release: " << QString::number(timerInterval); if (turboTimer.interval() != timerInterval) { turboTimer.start(timerInterval); } turboHold.restart(); } } lastDistance = getMouseDistanceFromDeadZone(); } checkmate = 0; } } void JoyGradientButton::wheelEventVertical() { JoyButtonSlot *buttonslot = 0; bool activateEvent = false; int tempInterval = 0; double diff = fabs(getMouseDistanceFromDeadZone() - lastWheelVerticalDistance); int oldInterval = 0; if (wheelSpeedY != 0) { if (lastWheelVerticalDistance > 0.0) { oldInterval = 1000 / wheelSpeedY / lastWheelVerticalDistance; } else { oldInterval = 1000 / wheelSpeedY / 0.01; } } if (currentWheelVerticalEvent) { buttonslot = currentWheelVerticalEvent; activateEvent = true; } if (!activateEvent) { if (!mouseWheelVerticalEventTimer.isActive()) { activateEvent = true; } else if (wheelVerticalTime.elapsed() > oldInterval) { activateEvent = true; } else if (diff >= 0.1 && wheelSpeedY != 0) { double distance = getMouseDistanceFromDeadZone(); if (distance > 0.0) { tempInterval = static_cast(1000 / wheelSpeedY / distance); } else { tempInterval = 0; } if (wheelVerticalTime.elapsed() < tempInterval) { // Still some valid time left. Continue current action with // remaining time left. tempInterval = tempInterval - wheelVerticalTime.elapsed(); tempInterval = qMin(tempInterval, 5); if (!mouseWheelVerticalEventTimer.isActive() || mouseWheelVerticalEventTimer.interval() != tempInterval) { mouseWheelVerticalEventTimer.start(tempInterval); } } else { // Elapsed time is greater than new interval. Change state. activateEvent = true; } } } if (buttonslot && wheelSpeedY != 0) { bool isActive = activeSlots.contains(buttonslot); if (isActive && activateEvent) { sendevent(buttonslot, true); sendevent(buttonslot, false); mouseWheelVerticalEventQueue.enqueue(buttonslot); double distance = getMouseDistanceFromDeadZone(); if (distance > 0.0) { tempInterval = static_cast(1000 / wheelSpeedY / distance); } else { tempInterval = 0; } tempInterval = qMin(tempInterval, 5); if (!mouseWheelVerticalEventTimer.isActive() || mouseWheelVerticalEventTimer.interval() != tempInterval) { mouseWheelVerticalEventTimer.start(tempInterval); } } else if (!isActive) { mouseWheelVerticalEventTimer.stop(); } } else if (!mouseWheelVerticalEventQueue.isEmpty() && wheelSpeedY != 0) { QQueue tempQueue; while (!mouseWheelVerticalEventQueue.isEmpty()) { buttonslot = mouseWheelVerticalEventQueue.dequeue(); bool isActive = activeSlots.contains(buttonslot); if (isActive && activateEvent) { sendevent(buttonslot, true); sendevent(buttonslot, false); tempQueue.enqueue(buttonslot); } else if (isActive) { tempQueue.enqueue(buttonslot); } } if (!tempQueue.isEmpty()) { mouseWheelVerticalEventQueue = tempQueue; double distance = getMouseDistanceFromDeadZone(); if (distance > 0.0) { tempInterval = static_cast(1000 / wheelSpeedY / distance); } else { tempInterval = 0; } tempInterval = qMin(tempInterval, 5); if (!mouseWheelVerticalEventTimer.isActive() || mouseWheelVerticalEventTimer.interval() != tempInterval) { mouseWheelVerticalEventTimer.start(tempInterval); } } else { mouseWheelVerticalEventTimer.stop(); } } else { mouseWheelVerticalEventTimer.stop(); } if (activateEvent) { wheelVerticalTime.restart(); lastWheelVerticalDistance = getMouseDistanceFromDeadZone(); } } void JoyGradientButton::wheelEventHorizontal() { JoyButtonSlot *buttonslot = 0; bool activateEvent = false; int tempInterval = 0; double diff = fabs(getMouseDistanceFromDeadZone() - lastWheelHorizontalDistance); int oldInterval = 0; if (wheelSpeedX != 0) { if (lastWheelHorizontalDistance > 0.0) { oldInterval = 1000 / wheelSpeedX / lastWheelHorizontalDistance; } else { oldInterval = 1000 / wheelSpeedX / 0.01; } } if (currentWheelHorizontalEvent) { buttonslot = currentWheelHorizontalEvent; activateEvent = true; } if (!activateEvent) { if (!mouseWheelHorizontalEventTimer.isActive()) { activateEvent = true; } else if (wheelHorizontalTime.elapsed() > oldInterval) { activateEvent = true; } else if (diff >= 0.1 && wheelSpeedX != 0) { double distance = getMouseDistanceFromDeadZone(); if (distance > 0.0) { tempInterval = static_cast(1000 / wheelSpeedX / distance); } else { tempInterval = 0; } if (wheelHorizontalTime.elapsed() < tempInterval) { // Still some valid time left. Continue current action with // remaining time left. tempInterval = tempInterval - wheelHorizontalTime.elapsed(); tempInterval = qMin(tempInterval, 5); if (!mouseWheelHorizontalEventTimer.isActive() || mouseWheelHorizontalEventTimer.interval() != tempInterval) { mouseWheelHorizontalEventTimer.start(tempInterval); } } else { // Elapsed time is greater than new interval. Change state. activateEvent = true; } } } if (buttonslot && wheelSpeedX != 0) { bool isActive = activeSlots.contains(buttonslot); if (isActive && activateEvent) { sendevent(buttonslot, true); sendevent(buttonslot, false); mouseWheelHorizontalEventQueue.enqueue(buttonslot); double distance = getMouseDistanceFromDeadZone(); if (distance > 0.0) { tempInterval = static_cast(1000 / wheelSpeedX / distance); } else { tempInterval = 0; } tempInterval = qMin(tempInterval, 5); if (!mouseWheelHorizontalEventTimer.isActive() || mouseWheelVerticalEventTimer.interval() != tempInterval) { mouseWheelHorizontalEventTimer.start(tempInterval); } } else if (!isActive) { mouseWheelHorizontalEventTimer.stop(); } } else if (!mouseWheelHorizontalEventQueue.isEmpty() && wheelSpeedX != 0) { QQueue tempQueue; while (!mouseWheelHorizontalEventQueue.isEmpty()) { buttonslot = mouseWheelHorizontalEventQueue.dequeue(); bool isActive = activeSlots.contains(buttonslot); if (isActive) { sendevent(buttonslot, true); sendevent(buttonslot, false); tempQueue.enqueue(buttonslot); } } if (!tempQueue.isEmpty()) { mouseWheelHorizontalEventQueue = tempQueue; double distance = getMouseDistanceFromDeadZone(); if (distance > 0.0) { tempInterval = static_cast(1000 / wheelSpeedX / distance); } else { tempInterval = 0; } tempInterval = qMin(tempInterval, 5); if (!mouseWheelHorizontalEventTimer.isActive() || mouseWheelVerticalEventTimer.interval() != tempInterval) { mouseWheelHorizontalEventTimer.start(tempInterval); } } else { mouseWheelHorizontalEventTimer.stop(); } } else { mouseWheelHorizontalEventTimer.stop(); } if (activateEvent) { wheelHorizontalTime.restart(); lastWheelHorizontalDistance = getMouseDistanceFromDeadZone(); } } antimicro-2.23/src/joybuttontypes/joygradientbutton.h000066400000000000000000000022311300750276700232670ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYGRADIENTBUTTON_H #define JOYGRADIENTBUTTON_H #include "joybutton.h" class JoyGradientButton : public JoyButton { Q_OBJECT public: explicit JoyGradientButton(int index, int originset, SetJoystick *parentSet, QObject *parent=0); signals: protected slots: virtual void turboEvent(); virtual void wheelEventVertical(); virtual void wheelEventHorizontal(); }; #endif // JOYGRADIENTBUTTON_H antimicro-2.23/src/joybuttonwidget.cpp000066400000000000000000000046311300750276700201740ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "joybuttonwidget.h" #include "joybuttoncontextmenu.h" JoyButtonWidget::JoyButtonWidget(JoyButton *button, bool displayNames, QWidget *parent) : FlashButtonWidget(displayNames, parent) { this->button = button; refreshLabel(); enableFlashes(); tryFlash(); this->setContextMenuPolicy(Qt::CustomContextMenu); connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint&))); //connect(button, SIGNAL(slotsChanged()), this, SLOT(refreshLabel())); connect(button, SIGNAL(propertyUpdated()), this, SLOT(refreshLabel())); connect(button, SIGNAL(activeZoneChanged()), this, SLOT(refreshLabel())); } JoyButton* JoyButtonWidget::getJoyButton() { return button; } void JoyButtonWidget::disableFlashes() { disconnect(button, SIGNAL(clicked(int)), this, SLOT(flash())); disconnect(button, SIGNAL(released(int)), this, SLOT(unflash())); this->unflash(); } void JoyButtonWidget::enableFlashes() { connect(button, SIGNAL(clicked(int)), this, SLOT(flash()), Qt::QueuedConnection); connect(button, SIGNAL(released(int)), this, SLOT(unflash()), Qt::QueuedConnection); } QString JoyButtonWidget::generateLabel() { QString temp; temp = button->getName(false, displayNames).replace("&", "&&"); return temp; } void JoyButtonWidget::showContextMenu(const QPoint &point) { QPoint globalPos = this->mapToGlobal(point); JoyButtonContextMenu *contextMenu = new JoyButtonContextMenu(button, this); contextMenu->buildMenu(); contextMenu->popup(globalPos); } void JoyButtonWidget::tryFlash() { if (button->getButtonState()) { flash(); } } antimicro-2.23/src/joybuttonwidget.h000066400000000000000000000024761300750276700176460ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYBUTTONWIDGET_H #define JOYBUTTONWIDGET_H #include #include "flashbuttonwidget.h" #include "joybutton.h" class JoyButtonWidget : public FlashButtonWidget { Q_OBJECT public: explicit JoyButtonWidget(JoyButton* button, bool displayNames, QWidget *parent=0); JoyButton* getJoyButton(); void tryFlash(); protected: virtual QString generateLabel(); JoyButton* button; signals: public slots: void disableFlashes(); void enableFlashes(); private slots: void showContextMenu(const QPoint &point); }; #endif // JOYBUTTONWIDGET_H antimicro-2.23/src/joycontrolstick.cpp000066400000000000000000003737001300750276700202010ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include #include "joycontrolstick.h" #include "inputdevice.h" // Define Pi here. const double JoyControlStick::PI = acos(-1.0); // Set default values used for stick properties. const int JoyControlStick::DEFAULTDEADZONE = 8000; const int JoyControlStick::DEFAULTMAXZONE = JoyAxis::AXISMAXZONE; const int JoyControlStick::DEFAULTDIAGONALRANGE = 45; const JoyControlStick::JoyMode JoyControlStick::DEFAULTMODE = JoyControlStick::StandardMode; const double JoyControlStick::DEFAULTCIRCLE = 0.0; const unsigned int JoyControlStick::DEFAULTSTICKDELAY = 0; JoyControlStick::JoyControlStick(JoyAxis *axis1, JoyAxis *axis2, int index, int originset, QObject *parent) : QObject(parent) { this->axisX = axis1; this->axisX->setControlStick(this); this->axisY = axis2; this->axisY->setControlStick(this); this->index = index; this->originset = originset; this->modifierButton = 0; reset(); populateButtons(); directionDelayTimer.setSingleShot(true); connect(&directionDelayTimer, SIGNAL(timeout()), this, SLOT(stickDirectionChangeEvent())); } JoyControlStick::~JoyControlStick() { axisX->removeControlStick(false); axisY->removeControlStick(false); deleteButtons(); } /** * @brief Take the input value for the two axes that make up a stick and * activate the proper event based on the current values. * @param Should set changing routines be ignored. */ void JoyControlStick::joyEvent(bool ignoresets) { safezone = !inDeadZone(); if (safezone && !isActive) { isActive = true; emit active(axisX->getCurrentRawValue(), axisY->getCurrentRawValue()); if (ignoresets || stickDelay == 0) { if (directionDelayTimer.isActive()) { directionDelayTimer.stop(); } createDeskEvent(ignoresets); } else { if (!directionDelayTimer.isActive()) { directionDelayTimer.start(stickDelay); } } } else if (!safezone && isActive) { isActive = false; emit released(axisX->getCurrentRawValue(), axisY->getCurrentRawValue()); if (ignoresets || stickDelay == 0) { if (directionDelayTimer.isActive()) { directionDelayTimer.stop(); } createDeskEvent(ignoresets); } else { if (!directionDelayTimer.isActive()) { directionDelayTimer.start(stickDelay); } } } else if (isActive) { if (ignoresets || stickDelay == 0) { if (directionDelayTimer.isActive()) { directionDelayTimer.stop(); } createDeskEvent(ignoresets); } else { JoyStickDirections pendingDirection = calculateStickDirection(); if (currentDirection != pendingDirection) { if (!directionDelayTimer.isActive()) { directionDelayTimer.start(stickDelay); } } else { if (directionDelayTimer.isActive()) { directionDelayTimer.stop(); } createDeskEvent(ignoresets); } } } emit moved(axisX->getCurrentRawValue(), axisY->getCurrentRawValue()); pendingStickEvent = false; } /** * @brief Check the current stick position to see if it lies in * the assigned dead zone. * @return If stick position is in the assigned dead zone */ bool JoyControlStick::inDeadZone() { int axis1Value = axisX->getCurrentRawValue(); int axis2Value = axisY->getCurrentRawValue(); unsigned int squareDist = static_cast(axis1Value*axis1Value) + static_cast(axis2Value*axis2Value); return squareDist <= static_cast(deadZone*deadZone); } /** * @brief Populate the virtual buttons assigned to an analog stick. */ void JoyControlStick::populateButtons() { JoyControlStickButton *button = new JoyControlStickButton(this, StickUp, originset, getParentSet(), this); buttons.insert(StickUp, button); button = new JoyControlStickButton(this, StickDown, originset, getParentSet(), this); buttons.insert(StickDown, button); button = new JoyControlStickButton(this, StickLeft, originset, getParentSet(), this); buttons.insert(StickLeft, button); button = new JoyControlStickButton(this, StickRight, originset, getParentSet(), this); buttons.insert(StickRight, button); button = new JoyControlStickButton(this, StickLeftUp, originset, getParentSet(), this); buttons.insert(StickLeftUp, button); button = new JoyControlStickButton(this, StickLeftDown, originset, getParentSet(), this); buttons.insert(StickLeftDown, button); button = new JoyControlStickButton(this, StickRightDown, originset, getParentSet(), this); buttons.insert(StickRightDown, button); button = new JoyControlStickButton(this, StickRightUp, originset, getParentSet(), this); buttons.insert(StickRightUp, button); modifierButton = new JoyControlStickModifierButton(this, originset, getParentSet(), this); } /** * @brief Get the assigned dead zone value. * @return Assigned dead zone value */ int JoyControlStick::getDeadZone() { return deadZone; } /** * @brief Get the assigned diagonal range value. * @return Assigned diagonal range. */ int JoyControlStick::getDiagonalRange() { return diagonalRange; } /** * @brief Find the position of the two stick axes, deactivate no longer used * stick direction button and then activate direction buttons for new * direction. * @param Should set changing operations be ignored. Necessary in the middle * of a set change. */ void JoyControlStick::createDeskEvent(bool ignoresets) { JoyControlStickButton *eventbutton1 = 0; JoyControlStickButton *eventbutton2 = 0; JoyControlStickButton *eventbutton3 = 0; if (safezone) { if (currentMode == StandardMode) { determineStandardModeEvent(eventbutton1, eventbutton2); } else if (currentMode == EightWayMode) { determineEightWayModeEvent(eventbutton1, eventbutton2, eventbutton3); } else if (currentMode == FourWayCardinal) { determineFourWayCardinalEvent(eventbutton1, eventbutton2); } else if (currentMode == FourWayDiagonal) { determineFourWayDiagonalEvent(eventbutton3); } } else { currentDirection = StickCentered; } /* * Release any currently active stick buttons. */ if (!eventbutton1 && activeButton1) { // Currently in deadzone. Disable currently active button. performButtonRelease(activeButton1, ignoresets); } else if (eventbutton1 && activeButton1 && eventbutton1 != activeButton1) { // Deadzone skipped. Button for new event is not the currently // active button. Disable the active button. performButtonRelease(activeButton1, ignoresets); } if (!eventbutton2 && activeButton2) { // Currently in deadzone. Disable currently active button. performButtonRelease(activeButton2, ignoresets); } else if (eventbutton2 && activeButton2 && eventbutton2 != activeButton2) { // Deadzone skipped. Button for new event is not the currently // active button. Disable the active button. performButtonRelease(activeButton2, ignoresets); } if (!eventbutton3 && activeButton3) { // Currently in deadzone. Disable currently active button. performButtonRelease(activeButton3, ignoresets); } else if (eventbutton3 && activeButton3 && eventbutton3 != activeButton3) { // Deadzone skipped. Button for new event is not the currently // active button. Disable the active button. performButtonRelease(activeButton3, ignoresets); } if (safezone) { // Activate modifier button before activating directional buttons. // Value from the new stick event will be used to determine // distance events. modifierButton->joyEvent(true, ignoresets); } else { // Release modifier button after releasing directional buttons. modifierButton->joyEvent(false, ignoresets); } /* * Enable stick buttons. */ if (eventbutton1 && !activeButton1) { // There is no active button. Call joyEvent and set current // button as active button performButtonPress(eventbutton1, activeButton1, ignoresets); } else if (eventbutton1 && activeButton1 && eventbutton1 == activeButton1) { // Button is currently active. Just pass current value performButtonPress(eventbutton1, activeButton1, ignoresets); } if (eventbutton2 && !activeButton2) { // There is no active button. Call joyEvent and set current // button as active button performButtonPress(eventbutton2, activeButton2, ignoresets); } else if (eventbutton2 && activeButton2 && eventbutton2 == activeButton2) { // Button is currently active. Just pass current value performButtonPress(eventbutton2, activeButton2, ignoresets); } if (eventbutton3 && !activeButton3) { // There is no active button. Call joyEvent and set current // button as active button performButtonPress(eventbutton3, activeButton3, ignoresets); } else if (eventbutton3 && activeButton3 && eventbutton3 == activeButton3) { // Button is currently active. Just pass current value performButtonPress(eventbutton3, activeButton3, ignoresets); } } /** * @brief Calculate the bearing (in degrees) corresponding to the current * position of the X and Y axes of a stick. * @return Bearing (in degrees) */ double JoyControlStick::calculateBearing() { return calculateBearing(axisX->getCurrentRawValue(), axisY->getCurrentRawValue()); } /** * @brief Calculate the bearing (in degrees) corresponding to the * passed X and Y axes values associated with the stick. * @param X axis value * @param Y axis value * @return Bearing (in degrees) */ double JoyControlStick::calculateBearing(int axisXValue, int axisYValue) { double finalAngle = 0.0; int axis1Value = axisXValue; int axis2Value = axisYValue; if (axis1Value == 0 && axis2Value == 0) { finalAngle = 0.0; } else { double temp1 = axis1Value; double temp2 = axis2Value; double angle = (atan2(temp1, -temp2) * 180) / PI; if (axis1Value >= 0 && axis2Value <= 0) { // NE Quadrant finalAngle = angle; } else if (axis1Value >= 0 && axis2Value >= 0) { // SE Quadrant (angle will be positive) finalAngle = angle; } else if (axis1Value <= 0 && axis2Value >= 0) { // SW Quadrant (angle will be negative) finalAngle = 360.0 + angle; } else if (axis1Value <= 0 && axis2Value <= 0) { // NW Quadrant (angle will be negative) finalAngle = 360.0 + angle; } } return finalAngle; } /** * @brief Get current radial distance of the stick position past the assigned * dead zone. * @return Distance percentage in the range of 0.0 - 1.0. */ double JoyControlStick::getDistanceFromDeadZone() { return getDistanceFromDeadZone(axisX->getCurrentRawValue(), axisY->getCurrentRawValue()); } /** * @brief Get radial distance of the stick position past the assigned dead zone * based on the passed X and Y axes values associated with the stick. * @param X axis value * @param Y axis value * @return Distance percentage in the range of 0.0 - 1.0. */ double JoyControlStick::getDistanceFromDeadZone(int axisXValue, int axisYValue) { double distance = 0.0; int axis1Value = axisXValue; int axis2Value = axisYValue; double angle2 = atan2(axis1Value, -axis2Value); double ang_sin = sin(angle2); double ang_cos = cos(angle2); unsigned int squared_dist = static_cast(axis1Value*axis1Value) + static_cast(axis2Value*axis2Value); unsigned int dist = sqrt(squared_dist); double squareStickFullPhi = qMin(ang_sin ? 1/fabs(ang_sin) : 2, ang_cos ? 1/fabs(ang_cos) : 2); double circle = this->circle; double circleStickFull = (squareStickFullPhi - 1) * circle + 1; double adjustedDist = circleStickFull > 1.0 ? (dist / circleStickFull) : dist; double adjustedDeadZone = circleStickFull > 1.0 ? (deadZone / circleStickFull) : deadZone; distance = (adjustedDist - adjustedDeadZone)/(double)(maxZone - adjustedDeadZone); distance = qBound(0.0, distance, 1.0); return distance; } /** * @brief Get distance of the Y axis past the assigned dead zone. * @param Should interpolation be performed along the diagonal regions. * @return Distance percentage in the range of 0.0 - 1.0. */ double JoyControlStick::calculateYDistanceFromDeadZone(bool interpolate) { return calculateYDistanceFromDeadZone(axisX->getCurrentRawValue(), axisY->getCurrentRawValue(), interpolate); } /** * @brief Get distance of the Y axis past the assigned dead zone based * on the passed X and Y axis values for the analog stick. * @param X axis value * @param Y axis value * @param Should interpolation be performed along the diagonal regions. * @return Distance percentage in the range of 0.0 - 1.0. */ double JoyControlStick::calculateYDistanceFromDeadZone(int axisXValue, int axisYValue, bool interpolate) { double distance = 0.0; int axis1Value = axisXValue; int axis2Value = axisYValue; //unsigned int square_dist = (unsigned int)(axis1Value*axis1Value) + (unsigned int)(axis2Value*axis2Value); double angle2 = atan2(axis1Value, -axis2Value); double ang_sin = sin(angle2); double ang_cos = cos(angle2); int deadY = abs(floor(deadZone * ang_cos + 0.5)); //int axis2ValueCircleFull = (int)floor(JoyAxis::AXISMAX * fabs(ang_cos) + 0.5); double squareStickFullPhi = qMin(ang_sin ? 1/fabs(ang_sin) : 2, ang_cos ? 1/fabs(ang_cos) : 2); double circle = this->circle; double circleStickFull = (squareStickFullPhi - 1) * circle + 1; //double circleToSquareTest = axis2Value * squareStickFullPhi; double adjustedAxis2Value = circleStickFull > 1.0 ? (axis2Value / circleStickFull) : axis2Value; double adjustedDeadYZone = circleStickFull > 1.0 ? (deadY / circleStickFull) : deadY; // Interpolation would return the correct value if diagonalRange is 90 but // the routine gets skipped to save time. if (interpolate && diagonalRange < 90) { JoyStickDirections direction = calculateStickDirection(axis1Value, axis2Value); if (direction == StickRightUp || direction == StickUp) { QList tempangles = getDiagonalZoneAngles(); double maxangle = tempangles.at(3); double minangle = tempangles.at(1); double square_dist = getAbsoluteRawDistance(axis1Value, axis2Value); double mindeadY = fabs(square_dist * sin(minangle * PI / 180.0)); double currentDeadY = qMax(static_cast(adjustedDeadYZone), mindeadY); double maxRange = static_cast(maxZone - currentDeadY); double tempdist4 = 0.0; if (maxRange != 0.0) { tempdist4 = (fabs(adjustedAxis2Value) - currentDeadY) / maxRange; } distance = tempdist4; } else if (direction == StickRightDown || direction == StickRight) { QList tempfuck = getDiagonalZoneAngles(); double maxangle = tempfuck.at(5); double minangle = tempfuck.at(4); double square_dist = getAbsoluteRawDistance(axis1Value, axis2Value); double mindeadY = fabs(square_dist * sin((minangle - 90.0) * PI / 180.0)); double currentDeadY = qMax(static_cast(adjustedDeadYZone), mindeadY); double maxRange = static_cast(maxZone - currentDeadY); double tempdist4 = 0.0; if (maxRange != 0.0) { tempdist4 = (fabs(adjustedAxis2Value) - currentDeadY) / maxRange; } distance = tempdist4; } else if (direction == StickLeftDown || direction == StickDown) { QList tempangles = getDiagonalZoneAngles(); double maxangle = tempangles.at(7); double minangle = tempangles.at(6); double square_dist = getAbsoluteRawDistance(axis1Value, axis2Value); double mindeadY = fabs(square_dist * sin((minangle - 180.0) * PI / 180.0)); double currentDeadY = qMax(static_cast(adjustedDeadYZone), mindeadY); double maxRange = static_cast(maxZone - currentDeadY); double tempdist4 = 0.0; if (maxRange != 0.0) { tempdist4 = (fabs(adjustedAxis2Value) - currentDeadY) / maxRange; } distance = tempdist4; } else if (direction == StickLeftUp || direction == StickLeft) { QList tempangles = getDiagonalZoneAngles(); double maxangle = tempangles.at(1); double minangle = tempangles.at(8); double square_dist = getAbsoluteRawDistance(axis1Value, axis2Value); double mindeadY = fabs(square_dist * sin((minangle - 270.0) * PI / 180.0)); double currentDeadY = qMax(static_cast(adjustedDeadYZone), mindeadY); double maxRange = static_cast(maxZone - currentDeadY); double tempdist4 = 0.0; if (maxRange != 0.0) { tempdist4 = (fabs(adjustedAxis2Value) - currentDeadY) / maxRange; } distance = tempdist4; } else { // Backup plan. Should not arrive here. double maxRange = static_cast(maxZone - adjustedDeadYZone); double tempdist4 = 0.0; if (maxRange != 0.0) { tempdist4 = (fabs(adjustedAxis2Value) - adjustedDeadYZone) / maxRange; } distance = tempdist4; } } else { // No interpolation desired or diagonal range is 90 degrees. double maxRange = static_cast(maxZone - adjustedDeadYZone); double tempdist4 = 0.0; if (maxRange != 0.0) { tempdist4 = (fabs(adjustedAxis2Value) - adjustedDeadYZone) / maxRange; } distance = tempdist4; } distance = qBound(0.0, distance, 1.0); return distance; } /** * @brief Get distance of the X axis past the assigned dead zone. * @param Should interpolation be performed along the diagonal regions. * @return Distance percentage in the range of 0.0 - 1.0. */ double JoyControlStick::calculateXDistanceFromDeadZone(bool interpolate) { return calculateXDistanceFromDeadZone(axisX->getCurrentRawValue(), axisY->getCurrentRawValue(), interpolate); } /** * @brief Get distance of the X axis past the assigned dead zone based * on the passed X and Y axis values for the analog stick. * @param X axis value * @param Y axis value * @param Should interpolation be performed along the diagonal regions. * @return Distance percentage in the range of 0.0 - 1.0. */ double JoyControlStick::calculateXDistanceFromDeadZone(int axisXValue, int axisYValue, bool interpolate) { double distance = 0.0; int axis1Value = axisXValue; int axis2Value = axisYValue; //unsigned int square_dist = (unsigned int)(axis1Value*axis1Value) + (unsigned int)(axis2Value*axis2Value); double angle2 = atan2(axis1Value, -axis2Value); double ang_sin = sin(angle2); double ang_cos = cos(angle2); int deadX = abs((int)floor(deadZone * ang_sin + 0.5)); //int axis1ValueCircleFull = (int)floor(JoyAxis::AXISMAX * fabs(ang_sin) + 0.5); double squareStickFullPhi = qMin(ang_sin ? 1/fabs(ang_sin) : 2, ang_cos ? 1/fabs(ang_cos) : 2); double circle = this->circle; double circleStickFull = (squareStickFullPhi - 1) * circle + 1; //double alternateStickFullValue = circleStickFull * abs(axis1ValueCircleFull); double adjustedAxis1Value = circleStickFull > 1.0 ? (axis1Value / circleStickFull) : axis1Value; double adjustedDeadXZone = circleStickFull > 1.0 ? (deadX / circleStickFull) : deadX; // Interpolation would return the correct value if diagonalRange is 90 but // the routine gets skipped to save time. if (interpolate && diagonalRange < 90) { JoyStickDirections direction = calculateStickDirection(axis1Value, axis2Value); if (direction == StickRightUp || direction == StickRight) { QList tempangles = getDiagonalZoneAngles(); double maxangle = tempangles.at(3); double minangle = tempangles.at(1); double square_dist = getAbsoluteRawDistance(axis1Value, axis2Value); double mindeadX = fabs(square_dist * cos(maxangle * PI / 180.0)); double currentDeadX = qMax(mindeadX, static_cast(adjustedDeadXZone)); double maxRange = static_cast(maxZone - currentDeadX); double tempdist4 = 0.0; if (maxRange != 0.0) { tempdist4 = (fabs(adjustedAxis1Value) - currentDeadX) / maxRange; } distance = tempdist4; } else if (direction == StickRightDown || direction == StickDown) { QList tempangles = getDiagonalZoneAngles(); double maxangle = tempangles.at(5); double minangle = tempangles.at(4); double square_dist = getAbsoluteRawDistance(axis1Value, axis2Value); double mindeadX = fabs(square_dist * cos((maxangle - 90.0) * PI / 180.0)); double currentDeadX = qMax(mindeadX, static_cast(adjustedDeadXZone)); double maxRange = static_cast(maxZone - currentDeadX); double tempdist4 = 0.0; if (maxRange != 0.0) { tempdist4 = (fabs(adjustedAxis1Value) - currentDeadX) / maxRange; } distance = tempdist4; } else if (direction == StickLeftDown || direction == StickLeft) { QList tempangles = getDiagonalZoneAngles(); double maxangle = tempangles.at(7); double minangle = tempangles.at(6); double square_dist = getAbsoluteRawDistance(axis1Value, axis2Value); double mindeadX = fabs(square_dist * cos((maxangle - 180.0) * PI / 180.0)); double currentDeadX = qMax(mindeadX, static_cast(adjustedDeadXZone)); double maxRange = static_cast(maxZone - currentDeadX); double tempdist4 = 0.0; if (maxRange != 0.0) { tempdist4 = (fabs(adjustedAxis1Value) - currentDeadX) / maxRange; } distance = tempdist4; } else if (direction == StickLeftUp || direction == StickUp) { QList tempangles = getDiagonalZoneAngles(); double maxangle = tempangles.at(1); double minangle = tempangles.at(8); double square_dist = getAbsoluteRawDistance(axis1Value, axis2Value); double mindeadX = fabs(square_dist * cos((maxangle - 270.0) * PI / 180.0)); double currentDeadX = qMax(mindeadX, static_cast(adjustedDeadXZone)); double maxRange = static_cast(maxZone - currentDeadX); double tempdist4 = 0.0; if (maxRange != 0.0) { tempdist4 = (fabs(adjustedAxis1Value) - currentDeadX) / maxRange; } distance = tempdist4; } else { // Backup plan. Should not arrive here. double maxRange = static_cast(maxZone - adjustedDeadXZone); double tempdist4 = 0.0; if (maxRange != 0.0) { tempdist4 = (fabs(adjustedAxis1Value) - adjustedDeadXZone) / maxRange; } distance = tempdist4; } } else { // No interpolation desired or diagonal range is 90 degrees. double maxRange = static_cast(maxZone - adjustedDeadXZone); double tempdist4 = 0.0; if (maxRange != 0.0) { tempdist4 = (fabs(adjustedAxis1Value) - adjustedDeadXZone) / maxRange; } distance = tempdist4; } distance = qBound(0.0, distance, 1.0); return distance; } /** * @brief Get the raw radial distance of the stick. Values will be between 0 - 32,767. * @return Radial distance in the range of 0 - 32,767. */ double JoyControlStick::getAbsoluteRawDistance() { double temp = getAbsoluteRawDistance(axisX->getCurrentRawValue(), axisY->getCurrentRawValue()); return temp; } double JoyControlStick::getAbsoluteRawDistance(int axisXValue, int axisYValue) { double distance = 0.0; int axis1Value = axisXValue; int axis2Value = axisYValue; unsigned int square_dist = static_cast(axis1Value*axis1Value) + static_cast(axis2Value*axis2Value); distance = sqrt(square_dist); return distance; } double JoyControlStick::getNormalizedAbsoluteDistance() { double distance = 0.0; int axis1Value = axisX->getCurrentRawValue(); int axis2Value = axisY->getCurrentRawValue(); unsigned int square_dist = static_cast(axis1Value*axis1Value) + static_cast(axis2Value*axis2Value); distance = sqrt(square_dist)/static_cast(maxZone); if (distance > 1.0) { distance = 1.0; } else if (distance < 0.0) { distance = 0.0; } return distance; } double JoyControlStick::getRadialDistance(int axisXValue, int axisYValue) { double distance = 0.0; int axis1Value = axisXValue; int axis2Value = axisYValue; unsigned int square_dist = static_cast(axis1Value*axis1Value) + static_cast(axis2Value*axis2Value); distance = sqrt(square_dist)/static_cast(maxZone); if (distance > 1.0) { distance = 1.0; } else if (distance < 0.0) { distance = 0.0; } return distance; } void JoyControlStick::setIndex(int index) { this->index = index; } int JoyControlStick::getIndex() { return index; } int JoyControlStick::getRealJoyIndex() { return index + 1; } QString JoyControlStick::getName(bool forceFullFormat, bool displayNames) { QString label = getPartialName(forceFullFormat, displayNames); label.append(": "); QStringList tempList; if (buttons.contains(StickUp)) { JoyControlStickButton *button = buttons.value(StickUp); if (!button->getButtonName().isEmpty()) { tempList.append(button->getButtonName()); } else { tempList.append(button->getSlotsSummary()); } } if (buttons.contains(StickLeft)) { JoyControlStickButton *button = buttons.value(StickLeft); if (!button->getButtonName().isEmpty()) { tempList.append(button->getButtonName()); } else { tempList.append(button->getSlotsSummary()); } } if (buttons.contains(StickDown)) { JoyControlStickButton *button = buttons.value(StickDown); if (!button->getButtonName().isEmpty()) { tempList.append(button->getButtonName()); } else { tempList.append(button->getSlotsSummary()); } } if (buttons.contains(StickRight)) { JoyControlStickButton *button = buttons.value(StickRight); if (!button->getButtonName().isEmpty()) { tempList.append(button->getButtonName()); } else { tempList.append(button->getSlotsSummary()); } } label.append(tempList.join(", ")); return label; } QString JoyControlStick::getPartialName(bool forceFullFormat, bool displayNames) { QString label; if (!stickName.isEmpty() && displayNames) { if (forceFullFormat) { label.append(tr("Stick")).append(" "); } label.append(stickName); } else if (!defaultStickName.isEmpty()) { if (forceFullFormat) { label.append(tr("Stick")).append(" "); } label.append(defaultStickName); } else { label.append(tr("Stick")).append(" "); label.append(QString::number(getRealJoyIndex())); } return label; } void JoyControlStick::setDefaultStickName(QString tempname) { defaultStickName = tempname; emit stickNameChanged(); } QString JoyControlStick::getDefaultStickName() { return defaultStickName; } int JoyControlStick::getMaxZone() { return maxZone; } int JoyControlStick::getCurrentlyAssignedSet() { return originset; } void JoyControlStick::reset() { deadZone = 8000; maxZone = JoyAxis::AXISMAXZONE; diagonalRange = 45; isActive = false; pendingStickEvent = false; /*if (activeButton1) { activeButton1->reset(); } activeButton1 = 0; if (activeButton2) { activeButton2->reset(); } activeButton2 = 0;*/ activeButton1 = 0; activeButton2 = 0; activeButton3 = 0; safezone = false; currentDirection = StickCentered; currentMode = StandardMode; stickName.clear(); circle = DEFAULTCIRCLE; stickDelay = DEFAULTSTICKDELAY; resetButtons(); } void JoyControlStick::setDeadZone(int value) { value = abs(value); if (value > JoyAxis::AXISMAX) { value = JoyAxis::AXISMAX; } if (value != deadZone && value < maxZone) { deadZone = value; emit deadZoneChanged(value); emit propertyUpdated(); } } void JoyControlStick::setMaxZone(int value) { value = abs(value); if (value >= JoyAxis::AXISMAX) { value = JoyAxis::AXISMAX; } if (value != maxZone && value > deadZone) { maxZone = value; emit maxZoneChanged(value); emit propertyUpdated(); } } /** * @brief Set the diagonal range value for a stick. * @param Value between 1 - 90. */ void JoyControlStick::setDiagonalRange(int value) { if (value < 1) { value = 1; } else if (value > 90) { value = 90; } if (value != diagonalRange) { diagonalRange = value; emit diagonalRangeChanged(value); emit propertyUpdated(); } } /** * @brief Delete old stick direction buttons and create new stick direction * buttons. */ void JoyControlStick::refreshButtons() { deleteButtons(); populateButtons(); } /** * @brief Delete stick direction buttons and stick modifier button. */ void JoyControlStick::deleteButtons() { QHashIterator iter(buttons); while (iter.hasNext()) { JoyButton *button = iter.next().value(); if (button) { delete button; button = 0; } } buttons.clear(); if (modifierButton) { delete modifierButton; modifierButton = 0; } } /** * @brief Take a XML stream and set the stick and direction button properties * according to the values contained within the stream. * @param QXmlStreamReader instance that will be used to read property values. */ void JoyControlStick::readConfig(QXmlStreamReader *xml) { if (xml->isStartElement() && xml->name() == "stick") { xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "stick")) { if (xml->name() == "deadZone" && xml->isStartElement()) { QString temptext = xml->readElementText(); int tempchoice = temptext.toInt(); this->setDeadZone(tempchoice); } else if (xml->name() == "maxZone" && xml->isStartElement()) { QString temptext = xml->readElementText(); int tempchoice = temptext.toInt(); this->setMaxZone(tempchoice); } else if (xml->name() == "diagonalRange" && xml->isStartElement()) { QString temptext = xml->readElementText(); int tempchoice = temptext.toInt(); this->setDiagonalRange(tempchoice); } else if (xml->name() == "mode" && xml->isStartElement()) { QString temptext = xml->readElementText(); if (temptext == "eight-way") { this->setJoyMode(EightWayMode); } else if (temptext == "four-way") { this->setJoyMode(FourWayCardinal); } else if (temptext == "diagonal") { this->setJoyMode(FourWayDiagonal); } } else if (xml->name() == "squareStick" && xml->isStartElement()) { QString temptext = xml->readElementText(); int tempchoice = temptext.toInt(); if (tempchoice > 0 && tempchoice <= 100) { this->setCircleAdjust(tempchoice / 100.0); } } else if (xml->name() == JoyControlStickButton::xmlName && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); JoyControlStickButton *button = buttons.value((JoyStickDirections)index); if (button) { button->readConfig(xml); } else { xml->skipCurrentElement(); } } else if (xml->name() == JoyControlStickModifierButton::xmlName && xml->isStartElement()) { modifierButton->readConfig(xml); } else if (xml->name() == "stickDelay" && xml->isStartElement()) { QString temptext = xml->readElementText(); int tempchoice = temptext.toInt(); this->setStickDelay(tempchoice); } else { xml->skipCurrentElement(); } xml->readNextStartElement(); } } } /** * @brief Write the status of the properties of a stick and direction buttons * to an XML stream. * @param QXmlStreamWriter instance that will be used to write a profile. */ void JoyControlStick::writeConfig(QXmlStreamWriter *xml) { if (!isDefault()) { xml->writeStartElement("stick"); xml->writeAttribute("index", QString::number(index+1)); if (deadZone != DEFAULTDEADZONE) { xml->writeTextElement("deadZone", QString::number(deadZone)); } if (maxZone != DEFAULTMAXZONE) { xml->writeTextElement("maxZone", QString::number(maxZone)); } if (currentMode == StandardMode || currentMode == EightWayMode) { if (diagonalRange != DEFAULTDIAGONALRANGE) { xml->writeTextElement("diagonalRange", QString::number(diagonalRange)); } } if (currentMode == EightWayMode) { xml->writeTextElement("mode", "eight-way"); } else if (currentMode == FourWayCardinal) { xml->writeTextElement("mode", "four-way"); } else if (currentMode == FourWayDiagonal) { xml->writeTextElement("mode", "diagonal"); } if (circle > DEFAULTCIRCLE) { xml->writeTextElement("squareStick", QString::number(circle * 100)); } if (stickDelay > DEFAULTSTICKDELAY) { xml->writeTextElement("stickDelay", QString::number(stickDelay)); } QHashIterator iter(buttons); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); button->writeConfig(xml); } if (!modifierButton->isDefault()) { modifierButton->writeConfig(xml); } xml->writeEndElement(); } } /** * @brief Reset all the properties of the stick direction buttons and the * stick modifier button. */ void JoyControlStick::resetButtons() { QHashIterator iter(buttons); while (iter.hasNext()) { JoyButton *button = iter.next().value(); if (button) { button->reset(); } } if (modifierButton) { modifierButton->reset(); } } /** * @brief Get a pointer to the stick direction button for the desired * direction. * @param Value of the direction of the stick. * @return Pointer to the stick direction button for the stick * direction. */ JoyControlStickButton* JoyControlStick::getDirectionButton(JoyStickDirections direction) { JoyControlStickButton *button = buttons.value(direction); return button; } /** * @brief Used to calculate the distance value that should be used for mouse * movement. * @param button * @return Distance factor that should be used for mouse movement */ double JoyControlStick::calculateMouseDirectionalDistance(JoyControlStickButton *button) { double finalDistance = 0.0; if (currentDirection == StickUp) { finalDistance = calculateYDistanceFromDeadZone(true); } else if (currentDirection == StickRightUp) { if (activeButton1 && activeButton1 == button) { finalDistance = calculateXDistanceFromDeadZone(true); } else if (activeButton2 && activeButton2 == button) { finalDistance = calculateYDistanceFromDeadZone(true); } else if (activeButton3 && activeButton3 == button) { finalDistance = calculateEightWayDiagonalDistanceFromDeadZone(); } } else if (currentDirection == StickRight) { finalDistance = calculateXDistanceFromDeadZone(true); } else if (currentDirection == StickRightDown) { if (activeButton1 && activeButton1 == button) { finalDistance = calculateXDistanceFromDeadZone(true); } else if (activeButton2 && activeButton2 == button) { finalDistance = calculateYDistanceFromDeadZone(true); } else if (activeButton3 && activeButton3 == button) { finalDistance = calculateEightWayDiagonalDistanceFromDeadZone(); } } else if (currentDirection == StickDown) { finalDistance = calculateYDistanceFromDeadZone(true); } else if (currentDirection == StickLeftDown) { if (activeButton1 && activeButton1 == button) { finalDistance = calculateXDistanceFromDeadZone(true); } else if (activeButton2 && activeButton2 == button) { finalDistance = calculateYDistanceFromDeadZone(true); } else if (activeButton3 && activeButton3 == button) { finalDistance = calculateEightWayDiagonalDistanceFromDeadZone(); } } else if (currentDirection == StickLeft) { finalDistance = calculateXDistanceFromDeadZone(true); } else if (currentDirection == StickLeftUp) { if (activeButton1 && activeButton1 == button) { finalDistance = calculateXDistanceFromDeadZone(true); } else if (activeButton2 && activeButton2 == button) { finalDistance = calculateYDistanceFromDeadZone(true); } else if (activeButton3 && activeButton3 == button) { finalDistance = calculateEightWayDiagonalDistanceFromDeadZone(); } } return finalDistance; } double JoyControlStick::calculateLastMouseDirectionalDistance(JoyControlStickButton *button) { double finalDistance = 0.0; JoyStickDirections direction = calculateStickDirection(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue()); if (direction == StickUp && button->getJoyNumber() == StickUp) { if (axisY->getLastKnownThrottleValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateYDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue(), true); } } else if (direction == StickRightUp) { if (button->getJoyNumber() == StickRight) { if (axisX->getLastKnownThrottleValue() < 0) { finalDistance = 0.0; } else { finalDistance = calculateXDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue(), true); } } else if (button->getJoyNumber() == StickUp) { if (axisY->getLastKnownThrottleValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateYDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue(), true); } } else if (button->getJoyNumber() == StickRightUp) { if (axisX->getLastKnownThrottleValue() <= 0 || axisY->getLastKnownThrottleValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateEightWayDiagonalDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue()); } } } else if (direction == StickRight && button->getJoyNumber() == StickRight) { if (axisX->getLastKnownThrottleValue() < 0) { finalDistance = 0.0; } else { finalDistance = calculateXDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue(), true); } } else if (direction == StickRightDown) { if (button->getJoyNumber() == StickRight) { if (axisX->getLastKnownThrottleValue() < 0) { finalDistance = 0.0; } else { finalDistance = calculateXDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue(), true); } } else if (button->getJoyNumber() == StickDown) { if (axisY->getLastKnownThrottleValue() < 0) { finalDistance = 0.0; } else { finalDistance = calculateYDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue(), true); } } else if (button->getJoyNumber() == StickRightDown) { if (axisX->getLastKnownThrottleValue() <= 0 || axisY->getLastKnownThrottleValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateEightWayDiagonalDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue()); } } } else if (direction == StickDown && button->getJoyNumber() == StickDown) { if (axisY->getLastKnownThrottleValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateYDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue(), true); } } else if (direction == StickLeftDown) { if (button->getJoyNumber() == StickLeft) { if (axisX->getLastKnownThrottleValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateXDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue(), true); } } else if (button->getJoyNumber() == StickDown) { if (axisY->getLastKnownThrottleValue() < 0) { finalDistance = 0.0; } else { finalDistance = calculateYDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue(), true); } } else if (button->getJoyNumber() == StickLeftDown) { if (axisX->getLastKnownThrottleValue() >= 0 || axisY->getLastKnownThrottleValue() <= 0) { finalDistance = 0.0; } else { finalDistance = calculateEightWayDiagonalDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue()); } } } else if (direction == StickLeft && button->getJoyNumber() == StickLeft) { if (axisX->getLastKnownThrottleValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateXDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue(), true); } } else if (direction == StickLeftUp) { if (button->getJoyNumber() == StickLeft) { if (axisX->getLastKnownThrottleValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateXDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue(), true); } } else if (button->getJoyNumber() == StickUp) { if (axisY->getLastKnownThrottleValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateYDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue(), true); } } else if (button->getJoyNumber() == StickLeftUp) { if (axisX->getLastKnownThrottleValue() >= 0 || axisY->getLastKnownThrottleValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateEightWayDiagonalDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue()); } } } return finalDistance; } double JoyControlStick::calculateLastDirectionalDistance() { double finalDistance = 0.0; JoyStickDirections direction = calculateStickDirection(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue()); if (direction == StickUp) { if (!axisX->getLastKnownThrottleValue() >= 0) { finalDistance = calculateYDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue()); } } else if (direction == StickRightUp) { if (!axisY->getLastKnownThrottleValue() <= 0 && !axisY->getLastKnownThrottleValue() >= 0) { finalDistance = calculateEightWayDiagonalDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue()); } } else if (direction == StickRight) { if (!axisX->getLastKnownThrottleValue() <= 0) { finalDistance = calculateXDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue()); } } else if (direction == StickRightDown) { if (!axisY->getLastKnownThrottleValue() <= 0 && !axisY->getLastKnownThrottleValue() <= 0) { finalDistance = calculateEightWayDiagonalDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue()); } } else if (direction == StickDown) { if (!axisY->getLastKnownThrottleValue() <= 0) { finalDistance = calculateYDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue()); } } else if (direction == StickLeftDown) { if (!axisY->getLastKnownThrottleValue() >= 0 && !axisY->getLastKnownThrottleValue() <= 0) { finalDistance = calculateEightWayDiagonalDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue()); } } else if (direction == StickLeft) { if (!axisX->getLastKnownThrottleValue() >= 0) { finalDistance = calculateXDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue()); } } else if (direction == StickLeftUp) { if (!axisY->getLastKnownThrottleValue() >= 0 && !axisY->getLastKnownThrottleValue() >= 0) { finalDistance = calculateEightWayDiagonalDistanceFromDeadZone(axisX->getLastKnownThrottleValue(), axisY->getLastKnownThrottleValue()); } } return finalDistance; } double JoyControlStick::calculateLastAccelerationDirectionalDistance() { double finalDistance = 0.0; if (currentDirection == StickUp) { if (!axisX->getLastKnownRawValue() >= 0) { finalDistance = calculateYAxisDistance(axisY->getLastKnownRawValue()); } } else if (currentDirection == StickRightUp) { if (!axisY->getLastKnownRawValue() <= 0 && !axisY->getLastKnownRawValue() >= 0) { finalDistance = calculateEightWayDiagonalDistance(axisX->getLastKnownRawValue(), axisY->getLastKnownRawValue()); } } else if (currentDirection == StickRight) { if (!axisX->getLastKnownRawValue() <= 0) { finalDistance = calculateXAxisDistance(axisX->getLastKnownRawValue()); } } else if (currentDirection == StickRightDown) { if (!axisY->getLastKnownRawValue() <= 0 && !axisY->getLastKnownRawValue() <= 0) { finalDistance = calculateEightWayDiagonalDistance(axisX->getLastKnownRawValue(), axisY->getLastKnownRawValue()); } } else if (currentDirection == StickDown) { if (!axisY->getLastKnownRawValue() <= 0) { finalDistance = calculateYAxisDistance(axisY->getLastKnownRawValue()); } } else if (currentDirection == StickLeftDown) { if (!axisY->getLastKnownRawValue() >= 0 && !axisY->getLastKnownRawValue() <= 0) { finalDistance = calculateEightWayDiagonalDistance(axisX->getLastKnownRawValue(), axisY->getLastKnownRawValue()); } } else if (currentDirection == StickLeft) { if (!axisX->getLastKnownRawValue() >= 0) { finalDistance = calculateXAxisDistance(axisX->getLastKnownRawValue()); } } else if (currentDirection == StickLeftUp) { if (!axisY->getLastKnownRawValue() >= 0 && !axisY->getLastKnownRawValue() >= 0) { finalDistance = calculateEightWayDiagonalDistance(axisX->getLastKnownRawValue(), axisY->getLastKnownRawValue()); } } return finalDistance; } /** * @brief Used to calculate the distance value that should be used for keyboard * events and distance slots * @return Distance factor that should be used for keyboard events and * distance slots */ double JoyControlStick::calculateDirectionalDistance() { double finalDistance = 0.0; if (currentDirection == StickUp) { finalDistance = calculateYDistanceFromDeadZone(); } else if (currentDirection == StickRightUp) { finalDistance = getDistanceFromDeadZone(); } else if (currentDirection == StickRight) { finalDistance = calculateXDistanceFromDeadZone(); } else if (currentDirection == StickRightDown) { finalDistance = getDistanceFromDeadZone(); } else if (currentDirection == StickDown) { finalDistance = calculateYDistanceFromDeadZone(); } else if (currentDirection == StickLeftDown) { finalDistance = getDistanceFromDeadZone(); } else if (currentDirection == StickLeft) { finalDistance = calculateXDistanceFromDeadZone(); } else if (currentDirection == StickLeftUp) { finalDistance = getDistanceFromDeadZone(); } return finalDistance; } /** * @brief Get the value for the currently active stick direction. * @return Value of the corresponding active stick direction. */ JoyControlStick::JoyStickDirections JoyControlStick::getCurrentDirection() { return currentDirection; } /** * @brief Get the value for the corresponding X axis. * @return X axis value. */ int JoyControlStick::getXCoordinate() { return axisX->getCurrentRawValue(); } /** * @brief Get the value for the corresponding Y axis. * @return Y axis value. */ int JoyControlStick::getYCoordinate() { return axisY->getCurrentRawValue(); } int JoyControlStick::getCircleXCoordinate() { int axisXValue = axisX->getCurrentRawValue(); int axisYValue = axisX->getCurrentRawValue(); if (this->circle > 0.0) { axisXValue = calculateCircleXValue(axisXValue, axisYValue); } return axisXValue; } int JoyControlStick::getCircleYCoordinate() { int axisXValue = axisX->getCurrentRawValue(); int axisYValue = axisY->getCurrentRawValue(); if (this->circle > 0.0) { axisYValue = calculateCircleYValue(axisXValue, axisYValue); } return axisYValue; } int JoyControlStick::calculateCircleXValue(int axisXValue, int axisYValue) { int value = axisXValue; if (this->circle > 0.0) { int axis1Value = axisXValue; int axis2Value = axisYValue; double angle2 = atan2(axis1Value, -axis2Value); double ang_sin = sin(angle2); double ang_cos = cos(angle2); //int axisXValueCircleFull = static_cast(floor(JoyAxis::AXISMAX * fabs(ang_sin) + 0.5)); double squareStickFull = qMin(ang_sin ? 1/fabs(ang_sin) : 2, ang_cos ? 1/fabs(ang_cos) : 2); double circle = this->circle; double circleStickFull = (squareStickFull - 1) * circle + 1; //double alternateStickFullValue = circleStickFull * abs(axisXValueCircleFull); //value = circleStickFull > 1.0 ? static_cast(floor((axisXValue / alternateStickFullValue) * abs(axisXValueCircleFull) + 0.5)) : value; value = circleStickFull > 1.0 ? static_cast(floor((axisXValue / circleStickFull) + 0.5)) : value; } return value; } int JoyControlStick::calculateCircleYValue(int axisXValue, int axisYValue) { int value = axisYValue; if (this->circle > 0.0) { int axis1Value = axisXValue; int axis2Value = axisYValue; double angle2 = atan2(axis1Value, -axis2Value); double ang_sin = sin(angle2); double ang_cos = cos(angle2); //int axisYValueCircleFull = static_cast(floor(JoyAxis::AXISMAX * fabs(ang_cos) + 0.5)); double squareStickFull = qMin(ang_sin ? 1/fabs(ang_sin) : 2, ang_cos ? 1/fabs(ang_cos) : 2); double circle = this->circle; double circleStickFull = (squareStickFull - 1) * circle + 1; //double alternateStickFullValue = circleStickFull * abs(axisYValueCircleFull); //value = circleStickFull > 1.0 ? static_cast(floor((axisYValue / alternateStickFullValue) * abs(axisYValueCircleFull) + 0.5)) : value; value = circleStickFull > 1.0 ? static_cast(floor((axisYValue / circleStickFull) + 0.5)) : value; } return value; } QList JoyControlStick::getDiagonalZoneAngles() { QList anglesList; int diagonalAngle = diagonalRange; double cardinalAngle = (360 - (diagonalAngle * 4)) / 4.0; double initialLeft = 360 - ((cardinalAngle) / 2.0); double initialRight = ((cardinalAngle)/ 2.0); /*if ((int)(cardinalAngle - 1) % 2 != 0) { initialLeft = 360 - (cardinalAngle / 2.0); initialRight = (cardinalAngle / 2.0) - 1; } */ double upRightInitial = initialRight; double rightInitial = upRightInitial + diagonalAngle; double downRightInitial = rightInitial + cardinalAngle; double downInitial = downRightInitial + diagonalAngle; double downLeftInitial = downInitial + cardinalAngle; double leftInitial = downLeftInitial + diagonalAngle; double upLeftInitial = leftInitial + cardinalAngle; anglesList.append(initialLeft); anglesList.append(initialRight); anglesList.append(upRightInitial); anglesList.append(rightInitial); anglesList.append(downRightInitial); anglesList.append(downInitial); anglesList.append(downLeftInitial); anglesList.append(leftInitial); anglesList.append(upLeftInitial); return anglesList; } QList JoyControlStick::getFourWayCardinalZoneAngles() { QList anglesList; int zoneRange = 90; int rightInitial = 45; int downInitial = rightInitial + zoneRange; int leftInitial = downInitial + zoneRange; int upInitial = leftInitial + zoneRange; anglesList.append(rightInitial); anglesList.append(downInitial); anglesList.append(leftInitial); anglesList.append(upInitial); return anglesList; } QList JoyControlStick::getFourWayDiagonalZoneAngles() { QList anglesList; int zoneRange = 90; int upRightInitial = 0; int downRightInitial = zoneRange; int downLeftInitial = downRightInitial + zoneRange; int upLeftInitial = downLeftInitial + zoneRange; anglesList.append(upRightInitial); anglesList.append(downRightInitial); anglesList.append(downLeftInitial); anglesList.append(upLeftInitial); return anglesList; } QHash* JoyControlStick::getButtons() { return &buttons; } JoyAxis* JoyControlStick::getAxisX() { return axisX; } JoyAxis* JoyControlStick::getAxisY() { return axisY; } void JoyControlStick::replaceXAxis(JoyAxis *axis) { if (axis->getParentSet() == axisY->getParentSet()) { axisX->removeControlStick(); this->axisX = axis; this->axisX->setControlStick(this); } } void JoyControlStick::replaceYAxis(JoyAxis *axis) { if (axis->getParentSet() == axisX->getParentSet()) { axisY->removeControlStick(); this->axisY = axis; this->axisY->setControlStick(this); } } void JoyControlStick::replaceAxes(JoyAxis *axisX, JoyAxis *axisY) { if (axisX->getParentSet() == axisY->getParentSet()) { this->axisX->removeControlStick(); this->axisY->removeControlStick(); this->axisX = axisX; this->axisY = axisY; this->axisX->setControlStick(this); this->axisY->setControlStick(this); } } void JoyControlStick::setJoyMode(JoyMode mode) { currentMode = mode; emit joyModeChanged(); emit propertyUpdated(); } JoyControlStick::JoyMode JoyControlStick::getJoyMode() { return currentMode; } void JoyControlStick::releaseButtonEvents() { QHashIterator iter(buttons); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); button->joyEvent(false, true); } } bool JoyControlStick::isDefault() { bool value = true; value = value && (deadZone == DEFAULTDEADZONE); value = value && (maxZone == DEFAULTMAXZONE); value = value && (diagonalRange == DEFAULTDIAGONALRANGE); value = value && (currentMode == DEFAULTMODE); value = value && (circle == DEFAULTCIRCLE); value = value && (stickDelay == DEFAULTSTICKDELAY); QHashIterator iter(buttons); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); value = value && (button->isDefault()); } if (modifierButton) { value = value && modifierButton->isDefault(); } return value; } void JoyControlStick::setButtonsMouseMode(JoyButton::JoyMouseMovementMode mode) { QHashIterator iter(buttons); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); button->setMouseMode(mode); } } bool JoyControlStick::hasSameButtonsMouseMode() { bool result = true; JoyButton::JoyMouseMovementMode initialMode = JoyButton::MouseCursor; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyControlStickButton *button = iter.next().value(); initialMode = button->getMouseMode(); } else { JoyControlStickButton *button = iter.next().value(); JoyButton::JoyMouseMovementMode temp = button->getMouseMode(); if (temp != initialMode) { result = false; iter.toBack(); } } } return result; } JoyButton::JoyMouseMovementMode JoyControlStick::getButtonsPresetMouseMode() { JoyButton::JoyMouseMovementMode resultMode = JoyButton::MouseCursor; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyControlStickButton *button = iter.next().value(); resultMode = button->getMouseMode(); } else { JoyControlStickButton *button = iter.next().value(); JoyButton::JoyMouseMovementMode temp = button->getMouseMode(); if (temp != resultMode) { resultMode = JoyButton::MouseCursor; iter.toBack(); } } } return resultMode; } void JoyControlStick::setButtonsMouseCurve(JoyButton::JoyMouseCurve mouseCurve) { QHashIterator iter(buttons); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); button->setMouseCurve(mouseCurve); } } bool JoyControlStick::hasSameButtonsMouseCurve() { bool result = true; JoyButton::JoyMouseCurve initialCurve = JoyButton::LinearCurve; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyControlStickButton *button = iter.next().value(); initialCurve = button->getMouseCurve(); } else { JoyControlStickButton *button = iter.next().value(); JoyButton::JoyMouseCurve temp = button->getMouseCurve(); if (temp != initialCurve) { result = false; iter.toBack(); } } } return result; } JoyButton::JoyMouseCurve JoyControlStick::getButtonsPresetMouseCurve() { JoyButton::JoyMouseCurve resultCurve = JoyButton::LinearCurve; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyControlStickButton *button = iter.next().value(); resultCurve = button->getMouseCurve(); } else { JoyControlStickButton *button = iter.next().value(); JoyButton::JoyMouseCurve temp = button->getMouseCurve(); if (temp != resultCurve) { resultCurve = JoyButton::LinearCurve; iter.toBack(); } } } return resultCurve; } void JoyControlStick::setButtonsSpringWidth(int value) { QHashIterator iter(buttons); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); button->setSpringWidth(value); } } void JoyControlStick::setButtonsSpringHeight(int value) { QHashIterator iter(buttons); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); button->setSpringHeight(value); } } int JoyControlStick::getButtonsPresetSpringWidth() { int presetSpringWidth = 0; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyControlStickButton *button = iter.next().value(); presetSpringWidth = button->getSpringWidth(); } else { JoyControlStickButton *button = iter.next().value(); int temp = button->getSpringWidth(); if (temp != presetSpringWidth) { presetSpringWidth = 0; iter.toBack(); } } } return presetSpringWidth; } int JoyControlStick::getButtonsPresetSpringHeight() { int presetSpringHeight = 0; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyControlStickButton *button = iter.next().value(); presetSpringHeight = button->getSpringHeight(); } else { JoyControlStickButton *button = iter.next().value(); int temp = button->getSpringHeight(); if (temp != presetSpringHeight) { presetSpringHeight = 0; iter.toBack(); } } } return presetSpringHeight; } void JoyControlStick::setButtonsSensitivity(double value) { QHashIterator iter(buttons); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); button->setSensitivity(value); } } double JoyControlStick::getButtonsPresetSensitivity() { double presetSensitivity = 1.0; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyControlStickButton *button = iter.next().value(); presetSensitivity = button->getSensitivity(); } else { JoyControlStickButton *button = iter.next().value(); double temp = button->getSensitivity(); if (temp != presetSensitivity) { presetSensitivity = 1.0; iter.toBack(); } } } return presetSensitivity; } QHash JoyControlStick::getApplicableButtons() { QHash temphash; if (currentMode == StandardMode || currentMode == EightWayMode || currentMode == FourWayCardinal) { temphash.insert(StickUp, buttons.value(StickUp)); temphash.insert(StickDown, buttons.value(StickDown)); temphash.insert(StickLeft, buttons.value(StickLeft)); temphash.insert(StickRight, buttons.value(StickRight)); } if (currentMode == EightWayMode || currentMode == FourWayDiagonal) { temphash.insert(StickLeftUp, buttons.value(StickLeftUp)); temphash.insert(StickRightUp, buttons.value(StickRightUp)); temphash.insert(StickRightDown, buttons.value(StickRightDown)); temphash.insert(StickLeftDown, buttons.value(StickLeftDown)); } return temphash; } void JoyControlStick::setStickName(QString tempName) { if (tempName.length() <= 20 && tempName != stickName) { stickName = tempName; emit stickNameChanged(); emit propertyUpdated(); } } QString JoyControlStick::getStickName() { return stickName; } void JoyControlStick::setButtonsWheelSpeedX(int value) { QHashIterator iter(buttons); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); button->setWheelSpeedX(value); } } void JoyControlStick::setButtonsWheelSpeedY(int value) { QHashIterator iter(buttons); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); button->setWheelSpeedY(value); } } /** * @brief Get pointer to the set that a stick belongs to. * @return Pointer to the set that a stick belongs to. */ SetJoystick* JoyControlStick::getParentSet() { SetJoystick *temp = 0; if (axisX) { temp = axisX->getParentSet(); } else if (axisY) { temp = axisY->getParentSet(); } return temp; } /** * @brief Activate a stick direction button. * @param Stick direction button that will be activated. * @param [out] Pointer to the currently active button. * @param Should set changing routines be ignored. */ void JoyControlStick::performButtonPress(JoyControlStickButton *eventbutton, JoyControlStickButton *&activebutton, bool ignoresets) { activebutton = eventbutton; eventbutton->joyEvent(true, ignoresets); } /** * @brief Stick direction button to release. * @param Stick direction button that will be released. * @param Should set changing routines be ignored. */ void JoyControlStick::performButtonRelease(JoyControlStickButton *&eventbutton, bool ignoresets) { eventbutton->joyEvent(false, ignoresets); eventbutton = 0; } /** * @brief Determine which stick direction buttons should be active for a * standard mode stick. * @param [out] Pointer to an X axis stick direction button that should be active. * @param [out] Pointer to a Y axis stick direction button that should be active. */ void JoyControlStick::determineStandardModeEvent(JoyControlStickButton *&eventbutton1, JoyControlStickButton *&eventbutton2) { double bearing = calculateBearing(); QList anglesList = getDiagonalZoneAngles(); double initialLeft = anglesList.value(0); double initialRight = anglesList.value(1); double upRightInitial = anglesList.value(2); double rightInitial = anglesList.value(3); double downRightInitial = anglesList.value(4); double downInitial = anglesList.value(5); double downLeftInitial = anglesList.value(6); double leftInitial = anglesList.value(7); double upLeftInitial = anglesList.value(8); //bearing = floor(bearing + 0.5); if (bearing <= initialRight || bearing >= initialLeft) { currentDirection = StickUp; eventbutton2 = buttons.value(StickUp); } else if (bearing >= upRightInitial && bearing < rightInitial) { currentDirection = StickRightUp; eventbutton1 = buttons.value(StickRight); eventbutton2 = buttons.value(StickUp); } else if (bearing >= rightInitial && bearing < downRightInitial) { currentDirection = StickRight; eventbutton1 = buttons.value(StickRight); } else if (bearing >= downRightInitial && bearing < downInitial) { currentDirection = StickRightDown; eventbutton1 = buttons.value(StickRight); eventbutton2 = buttons.value(StickDown); } else if (bearing >= downInitial && bearing < downLeftInitial) { currentDirection = StickDown; eventbutton2 = buttons.value(StickDown); } else if (bearing >= downLeftInitial && bearing < leftInitial) { currentDirection = StickLeftDown; eventbutton1 = buttons.value(StickLeft); eventbutton2 = buttons.value(StickDown); } else if (bearing >= leftInitial && bearing < upLeftInitial) { currentDirection = StickLeft; eventbutton1 = buttons.value(StickLeft); } else if (bearing >= upLeftInitial && bearing < initialLeft) { currentDirection = StickLeftUp; eventbutton1 = buttons.value(StickLeft); eventbutton2 = buttons.value(StickUp); } } /** * @brief Determine which stick direction button should be active for a 8 way * mode stick. * @param [out] Pointer to an X axis stick direction button that should be active. * @param [out] Pointer to a Y axis stick direction button that should be active. * @param [out] Pointer to a diagonal stick direction button that should be active. */ void JoyControlStick::determineEightWayModeEvent(JoyControlStickButton *&eventbutton1, JoyControlStickButton *&eventbutton2, JoyControlStickButton *&eventbutton3) { double bearing = calculateBearing(); QList anglesList = getDiagonalZoneAngles(); double initialLeft = anglesList.value(0); double initialRight = anglesList.value(1); double upRightInitial = anglesList.value(2); double rightInitial = anglesList.value(3); double downRightInitial = anglesList.value(4); double downInitial = anglesList.value(5); double downLeftInitial = anglesList.value(6); double leftInitial = anglesList.value(7); double upLeftInitial = anglesList.value(8); //bearing = floor(bearing + 0.5); if (bearing <= initialRight || bearing >= initialLeft) { currentDirection = StickUp; eventbutton2 = buttons.value(StickUp); } else if (bearing >= upRightInitial && bearing < rightInitial) { currentDirection = StickRightUp; eventbutton3 = buttons.value(StickRightUp); } else if (bearing >= rightInitial && bearing < downRightInitial) { currentDirection = StickRight; eventbutton1 = buttons.value(StickRight); } else if (bearing >= downRightInitial && bearing < downInitial) { currentDirection = StickRightDown; eventbutton3 = buttons.value(StickRightDown); } else if (bearing >= downInitial && bearing < downLeftInitial) { currentDirection = StickDown; eventbutton2 = buttons.value(StickDown); } else if (bearing >= downLeftInitial && bearing < leftInitial) { currentDirection = StickLeftDown; eventbutton3 = buttons.value(StickLeftDown); } else if (bearing >= leftInitial && bearing < upLeftInitial) { currentDirection = StickLeft; eventbutton1 = buttons.value(StickLeft); } else if (bearing >= upLeftInitial && bearing < initialLeft) { currentDirection = StickLeftUp; eventbutton3 = buttons.value(StickLeftUp); } } /** * @brief Determine which cardinal stick direction button should be active * when using a four way cardinal stick. * @param [out] Pointer to an X axis stick direction button that should be active. * @param [out] Pointer to a Y axis stick direction button that should be active. */ void JoyControlStick::determineFourWayCardinalEvent(JoyControlStickButton *&eventbutton1, JoyControlStickButton *&eventbutton2) { double bearing = calculateBearing(); QList anglesList = getFourWayCardinalZoneAngles(); int rightInitial = anglesList.value(0); int downInitial = anglesList.value(1); int leftInitial = anglesList.value(2); int upInitial = anglesList.value(3); //bearing = floor(bearing + 0.5); if (bearing < rightInitial || bearing >= upInitial) { currentDirection = StickUp; eventbutton2 = buttons.value(StickUp); } else if (bearing >= rightInitial && bearing < downInitial) { currentDirection = StickRight; eventbutton1 = buttons.value(StickRight); } else if (bearing >= downInitial && bearing < leftInitial) { currentDirection = StickDown; eventbutton2 = buttons.value(StickDown); } else if (bearing >= leftInitial && bearing < upInitial) { currentDirection = StickLeft; eventbutton1 = buttons.value(StickLeft); } } /** * @brief Determine which stick direction button should be active when using 4 way * diagonal mode. * @param [out] pointer to a diagonal stick direction button that should be active. */ void JoyControlStick::determineFourWayDiagonalEvent(JoyControlStickButton *&eventbutton3) { double bearing = calculateBearing(); QList anglesList = getFourWayDiagonalZoneAngles(); int upRightInitial = anglesList.value(0); int downRightInitial = anglesList.value(1); int downLeftInitial = anglesList.value(2); int upLeftInitial = anglesList.value(3); //bearing = floor(bearing + 0.5); if (bearing >= upRightInitial && bearing < downRightInitial) { currentDirection = StickRightUp; eventbutton3 = buttons.value(StickRightUp); } else if (bearing >= downRightInitial && bearing < downLeftInitial) { currentDirection = StickRightDown; eventbutton3 = buttons.value(StickRightDown); } else if (bearing >= downLeftInitial && bearing < upLeftInitial) { currentDirection = StickLeftDown; eventbutton3 = buttons.value(StickLeftDown); } else if (bearing >= upLeftInitial) { currentDirection = StickLeftUp; eventbutton3 = buttons.value(StickLeftUp); } } /** * @brief Find the current stick direction based on a Standard mode stick. * @return Current direction the stick is positioned. */ JoyControlStick::JoyStickDirections JoyControlStick::determineStandardModeDirection() { return determineStandardModeDirection(axisX->getCurrentRawValue(), axisY->getCurrentRawValue()); } JoyControlStick::JoyStickDirections JoyControlStick::determineStandardModeDirection(int axisXValue, int axisYValue) { JoyStickDirections result = StickCentered; double bearing = calculateBearing(axisXValue, axisYValue); //bearing = floor(bearing + 0.5); QList anglesList = getDiagonalZoneAngles(); int initialLeft = anglesList.value(0); int initialRight = anglesList.value(1); int upRightInitial = anglesList.value(2); int rightInitial = anglesList.value(3); int downRightInitial = anglesList.value(4); int downInitial = anglesList.value(5); int downLeftInitial = anglesList.value(6); int leftInitial = anglesList.value(7); int upLeftInitial = anglesList.value(8); if (bearing <= initialRight || bearing >= initialLeft) { result = StickUp; } else if (bearing >= upRightInitial && bearing < rightInitial) { result = StickRightUp; } else if (bearing >= rightInitial && bearing < downRightInitial) { result = StickRight; } else if (bearing >= downRightInitial && bearing < downInitial) { result = StickRightDown; } else if (bearing >= downInitial && bearing < downLeftInitial) { result = StickDown; } else if (bearing >= downLeftInitial && bearing < leftInitial) { result = StickLeftDown; } else if (bearing >= leftInitial && bearing < upLeftInitial) { result = StickLeft; } else if (bearing >= upLeftInitial && bearing < initialLeft) { result = StickLeftUp; } return result; } /** * @brief Find the current stick direction based on a Eight Way mode stick. * @return Current direction the stick is positioned. */ JoyControlStick::JoyStickDirections JoyControlStick::determineEightWayModeDirection() { return determineStandardModeDirection(axisX->getCurrentRawValue(), axisY->getCurrentRawValue()); } JoyControlStick::JoyStickDirections JoyControlStick::determineEightWayModeDirection(int axisXValue, int axisYValue) { return determineStandardModeDirection(axisXValue, axisYValue); } /** * @brief Find the current stick direction based on a Four Way Cardinal mode * stick. * @return Current direction the stick is positioned. */ JoyControlStick::JoyStickDirections JoyControlStick::determineFourWayCardinalDirection() { return determineFourWayCardinalDirection(axisX->getCurrentRawValue(), axisY->getCurrentRawValue()); } JoyControlStick::JoyStickDirections JoyControlStick::determineFourWayCardinalDirection(int axisXValue, int axisYValue) { JoyStickDirections result = StickCentered; double bearing = calculateBearing(axisXValue, axisYValue); //bearing = floor(bearing + 0.5); QList anglesList = getFourWayCardinalZoneAngles(); int rightInitial = anglesList.value(0); int downInitial = anglesList.value(1); int leftInitial = anglesList.value(2); int upInitial = anglesList.value(3); if (bearing < rightInitial || bearing >= upInitial) { result = StickUp; } else if (bearing >= rightInitial && bearing < downInitial) { result = StickRight; } else if (bearing >= downInitial && bearing < leftInitial) { result = StickDown; } else if (bearing >= leftInitial && bearing < upInitial) { result = StickLeft; } return result; } /** * @brief Find the current stick direction based on a Four Way Diagonal mode * stick. * @return Current direction the stick is positioned. */ JoyControlStick::JoyStickDirections JoyControlStick::determineFourWayDiagonalDirection() { return determineFourWayDiagonalDirection(axisX->getCurrentRawValue(), axisY->getCurrentRawValue()); } JoyControlStick::JoyStickDirections JoyControlStick::determineFourWayDiagonalDirection(int axisXValue, int axisYValue) { JoyStickDirections result = StickCentered; double bearing = calculateBearing(axisXValue, axisYValue); //bearing = floor(bearing + 0.5); QList anglesList = getFourWayDiagonalZoneAngles(); int upRightInitial = anglesList.value(0); int downRightInitial = anglesList.value(1); int downLeftInitial = anglesList.value(2); int upLeftInitial = anglesList.value(3); if (bearing >= upRightInitial && bearing < downRightInitial) { result = StickRightUp; } else if (bearing >= downRightInitial && bearing < downLeftInitial) { result = StickRightDown; } else if (bearing >= downLeftInitial && bearing < upLeftInitial) { result = StickLeftDown; } else if (bearing >= upLeftInitial) { result = StickLeftUp; } return result; } /** * @brief Calculate the current direction of the stick based on the values * of the X and Y axes and the current mode of the stick. * @return Current direction the stick is positioned. */ JoyControlStick::JoyStickDirections JoyControlStick::calculateStickDirection() { return calculateStickDirection(axisX->getCurrentRawValue(), axisY->getCurrentRawValue()); } JoyControlStick::JoyStickDirections JoyControlStick::calculateStickDirection(int axisXValue, int axisYValue) { JoyStickDirections result = StickCentered; if (currentMode == StandardMode) { result = determineStandardModeDirection(axisXValue, axisYValue); } else if (currentMode == EightWayMode) { result = determineEightWayModeDirection(axisXValue, axisYValue); } else if (currentMode == FourWayCardinal) { result = determineFourWayCardinalDirection(axisXValue, axisYValue); } else if (currentMode == FourWayDiagonal) { result = determineFourWayDiagonalDirection(axisXValue, axisYValue); } return result; } void JoyControlStick::establishPropertyUpdatedConnection() { connect(this, SIGNAL(propertyUpdated()), getParentSet()->getInputDevice(), SLOT(profileEdited())); } void JoyControlStick::disconnectPropertyUpdatedConnection() { disconnect(this, SIGNAL(propertyUpdated()), getParentSet()->getInputDevice(), SLOT(profileEdited())); } /** * @brief Check all stick buttons and see if any have slots assigned. * @return Status of whether any stick button has a slot assigned. */ bool JoyControlStick::hasSlotsAssigned() { bool hasSlots = false; QHashIterator iter(buttons); while (iter.hasNext()) { JoyButton *button = iter.next().value(); if (button) { if (button->getAssignedSlots()->count() > 0) { hasSlots = true; iter.toBack(); } } } return hasSlots; } void JoyControlStick::setButtonsSpringRelativeStatus(bool value) { QHashIterator iter(buttons); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); button->setSpringRelativeStatus(value); } } bool JoyControlStick::isRelativeSpring() { bool relative = false; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyControlStickButton *button = iter.next().value(); relative = button->isRelativeSpring(); } else { JoyControlStickButton *button = iter.next().value(); bool temp = button->isRelativeSpring(); if (temp != relative) { relative = false; iter.toBack(); } } } return relative; } /** * @brief Copy slots from all stick buttons and properties from a stick * onto another. * @param JoyControlStick object to be modified. */ void JoyControlStick::copyAssignments(JoyControlStick *destStick) { destStick->reset(); destStick->deadZone = deadZone; destStick->maxZone = maxZone; destStick->diagonalRange = diagonalRange; destStick->currentDirection = currentDirection; destStick->currentMode = currentMode; destStick->stickName = stickName; destStick->circle = circle; destStick->stickDelay = stickDelay; QHashIterator iter(destStick->buttons); while (iter.hasNext()) { JoyControlStickButton *destButton = iter.next().value(); if (destButton) { JoyControlStickButton *sourceButton = buttons.value(destButton->getDirection()); if (sourceButton) { sourceButton->copyAssignments(destButton); } } } JoyControlStickModifierButton *destModifierButton = destStick->getModifierButton(); if (modifierButton && destModifierButton) { modifierButton->copyAssignments(destModifierButton); } if (!destStick->isDefault()) { emit propertyUpdated(); } } /** * @brief Set the percentage of the outer square that should be ignored * when performing the final axis calculations. * @param Percentage represented by the range of 0.0 - 1.0. */ void JoyControlStick::setCircleAdjust(double circle) { if (circle >= 0.0 && circle <= 1.0) { this->circle = circle; emit circleAdjustChange(circle); emit propertyUpdated(); } } /** * @brief Get the current percentage of the outer square that should be ignored * when performing the final axis calculations. * @return Percentage represented by the range of 0.0 - 1.0. */ double JoyControlStick::getCircleAdjust() { return circle; } /** * @brief Slot called when directionDelayTimer has timed out. The method will * call createDeskEvent. */ void JoyControlStick::stickDirectionChangeEvent() { createDeskEvent(); } void JoyControlStick::setStickDelay(int value) { if ((value >= 10 && value <= 1000) || (value == 0)) { this->stickDelay = value; emit stickDelayChanged(value); emit propertyUpdated(); } } unsigned int JoyControlStick::getStickDelay() { return stickDelay; } void JoyControlStick::setButtonsEasingDuration(double value) { QHashIterator iter(buttons); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); button->setEasingDuration(value); } } double JoyControlStick::getButtonsEasingDuration() { double result = JoyButton::DEFAULTEASINGDURATION; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyControlStickButton *button = iter.next().value(); result = button->getEasingDuration(); } else { JoyControlStickButton *button = iter.next().value(); double temp = button->getEasingDuration(); if (temp != result) { result = JoyButton::DEFAULTEASINGDURATION; iter.toBack(); } } } return result; } JoyControlStickModifierButton *JoyControlStick::getModifierButton() { return modifierButton; } void JoyControlStick::queueJoyEvent(bool ignoresets) { Q_UNUSED(ignoresets); pendingStickEvent = true; } bool JoyControlStick::hasPendingEvent() { return pendingStickEvent; } void JoyControlStick::activatePendingEvent() { if (pendingStickEvent) { bool ignoresets = false; joyEvent(ignoresets); pendingStickEvent = false; } } void JoyControlStick::clearPendingEvent() { pendingStickEvent = false; } void JoyControlStick::setButtonsExtraAccelerationStatus(bool enabled) { QHashIterator iter(getApplicableButtons()); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); if (button) { button->setExtraAccelerationStatus(enabled); } } } bool JoyControlStick::getButtonsExtraAccelerationStatus() { bool result = false; QHashIterator iter(getApplicableButtons()); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); if (button) { bool temp = button->isExtraAccelerationEnabled(); if (!temp) { result = false; iter.toBack(); } else { result = temp; } } } return result; } void JoyControlStick::setButtonsExtraAccelerationMultiplier(double value) { QHashIterator iter(getApplicableButtons()); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); if (button) { button->setExtraAccelerationMultiplier(value); } } } double JoyControlStick::getButtonsExtraAccelerationMultiplier() { double result = JoyButton::DEFAULTEXTRACCELVALUE; QHashIterator iter(getApplicableButtons()); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyControlStickButton *button = iter.next().value(); if (button) { result = button->getExtraAccelerationMultiplier(); } } else { JoyControlStickButton *button = iter.next().value(); if (button) { double temp = button->getExtraAccelerationMultiplier(); if (temp != result) { result = JoyButton::DEFAULTEXTRACCELVALUE; iter.toBack(); } } } } return result; } void JoyControlStick::setButtonsStartAccelerationMultiplier(double value) { QHashIterator iter(getApplicableButtons()); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); if (button) { button->setStartAccelMultiplier(value); } } } double JoyControlStick::getButtonsStartAccelerationMultiplier() { double result = JoyButton::DEFAULTSTARTACCELMULTIPLIER; QHashIterator iter(getApplicableButtons()); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyControlStickButton *button = iter.next().value(); if (button) { result = button->getStartAccelMultiplier(); } } else { JoyControlStickButton *button = iter.next().value(); if (button) { double temp = button->getStartAccelMultiplier(); if (temp != result) { result = JoyButton::DEFAULTSTARTACCELMULTIPLIER; iter.toBack(); } } } } return result; } void JoyControlStick::setButtonsMinAccelerationThreshold(double value) { QHashIterator iter(getApplicableButtons()); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); if (button) { button->setMinAccelThreshold(value); } } } double JoyControlStick::getButtonsMinAccelerationThreshold() { double result = JoyButton::DEFAULTMINACCELTHRESHOLD; QHashIterator iter(getApplicableButtons()); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyControlStickButton *button = iter.next().value(); if (button) { result = button->getMinAccelThreshold(); } } else { JoyControlStickButton *button = iter.next().value(); if (button) { double temp = button->getMinAccelThreshold(); if (temp != result) { result = JoyButton::DEFAULTMINACCELTHRESHOLD; iter.toBack(); } } } } return result; } void JoyControlStick::setButtonsMaxAccelerationThreshold(double value) { QHashIterator iter(getApplicableButtons()); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); if (button) { button->setMaxAccelThreshold(value); } } } double JoyControlStick::getButtonsMaxAccelerationThreshold() { double result = JoyButton::DEFAULTMAXACCELTHRESHOLD; QHashIterator iter(getApplicableButtons()); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyControlStickButton *button = iter.next().value(); if (button) { result = button->getMaxAccelThreshold(); } } else { JoyControlStickButton *button = iter.next().value(); if (button) { double temp = button->getMaxAccelThreshold(); if (temp != result) { result = JoyButton::DEFAULTMAXACCELTHRESHOLD; iter.toBack(); } } } } return result; } void JoyControlStick::setButtonsAccelerationExtraDuration(double value) { QHashIterator iter(getApplicableButtons()); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); if (button) { button->setAccelExtraDuration(value); } } } double JoyControlStick::getButtonsAccelerationEasingDuration() { double result = JoyButton::DEFAULTACCELEASINGDURATION; QHashIterator iter(getApplicableButtons()); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyControlStickButton *button = iter.next().value(); if (button) { result = button->getAccelExtraDuration(); } } else { JoyControlStickButton *button = iter.next().value(); if (button) { double temp = button->getAccelExtraDuration(); if (temp != result) { result = JoyButton::DEFAULTACCELEASINGDURATION; iter.toBack(); } } } } return result; } void JoyControlStick::setButtonsSpringDeadCircleMultiplier(int value) { QHashIterator iter(getApplicableButtons()); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); if (button) { button->setSpringDeadCircleMultiplier(value); } } } int JoyControlStick::getButtonsSpringDeadCircleMultiplier() { int result = JoyButton::DEFAULTSPRINGRELEASERADIUS; QHashIterator iter(getApplicableButtons()); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyControlStickButton *button = iter.next().value(); if (button) { result = button->getSpringDeadCircleMultiplier(); } } else { JoyControlStickButton *button = iter.next().value(); if (button) { int temp = button->getSpringDeadCircleMultiplier(); if (temp != result) { result = JoyButton::DEFAULTSPRINGRELEASERADIUS; iter.toBack(); } } } } return result; } double JoyControlStick::calculateAccelerationDistance(JoyControlStickButton *button) { double finalDistance = 0.0; if (currentDirection == StickUp) { if (axisY->getCurrentRawValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateYAxisDistance(axisY->getCurrentRawValue()); } } else if (currentDirection == StickRightUp) { if (button->getJoyNumber() == StickRight) { if (axisX->getCurrentRawValue() < 0) { finalDistance = 0.0; } else { finalDistance = calculateXAxisDistance(axisX->getCurrentRawValue()); } } else if (button->getJoyNumber() == StickUp) { if (axisY->getCurrentRawValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateYAxisDistance(axisY->getCurrentRawValue()); } } else if (button->getJoyNumber() == StickRightUp) { if (axisX->getCurrentRawValue() <= 0 || axisY->getCurrentRawValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateEightWayDiagonalDistance(axisX->getCurrentRawValue(), axisY->getCurrentRawValue()); } } } else if (currentDirection == StickRight) { if (axisX->getCurrentRawValue() < 0) { finalDistance = 0.0; } else { finalDistance = calculateXAxisDistance(axisX->getCurrentRawValue()); } } else if (currentDirection == StickRightDown) { if (button->getJoyNumber() == StickRight) { if (axisX->getCurrentRawValue() < 0) { finalDistance = 0.0; } else { finalDistance = calculateXAxisDistance(axisX->getCurrentRawValue()); } } else if (button->getJoyNumber() == StickDown) { if (axisY->getCurrentRawValue() < 0) { finalDistance = 0.0; } else { finalDistance = calculateYAxisDistance(axisY->getCurrentRawValue()); } } else if (button->getJoyNumber() == StickRightDown) { if (axisX->getCurrentRawValue() <= 0 || axisY->getCurrentRawValue() <= 0) { finalDistance = 0.0; } else { finalDistance = calculateEightWayDiagonalDistance(axisX->getCurrentRawValue(), axisY->getCurrentRawValue()); } } } else if (currentDirection == StickDown) { if (axisY->getCurrentRawValue() <= 0) { finalDistance = 0.0; } else { finalDistance = calculateYAxisDistance(axisY->getCurrentRawValue()); } } else if (currentDirection == StickLeftDown) { if (button->getJoyNumber() == StickLeft) { if (axisX->getCurrentRawValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateXAxisDistance(axisX->getCurrentRawValue()); } } else if (button->getJoyNumber() == StickDown) { if (axisY->getCurrentRawValue() < 0) { finalDistance = 0.0; } else { finalDistance = calculateYAxisDistance(axisY->getCurrentRawValue()); } } else if (button->getJoyNumber() == StickLeftDown) { if (axisX->getCurrentRawValue() >= 0 || axisY->getCurrentRawValue() <= 0) { finalDistance = 0.0; } else { finalDistance = calculateEightWayDiagonalDistance(axisX->getCurrentRawValue(), axisY->getCurrentRawValue()); } } } else if (currentDirection == StickLeft) { if (axisX->getCurrentRawValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateXAxisDistance(axisX->getCurrentRawValue()); } } else if (currentDirection == StickLeftUp) { if (button->getJoyNumber() == StickLeft) { if (axisX->getCurrentRawValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateXAxisDistance(axisX->getCurrentRawValue()); } } else if (button->getJoyNumber() == StickUp) { if (axisY->getCurrentRawValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateYAxisDistance(axisY->getCurrentRawValue()); } } else if (button->getJoyNumber() == StickLeftUp) { if (axisX->getCurrentRawValue() >= 0 || axisY->getCurrentRawValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateEightWayDiagonalDistance(axisX->getCurrentRawValue(), axisY->getCurrentRawValue()); } } } return finalDistance; } // TODO: Maybe change method name. double JoyControlStick::calculateLastAccelerationButtonDistance(JoyControlStickButton *button) { double finalDistance = 0.0; if (currentDirection == StickUp) { if (axisY->getLastKnownRawValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateYAxisDistance(axisY->getLastKnownRawValue()); } } else if (currentDirection == StickRightUp) { if (button->getJoyNumber() == StickRight) { if (axisX->getLastKnownRawValue() <= 0) { finalDistance = 0.0; } else { finalDistance = calculateXAxisDistance(axisX->getLastKnownRawValue()); } } else if (button->getJoyNumber() == StickUp) { if (axisY->getLastKnownRawValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateYAxisDistance(axisY->getLastKnownRawValue()); } } else if (button->getJoyNumber() == StickRightUp) { if (axisX->getLastKnownRawValue() <= 0 || axisY->getLastKnownRawValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateEightWayDiagonalDistance(axisX->getLastKnownRawValue(), axisY->getLastKnownRawValue()); } } } else if (currentDirection == StickRight) { if (axisX->getLastKnownRawValue() <= 0) { finalDistance = 0.0; } else { finalDistance = calculateXAxisDistance(axisX->getLastKnownRawValue()); } } else if (currentDirection == StickRightDown) { if (button->getJoyNumber() == StickRight) { if (axisX->getLastKnownRawValue() <= 0) { finalDistance = 0.0; } else { finalDistance = calculateXAxisDistance(axisX->getLastKnownRawValue()); } } else if (button->getJoyNumber() == StickDown) { if (axisY->getLastKnownRawValue() <= 0) { finalDistance = 0.0; } else { finalDistance = calculateYAxisDistance(axisY->getLastKnownRawValue()); } } else if (button->getJoyNumber() == StickRightDown) { if (axisX->getLastKnownRawValue() <= 0 || axisY->getLastKnownRawValue() <= 0) { finalDistance = 0.0; } else { finalDistance = calculateEightWayDiagonalDistance(axisX->getLastKnownRawValue(), axisY->getLastKnownRawValue()); } } } else if (currentDirection == StickDown) { if (axisY->getLastKnownRawValue() <= 0) { finalDistance = 0.0; } else { finalDistance = calculateYAxisDistance(axisY->getLastKnownRawValue()); } } else if (currentDirection == StickLeftDown) { if (button->getJoyNumber() == StickLeft) { if (axisX->getLastKnownRawValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateXAxisDistance(axisX->getLastKnownRawValue()); } } else if (button->getJoyNumber() == StickDown) { if (axisY->getLastKnownRawValue() <= 0) { finalDistance = 0.0; } else { finalDistance = calculateYAxisDistance(axisY->getLastKnownRawValue()); } } else if (button->getJoyNumber() == StickLeftDown) { if (axisX->getLastKnownRawValue() >= 0 || axisY->getLastKnownRawValue() <= 0) { finalDistance = 0.0; } else { finalDistance = calculateEightWayDiagonalDistance(axisX->getLastKnownRawValue(), axisY->getLastKnownRawValue()); } } } else if (currentDirection == StickLeft) { if (axisX->getLastKnownRawValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateXAxisDistance(axisX->getLastKnownRawValue()); } } else if (currentDirection == StickLeftUp) { if (button->getJoyNumber() == StickLeft) { if (axisX->getLastKnownRawValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateXAxisDistance(axisX->getLastKnownRawValue()); } } else if (button->getJoyNumber() == StickUp) { if (axisY->getLastKnownRawValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateYAxisDistance(axisY->getLastKnownRawValue()); } } else if (button->getJoyNumber() == StickLeftUp) { if (axisX->getLastKnownRawValue() >= 0 || axisY->getLastKnownRawValue() >= 0) { finalDistance = 0.0; } else { finalDistance = calculateEightWayDiagonalDistance(axisX->getLastKnownRawValue(), axisY->getLastKnownRawValue()); } } } return finalDistance; } double JoyControlStick::calculateXAxisDistance(int axisXValue) { double distance = 0.0; int axis1Value = axisXValue; distance = axis1Value / (double)(maxZone); if (distance < -1.0) { distance = -1.0; } else if (distance > 1.0) { distance = 1.0; } //qDebug() << "DISTANCE: " << distance; return distance; } double JoyControlStick::calculateYAxisDistance(int axisYValue) { double distance = 0.0; int axis2Value = axisYValue; distance = axis2Value / (double)(maxZone); if (distance < -1.0) { distance = -1.0; } else if (distance > 1.0) { distance = 1.0; } return distance; } double JoyControlStick::calculateEightWayDiagonalDistanceFromDeadZone() { double temp = calculateEightWayDiagonalDistanceFromDeadZone(axisX->getCurrentRawValue(), axisY->getCurrentRawValue()); return temp; } double JoyControlStick::calculateEightWayDiagonalDistanceFromDeadZone(int axisXValue, int axisYValue) { double distance = 0.0; double radius = getDistanceFromDeadZone(axisXValue, axisYValue); double bearing = calculateBearing(axisXValue, axisYValue); int relativeBearing = static_cast(bearing) % 90; int diagonalAngle = relativeBearing; if (relativeBearing > 45) { diagonalAngle = 90 - relativeBearing; } distance = radius * (diagonalAngle / 45.0); return distance; } double JoyControlStick::calculateEightWayDiagonalDistance(int axisXValue, int axisYValue) { double distance = 0.0; double radius = getRadialDistance(axisXValue, axisYValue); double bearing = calculateBearing(axisXValue, axisYValue); int relativeBearing = static_cast(bearing) % 90; int diagonalAngle = relativeBearing; if (relativeBearing > 45) { diagonalAngle = 90 - relativeBearing; } distance = radius * (diagonalAngle / 45.0); return distance; } double JoyControlStick::calculateXDiagonalDeadZone(int axisXValue, int axisYValue) { double diagonalDeadZone = 0.0; JoyStickDirections direction = calculateStickDirection(axisXValue, axisYValue); //double angle2 = atan2(axisXValue, -axisYValue); //double ang_sin = sin(angle2); //double ang_cos = cos(angle2); //int deadX = abs((int)floor(deadZone * ang_sin + 0.5)); if (diagonalRange < 90) { if (direction == StickRightUp || direction == StickRight) { QList tempangles = getDiagonalZoneAngles(); double maxangle = tempangles.at(3); //double minangle = tempangles.at(1); double mindeadX = fabs(deadZone * cos(maxangle * PI / 180.0)); //double currentDeadX = qMax(mindeadX, static_cast(deadX)); diagonalDeadZone = mindeadX; } else if (direction == StickRightDown || direction == StickDown) { QList tempangles = getDiagonalZoneAngles(); double maxangle = tempangles.at(5); //double minangle = tempangles.at(4); double mindeadX = fabs(deadZone * cos((maxangle - 90.0) * PI / 180.0)); //double currentDeadX = qMax(mindeadX, static_cast(deadX)); diagonalDeadZone = mindeadX; } else if (direction == StickLeftDown || direction == StickLeft) { QList tempangles = getDiagonalZoneAngles(); double maxangle = tempangles.at(7); //double minangle = tempangles.at(6); double mindeadX = fabs(deadZone * cos((maxangle - 180.0) * PI / 180.0)); //double currentDeadX = qMax(mindeadX, static_cast(deadX)); diagonalDeadZone = mindeadX; } else if (direction == StickLeftUp || direction == StickUp) { QList tempangles = getDiagonalZoneAngles(); double maxangle = tempangles.at(1); //double minangle = tempangles.at(8); double mindeadX = fabs(deadZone * cos((maxangle - 270.0) * PI / 180.0)); //double currentDeadX = qMax(mindeadX, static_cast(deadX)); diagonalDeadZone = mindeadX; } else { diagonalDeadZone = 0.0; } } else { diagonalDeadZone = 0.0; } return diagonalDeadZone; } double JoyControlStick::calculateYDiagonalDeadZone(int axisXValue, int axisYValue) { double diagonalDeadZone = 0.0; JoyStickDirections direction = calculateStickDirection(axisXValue, axisYValue); //double angle2 = atan2(axisXValue, -axisYValue); //double ang_sin = sin(angle2); //double ang_cos = cos(angle2); //int deadY = abs(floor(deadZone * ang_cos + 0.5)); if (diagonalRange < 90) { if (direction == StickRightUp || direction == StickUp) { QList tempangles = getDiagonalZoneAngles(); //double maxangle = tempangles.at(3); double minangle = tempangles.at(1); double mindeadY = fabs(deadZone * sin(minangle * PI / 180.0)); //double currentDeadY = qMax(static_cast(deadY), mindeadY); diagonalDeadZone = mindeadY; } else if (direction == StickRightDown || direction == StickRight) { QList tempfuck = getDiagonalZoneAngles(); //double maxangle = tempfuck.at(5); double minangle = tempfuck.at(4); double mindeadY = fabs(deadZone * sin((minangle - 90.0) * PI / 180.0)); //double currentDeadY = qMax(static_cast(deadY), mindeadY); diagonalDeadZone = mindeadY; } else if (direction == StickLeftDown || direction == StickDown) { QList tempangles = getDiagonalZoneAngles(); //double maxangle = tempangles.at(7); double minangle = tempangles.at(6); double mindeadY = fabs(deadZone * sin((minangle - 180.0) * PI / 180.0)); //double currentDeadY = qMax(static_cast(deadY), mindeadY); diagonalDeadZone = mindeadY; } else if (direction == StickLeftUp || direction == StickLeft) { QList tempangles = getDiagonalZoneAngles(); //double maxangle = tempangles.at(1); double minangle = tempangles.at(8); double mindeadY = fabs(deadZone * sin((minangle - 270.0) * PI / 180.0)); //double currentDeadY = qMax(static_cast(deadY), mindeadY); diagonalDeadZone = mindeadY; } else { diagonalDeadZone = 0.0; } } else { diagonalDeadZone = 0.0; } return diagonalDeadZone; } double JoyControlStick::getSpringDeadCircleX() { double result = 0.0; double angle2 = 0.0; int axis1Value = 0; int axis2Value = 0; if (axisX->getCurrentRawValue() == 0 && axisY->getCurrentRawValue() == 0) { // Stick moved back to absolute center. Use previously available values // to find stick angle. angle2 = atan2(axisX->getLastKnownRawValue(), -axisY->getLastKnownRawValue()); axis1Value = axisX->getLastKnownRawValue(); axis2Value = axisY->getLastKnownRawValue(); } else { // Use current axis values to find stick angle. angle2 = atan2(axisX->getCurrentRawValue(), -axisY->getCurrentRawValue()); axis1Value = axisX->getCurrentRawValue(); axis2Value = axisY->getCurrentRawValue(); } double ang_sin = sin(angle2); double ang_cos = cos(angle2); int deadX = abs((int)floor(deadZone * ang_sin + 0.5)); double diagonalDeadX = calculateXDiagonalDeadZone(axis1Value, axis2Value); double squareStickFullPhi = qMin(ang_sin ? 1/fabs(ang_sin) : 2, ang_cos ? 1/fabs(ang_cos) : 2); double circle = this->circle; double circleStickFull = (squareStickFullPhi - 1) * circle + 1; double adjustedDeadXZone = circleStickFull > 1.0 ? (deadX / circleStickFull) : deadX; //result = adjustedDeadXZone / static_cast(deadZone); double finalDeadZoneX = adjustedDeadXZone - diagonalDeadX; double maxRange = static_cast(deadZone - diagonalDeadX); if (maxRange != 0.0) { result = finalDeadZoneX / maxRange; } return result; } double JoyControlStick::getSpringDeadCircleY() { double result = 0.0; double angle2 = 0.0; int axis1Value = 0; int axis2Value = 0; if (axisX->getCurrentRawValue() == 0 && axisY->getCurrentRawValue() == 0) { // Stick moved back to absolute center. Use previously available values // to find stick angle. angle2 = atan2(axisX->getLastKnownRawValue(), -axisY->getLastKnownRawValue()); axis1Value = axisX->getLastKnownRawValue(); axis2Value = axisY->getLastKnownRawValue(); } else { // Use current axis values to find stick angle. angle2 = atan2(axisX->getCurrentRawValue(), -axisY->getCurrentRawValue()); axis1Value = axisX->getCurrentRawValue(); axis2Value = axisY->getCurrentRawValue(); } double ang_sin = sin(angle2); double ang_cos = cos(angle2); int deadY = abs((int)floor(deadZone * ang_cos + 0.5)); double diagonalDeadY = calculateYDiagonalDeadZone(axis1Value, axis2Value); double squareStickFullPhi = qMin(ang_sin ? 1/fabs(ang_sin) : 2, ang_cos ? 1/fabs(ang_cos) : 2); double circle = this->circle; double circleStickFull = (squareStickFullPhi - 1) * circle + 1; double adjustedDeadYZone = circleStickFull > 1.0 ? (deadY / circleStickFull) : deadY; //result = adjustedDeadYZone / static_cast(deadZone); double finalDeadZoneY = adjustedDeadYZone - diagonalDeadY; double maxRange = static_cast(deadZone - diagonalDeadY); if (maxRange != 0.0) { result = finalDeadZoneY / maxRange; } return result; } void JoyControlStick::setButtonsExtraAccelCurve(JoyButton::JoyExtraAccelerationCurve curve) { QHashIterator iter(getApplicableButtons()); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); if (button) { button->setExtraAccelerationCurve(curve); } } } JoyButton::JoyExtraAccelerationCurve JoyControlStick::getButtonsExtraAccelerationCurve() { JoyButton::JoyExtraAccelerationCurve result = JoyButton::LinearAccelCurve; QHashIterator iter(getApplicableButtons()); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyControlStickButton *button = iter.next().value(); if (button) { result = button->getExtraAccelerationCurve(); } } else { JoyControlStickButton *button = iter.next().value(); if (button) { JoyButton::JoyExtraAccelerationCurve temp = button->getExtraAccelerationCurve(); if (temp != result) { result = JoyButton::LinearAccelCurve; iter.toBack(); } } } } return result; } void JoyControlStick::setDirButtonsUpdateInitAccel(JoyControlStick::JoyStickDirections direction, bool state) { QHash apphash = getButtonsForDirection(direction); QHashIterator iter(apphash); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); button->setUpdateInitAccel(state); } } QHash JoyControlStick::getButtonsForDirection(JoyControlStick::JoyStickDirections direction) { QHash temphash; if (currentMode == StandardMode) { if (direction & JoyControlStick::StickUp) { JoyControlStickButton *button = this->buttons.value(JoyControlStick::StickUp); temphash.insert(JoyControlStick::StickUp, button); } if (direction & JoyControlStick::StickRight) { JoyControlStickButton *button = this->buttons.value(JoyControlStick::StickRight); temphash.insert(JoyControlStick::StickRight, button); } if (direction & JoyControlStick::StickDown) { JoyControlStickButton *button = this->buttons.value(JoyControlStick::StickDown); temphash.insert(JoyControlStick::StickDown, button); } if (direction & JoyControlStick::StickLeft) { JoyControlStickButton *button = this->buttons.value(JoyControlStick::StickLeft); temphash.insert(JoyControlStick::StickLeft, button); } } else if (currentMode == EightWayMode) { temphash.insert(direction, buttons.value(direction)); } else if (currentMode == FourWayCardinal) { if (direction == JoyControlStick::StickUp || direction == JoyControlStick::StickDown || direction == JoyControlStick::StickLeft || direction == JoyControlStick::StickRight) { temphash.insert(direction, buttons.value(direction)); } } else if (currentMode == FourWayDiagonal) { if (direction == JoyControlStick::StickRightUp || direction == JoyControlStick::StickRightDown || direction == JoyControlStick::StickLeftDown || direction == JoyControlStick::StickLeftUp) { temphash.insert(direction, buttons.value(direction)); } } return temphash; } antimicro-2.23/src/joycontrolstick.h000066400000000000000000000252521300750276700176420ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYCONTROLSTICK_H #define JOYCONTROLSTICK_H #include #include #include #include #include #include #include "joyaxis.h" #include "joybutton.h" #include "joycontrolstickdirectionstype.h" #include "joybuttontypes/joycontrolstickbutton.h" #include "joybuttontypes/joycontrolstickmodifierbutton.h" class JoyControlStick : public QObject, public JoyStickDirectionsType { Q_OBJECT public: explicit JoyControlStick(JoyAxis *axisX, JoyAxis *axisY, int index, int originset = 0, QObject *parent = 0); ~JoyControlStick(); enum JoyMode {StandardMode=0, EightWayMode, FourWayCardinal, FourWayDiagonal}; void joyEvent(bool ignoresets=false); bool inDeadZone(); int getDeadZone(); int getDiagonalRange(); double getDistanceFromDeadZone(); double getDistanceFromDeadZone(int axisXValue, int axisYValue); double getAbsoluteRawDistance(); double getAbsoluteRawDistance(int axisXValue, int axisYValue); double getNormalizedAbsoluteDistance(); int getIndex(); void setIndex(int index); int getRealJoyIndex(); int getMaxZone(); int getCurrentlyAssignedSet(); virtual QString getName(bool forceFullFormat=false, bool displayNames=false); virtual QString getPartialName(bool forceFullFormat=false, bool displayNames=false); JoyStickDirections getCurrentDirection(); int getXCoordinate(); int getYCoordinate(); int getCircleXCoordinate(); int getCircleYCoordinate(); double calculateBearing(); double calculateBearing(int axisXValue, int axisYValue); QList getDiagonalZoneAngles(); QList getFourWayCardinalZoneAngles(); QList getFourWayDiagonalZoneAngles(); QHash* getButtons(); JoyControlStickModifierButton* getModifierButton(); JoyAxis* getAxisX(); JoyAxis* getAxisY(); void replaceXAxis(JoyAxis *axis); void replaceYAxis(JoyAxis *axis); void replaceAxes(JoyAxis *axisX, JoyAxis* axisY); JoyControlStickButton* getDirectionButton(JoyStickDirections direction); double calculateMouseDirectionalDistance(JoyControlStickButton *button); double calculateDirectionalDistance(); double calculateLastDirectionalDistance(); double calculateLastMouseDirectionalDistance(JoyControlStickButton *button); double calculateLastAccelerationButtonDistance(JoyControlStickButton *button); double calculateAccelerationDistance(JoyControlStickButton *button); double calculateXAxisDistance(int axisXValue); double calculateYAxisDistance(int axisYValue); double calculateLastAccelerationDirectionalDistance(); double getRadialDistance(int axisXValue, int axisYValue); void setJoyMode(JoyMode mode); JoyMode getJoyMode(); void setButtonsMouseMode(JoyButton::JoyMouseMovementMode mode); bool hasSameButtonsMouseMode(); JoyButton::JoyMouseMovementMode getButtonsPresetMouseMode(); void setButtonsMouseCurve(JoyButton::JoyMouseCurve mouseCurve); bool hasSameButtonsMouseCurve(); JoyButton::JoyMouseCurve getButtonsPresetMouseCurve(); void setButtonsSpringWidth(int value); int getButtonsPresetSpringWidth(); void setButtonsSpringHeight(int value); int getButtonsPresetSpringHeight(); void setButtonsSensitivity(double value); double getButtonsPresetSensitivity(); void setButtonsWheelSpeedX(int value); void setButtonsWheelSpeedY(int value); void setButtonsExtraAccelerationStatus(bool enabled); bool getButtonsExtraAccelerationStatus(); void setButtonsExtraAccelerationMultiplier(double value); double getButtonsExtraAccelerationMultiplier(); void setButtonsStartAccelerationMultiplier(double value); double getButtonsStartAccelerationMultiplier(); void setButtonsMinAccelerationThreshold(double value); double getButtonsMinAccelerationThreshold(); void setButtonsMaxAccelerationThreshold(double value); double getButtonsMaxAccelerationThreshold(); void setButtonsAccelerationExtraDuration(double value); double getButtonsAccelerationEasingDuration(); void setButtonsSpringDeadCircleMultiplier(int value); int getButtonsSpringDeadCircleMultiplier(); void setButtonsExtraAccelCurve(JoyButton::JoyExtraAccelerationCurve curve); JoyButton::JoyExtraAccelerationCurve getButtonsExtraAccelerationCurve(); void releaseButtonEvents(); QString getStickName(); virtual bool isDefault(); virtual void setDefaultStickName(QString tempname); virtual QString getDefaultStickName(); virtual void readConfig(QXmlStreamReader *xml); virtual void writeConfig(QXmlStreamWriter *xml); SetJoystick* getParentSet(); bool hasSlotsAssigned(); bool isRelativeSpring(); void copyAssignments(JoyControlStick *destStick); double getCircleAdjust(); unsigned int getStickDelay(); double getButtonsEasingDuration(); void queueJoyEvent(bool ignoresets); bool hasPendingEvent(); void activatePendingEvent(); void clearPendingEvent(); //double calculateXDistanceFromDeadZone(int axisXValue, int axisYValue, bool interpolate=false); double getSpringDeadCircleX(); double getSpringDeadCircleY(); QHash getButtonsForDirection(JoyControlStick::JoyStickDirections direction); void setDirButtonsUpdateInitAccel(JoyControlStick::JoyStickDirections direction, bool state); static const double PI; // Define default values for stick properties. static const int DEFAULTDEADZONE; static const int DEFAULTMAXZONE; static const int DEFAULTDIAGONALRANGE; static const JoyMode DEFAULTMODE; static const double DEFAULTCIRCLE; static const unsigned int DEFAULTSTICKDELAY; protected: virtual void populateButtons(); void createDeskEvent(bool ignoresets = false); void determineStandardModeEvent(JoyControlStickButton *&eventbutton1, JoyControlStickButton *&eventbutton2); void determineEightWayModeEvent(JoyControlStickButton *&eventbutton1, JoyControlStickButton *&eventbutton2, JoyControlStickButton *&eventbutton3); void determineFourWayCardinalEvent(JoyControlStickButton *&eventbutton1, JoyControlStickButton *&eventbutton2); void determineFourWayDiagonalEvent(JoyControlStickButton *&eventbutton3); JoyControlStick::JoyStickDirections determineStandardModeDirection(); JoyControlStick::JoyStickDirections determineStandardModeDirection(int axisXValue, int axisYValue); JoyControlStick::JoyStickDirections determineEightWayModeDirection(); JoyControlStick::JoyStickDirections determineEightWayModeDirection(int axisXValue, int axisYValue); JoyControlStick::JoyStickDirections determineFourWayCardinalDirection(); JoyControlStick::JoyStickDirections determineFourWayCardinalDirection(int axisXValue, int axisYValue); JoyControlStick::JoyStickDirections determineFourWayDiagonalDirection(); JoyControlStick::JoyStickDirections determineFourWayDiagonalDirection(int axisXValue, int axisYValue); JoyControlStick::JoyStickDirections calculateStickDirection(); JoyControlStick::JoyStickDirections calculateStickDirection(int axisXValue, int axisYValue); void performButtonPress(JoyControlStickButton *eventbutton, JoyControlStickButton *&activebutton, bool ignoresets); void performButtonRelease(JoyControlStickButton *&eventbutton, bool ignoresets); void refreshButtons(); void deleteButtons(); void resetButtons(); double calculateXDistanceFromDeadZone(bool interpolate=false); double calculateXDistanceFromDeadZone(int axisXValue, int axisYValue, bool interpolate=false); double calculateYDistanceFromDeadZone(bool interpolate=false); double calculateYDistanceFromDeadZone(int axisXValue, int axisYValue, bool interpolate=false); int calculateCircleXValue(int axisXValue, int axisYValue); int calculateCircleYValue(int axisXValue, int axisYValue); double calculateEightWayDiagonalDistanceFromDeadZone(); double calculateEightWayDiagonalDistanceFromDeadZone(int axisXValue, int axisYValue); double calculateEightWayDiagonalDistance(int axisXValue, int axisYValue); inline double calculateXDiagonalDeadZone(int axisXValue, int axisYValue); inline double calculateYDiagonalDeadZone(int axisXValue, int axisYValue); QHash getApplicableButtons(); void clearPendingAxisEvents(); JoyAxis *axisX; JoyAxis *axisY; int originset; int deadZone; int diagonalRange; int maxZone; bool isActive; JoyControlStickButton *activeButton1; JoyControlStickButton *activeButton2; JoyControlStickButton *activeButton3; bool safezone; int index; JoyStickDirections currentDirection; JoyMode currentMode; QString stickName; QString defaultStickName; double circle; QTimer directionDelayTimer; unsigned int stickDelay; bool pendingStickEvent; QHash buttons; JoyControlStickModifierButton *modifierButton; signals: void moved(int xaxis, int yaxis); void active(int xaxis, int yaxis); void released(int axis, int yaxis); void deadZoneChanged(int value); void diagonalRangeChanged(int value); void maxZoneChanged(int value); void circleAdjustChange(double circle); void stickDelayChanged(int value); void stickNameChanged(); void joyModeChanged(); void propertyUpdated(); public slots: void reset(); void setDeadZone(int value); void setMaxZone(int value); void setDiagonalRange(int value); void setStickName(QString tempName); void setButtonsSpringRelativeStatus(bool value); void setCircleAdjust(double circle); void setStickDelay(int value); void setButtonsEasingDuration(double value); void establishPropertyUpdatedConnection(); void disconnectPropertyUpdatedConnection(); private slots: void stickDirectionChangeEvent(); }; #endif // JOYCONTROLSTICK_H antimicro-2.23/src/joycontrolstickbuttonpushbutton.cpp000066400000000000000000000074631300750276700235710ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "joycontrolstickbuttonpushbutton.h" #include "joybuttoncontextmenu.h" #include "joycontrolstick.h" JoyControlStickButtonPushButton::JoyControlStickButtonPushButton(JoyControlStickButton *button, bool displayNames, QWidget *parent) : FlashButtonWidget(displayNames, parent) { this->button = button; refreshLabel(); enableFlashes(); tryFlash(); this->setContextMenuPolicy(Qt::CustomContextMenu); connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint&))); //connect(button, SIGNAL(slotsChanged()), this, SLOT(refreshLabel())); connect(button, SIGNAL(propertyUpdated()), this, SLOT(refreshLabel())); connect(button, SIGNAL(activeZoneChanged()), this, SLOT(refreshLabel())); connect(button->getStick()->getModifierButton(), SIGNAL(activeZoneChanged()), this, SLOT(refreshLabel())); } JoyControlStickButton* JoyControlStickButtonPushButton::getButton() { return button; } void JoyControlStickButtonPushButton::setButton(JoyControlStickButton *button) { disableFlashes(); if (this->button) { //disconnect(this->button, SIGNAL(slotsChanged()), this, SLOT(refreshLabel())); disconnect(button, SIGNAL(propertyUpdated()), this, SLOT(refreshLabel())); disconnect(this->button, SIGNAL(activeZoneChanged()), this, SLOT(refreshLabel())); } this->button = button; refreshLabel(); enableFlashes(); //connect(button, SIGNAL(slotsChanged()), this, SLOT(refreshLabel())); connect(button, SIGNAL(propertyUpdated()), this, SLOT(refreshLabel())); connect(button, SIGNAL(activeZoneChanged()), this, SLOT(refreshLabel()), Qt::QueuedConnection); } void JoyControlStickButtonPushButton::disableFlashes() { if (button) { disconnect(button, SIGNAL(clicked(int)), this, SLOT(flash())); disconnect(button, SIGNAL(released(int)), this, SLOT(unflash())); } this->unflash(); } void JoyControlStickButtonPushButton::enableFlashes() { if (button) { connect(button, SIGNAL(clicked(int)), this, SLOT(flash()), Qt::QueuedConnection); connect(button, SIGNAL(released(int)), this, SLOT(unflash()), Qt::QueuedConnection); } } /** * @brief Generate the string that will be displayed on the button * @return Display string */ QString JoyControlStickButtonPushButton::generateLabel() { QString temp; if (button) { if (!button->getActionName().isEmpty() && displayNames) { temp = button->getActionName().replace("&", "&&"); } else { temp = button->getCalculatedActiveZoneSummary().replace("&", "&&"); } } return temp; } void JoyControlStickButtonPushButton::showContextMenu(const QPoint &point) { QPoint globalPos = this->mapToGlobal(point); JoyButtonContextMenu *contextMenu = new JoyButtonContextMenu(button, this); contextMenu->buildMenu(); contextMenu->popup(globalPos); } void JoyControlStickButtonPushButton::tryFlash() { if (button->getButtonState()) { flash(); } } antimicro-2.23/src/joycontrolstickbuttonpushbutton.h000066400000000000000000000030711300750276700232250ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYCONTROLSTICKBUTTONPUSHBUTTON_H #define JOYCONTROLSTICKBUTTONPUSHBUTTON_H #include #include "flashbuttonwidget.h" #include "joybuttontypes/joycontrolstickbutton.h" class JoyControlStickButtonPushButton : public FlashButtonWidget { Q_OBJECT Q_PROPERTY(bool isflashing READ isButtonFlashing) public: explicit JoyControlStickButtonPushButton(JoyControlStickButton *button, bool displayNames, QWidget *parent = 0); JoyControlStickButton* getButton(); void setButton(JoyControlStickButton *button); void tryFlash(); protected: virtual QString generateLabel(); JoyControlStickButton *button; signals: public slots: void disableFlashes(); void enableFlashes(); private slots: void showContextMenu(const QPoint &point); }; #endif // JOYCONTROLSTICKBUTTONPUSHBUTTON_H antimicro-2.23/src/joycontrolstickcontextmenu.cpp000066400000000000000000000516641300750276700224750ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "joycontrolstickcontextmenu.h" #include "mousedialog/mousecontrolsticksettingsdialog.h" #include "antkeymapper.h" #include "inputdevice.h" #include "common.h" JoyControlStickContextMenu::JoyControlStickContextMenu(JoyControlStick *stick, QWidget *parent) : QMenu(parent), helper(stick) { this->stick = stick; helper.moveToThread(stick->thread()); connect(this, SIGNAL(aboutToHide()), this, SLOT(deleteLater())); } void JoyControlStickContextMenu::buildMenu() { QAction *action = 0; QActionGroup *presetGroup = new QActionGroup(this); int presetMode = 0; int currentPreset = getPresetIndex(); action = this->addAction(tr("Mouse (Normal)")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setStickPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("Mouse (Inverted Horizontal)")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setStickPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("Mouse (Inverted Vertical)")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setStickPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("Mouse (Inverted Horizontal + Vertical)")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setStickPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("Arrows")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setStickPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("Keys: W | A | S | D")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setStickPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("NumPad")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setStickPreset())); presetGroup->addAction(action); presetMode++; action = this->addAction(tr("None")); action->setCheckable(true); action->setChecked(currentPreset == presetMode+1); action->setData(QVariant(presetMode)); connect(action, SIGNAL(triggered()), this, SLOT(setStickPreset())); presetGroup->addAction(action); this->addSeparator(); QActionGroup *modesGroup = new QActionGroup(this); int mode = static_cast(JoyControlStick::StandardMode); action = this->addAction(tr("Standard")); action->setCheckable(true); action->setChecked(stick->getJoyMode() == JoyControlStick::StandardMode); action->setData(QVariant(mode)); connect(action, SIGNAL(triggered()), this, SLOT(setStickMode())); modesGroup->addAction(action); action = this->addAction(tr("Eight Way")); action->setCheckable(true); action->setChecked(stick->getJoyMode() == JoyControlStick::EightWayMode); mode = static_cast(JoyControlStick::EightWayMode); action->setData(QVariant(mode)); connect(action, SIGNAL(triggered()), this, SLOT(setStickMode())); modesGroup->addAction(action); action = this->addAction(tr("4 Way Cardinal")); action->setCheckable(true); action->setChecked(stick->getJoyMode() == JoyControlStick::FourWayCardinal); mode = static_cast(JoyControlStick::FourWayCardinal); action->setData(QVariant(mode)); connect(action, SIGNAL(triggered()), this, SLOT(setStickMode())); modesGroup->addAction(action); action = this->addAction(tr("4 Way Diagonal")); action->setCheckable(true); action->setChecked(stick->getJoyMode() == JoyControlStick::FourWayDiagonal); mode = static_cast(JoyControlStick::FourWayDiagonal); action->setData(QVariant(mode)); connect(action, SIGNAL(triggered()), this, SLOT(setStickMode())); modesGroup->addAction(action); this->addSeparator(); action = this->addAction(tr("Mouse Settings")); action->setCheckable(false); connect(action, SIGNAL(triggered()), this, SLOT(openMouseSettingsDialog())); } void JoyControlStickContextMenu::setStickMode() { QAction *action = static_cast(sender()); int item = action->data().toInt(); stick->setJoyMode(static_cast(item)); } void JoyControlStickContextMenu::setStickPreset() { QAction *action = static_cast(sender()); int item = action->data().toInt(); JoyButtonSlot *upButtonSlot = 0; JoyButtonSlot *downButtonSlot = 0; JoyButtonSlot *leftButtonSlot = 0; JoyButtonSlot *rightButtonSlot = 0; JoyButtonSlot *upLeftButtonSlot = 0; JoyButtonSlot *upRightButtonSlot = 0; JoyButtonSlot *downLeftButtonSlot = 0; JoyButtonSlot *downRightButtonSlot = 0; if (item == 0) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); downButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); leftButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); rightButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); stick->setJoyMode(JoyControlStick::StandardMode); stick->setDiagonalRange(65); PadderCommon::inputDaemonMutex.unlock(); } else if (item == 1) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); downButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); leftButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); rightButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); stick->setJoyMode(JoyControlStick::StandardMode); stick->setDiagonalRange(65); PadderCommon::inputDaemonMutex.unlock(); } else if (item == 2) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); downButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); leftButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); rightButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); stick->setJoyMode(JoyControlStick::StandardMode); stick->setDiagonalRange(65); PadderCommon::inputDaemonMutex.unlock(); } else if (item == 3) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); downButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); leftButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); rightButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); stick->setJoyMode(JoyControlStick::StandardMode); stick->setDiagonalRange(65); PadderCommon::inputDaemonMutex.unlock(); } else if (item == 4) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Up), Qt::Key_Up, JoyButtonSlot::JoyKeyboard, this); downButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Down), Qt::Key_Down, JoyButtonSlot::JoyKeyboard, this); leftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Left), Qt::Key_Left, JoyButtonSlot::JoyKeyboard, this); rightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Right), Qt::Key_Right, JoyButtonSlot::JoyKeyboard, this); stick->setJoyMode(JoyControlStick::StandardMode); stick->setDiagonalRange(45); PadderCommon::inputDaemonMutex.unlock(); } else if (item == 5) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_W), Qt::Key_W, JoyButtonSlot::JoyKeyboard, this); downButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_S), Qt::Key_S, JoyButtonSlot::JoyKeyboard, this); leftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_A), Qt::Key_A, JoyButtonSlot::JoyKeyboard, this); rightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_D), Qt::Key_D, JoyButtonSlot::JoyKeyboard, this); stick->setJoyMode(JoyControlStick::StandardMode); stick->setDiagonalRange(45); PadderCommon::inputDaemonMutex.unlock(); } else if (item == 6) { PadderCommon::inputDaemonMutex.lock(); if (stick->getJoyMode() == JoyControlStick::StandardMode || stick->getJoyMode() == JoyControlStick::FourWayCardinal) { upButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_8), QtKeyMapperBase::AntKey_KP_8, JoyButtonSlot::JoyKeyboard, this); downButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_2), QtKeyMapperBase::AntKey_KP_2, JoyButtonSlot::JoyKeyboard, this); leftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_4), QtKeyMapperBase::AntKey_KP_4, JoyButtonSlot::JoyKeyboard, this); rightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_6), QtKeyMapperBase::AntKey_KP_6, JoyButtonSlot::JoyKeyboard, this); } else if (stick->getJoyMode() == JoyControlStick::EightWayMode) { upButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_8), QtKeyMapperBase::AntKey_KP_8, JoyButtonSlot::JoyKeyboard, this); downButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_2), QtKeyMapperBase::AntKey_KP_2, JoyButtonSlot::JoyKeyboard, this); leftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_4), QtKeyMapperBase::AntKey_KP_4, JoyButtonSlot::JoyKeyboard, this); rightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_6), QtKeyMapperBase::AntKey_KP_6, JoyButtonSlot::JoyKeyboard, this); upLeftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_7), QtKeyMapperBase::AntKey_KP_7, JoyButtonSlot::JoyKeyboard, this); upRightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_9), QtKeyMapperBase::AntKey_KP_9, JoyButtonSlot::JoyKeyboard, this); downLeftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_1), QtKeyMapperBase::AntKey_KP_1, JoyButtonSlot::JoyKeyboard, this); downRightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_3), QtKeyMapperBase::AntKey_KP_3, JoyButtonSlot::JoyKeyboard, this); } else if (stick->getJoyMode() == JoyControlStick::FourWayDiagonal) { upLeftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_7), QtKeyMapperBase::AntKey_KP_7, JoyButtonSlot::JoyKeyboard, this); upRightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_9), QtKeyMapperBase::AntKey_KP_9, JoyButtonSlot::JoyKeyboard, this); downLeftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_1), QtKeyMapperBase::AntKey_KP_1, JoyButtonSlot::JoyKeyboard, this); downRightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_3), QtKeyMapperBase::AntKey_KP_3, JoyButtonSlot::JoyKeyboard, this); } stick->setDiagonalRange(45); PadderCommon::inputDaemonMutex.unlock(); } else if (item == 7) { QMetaObject::invokeMethod(&helper, "clearButtonsSlotsEventReset"); QMetaObject::invokeMethod(stick, "setDiagonalRange", Q_ARG(int, 45)); } QHash tempHash; tempHash.insert(JoyControlStick::StickUp, upButtonSlot); tempHash.insert(JoyControlStick::StickDown, downButtonSlot); tempHash.insert(JoyControlStick::StickLeft, leftButtonSlot); tempHash.insert(JoyControlStick::StickRight, rightButtonSlot); tempHash.insert(JoyControlStick::StickLeftUp, upLeftButtonSlot); tempHash.insert(JoyControlStick::StickRightUp, upRightButtonSlot); tempHash.insert(JoyControlStick::StickLeftDown, downLeftButtonSlot); tempHash.insert(JoyControlStick::StickRightDown, downRightButtonSlot); helper.setPendingSlots(&tempHash); QMetaObject::invokeMethod(&helper, "setFromPendingSlots", Qt::BlockingQueuedConnection); } int JoyControlStickContextMenu::getPresetIndex() { int result = 0; PadderCommon::inputDaemonMutex.lock(); JoyControlStickButton *upButton = stick->getDirectionButton(JoyControlStick::StickUp); QList *upslots = upButton->getAssignedSlots(); JoyControlStickButton *downButton = stick->getDirectionButton(JoyControlStick::StickDown); QList *downslots = downButton->getAssignedSlots(); JoyControlStickButton *leftButton = stick->getDirectionButton(JoyControlStick::StickLeft); QList *leftslots = leftButton->getAssignedSlots(); JoyControlStickButton *rightButton = stick->getDirectionButton(JoyControlStick::StickRight); QList *rightslots = rightButton->getAssignedSlots(); if (upslots->length() == 1 && downslots->length() == 1 && leftslots->length() == 1 && rightslots->length() == 1) { JoyButtonSlot *upslot = upslots->at(0); JoyButtonSlot *downslot = downslots->at(0); JoyButtonSlot *leftslot = leftslots->at(0); JoyButtonSlot *rightslot = rightslots->at(0); if (upslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && upslot->getSlotCode() == JoyButtonSlot::MouseUp && downslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && downslot->getSlotCode() == JoyButtonSlot::MouseDown && leftslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && leftslot->getSlotCode() == JoyButtonSlot::MouseLeft && rightslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && rightslot->getSlotCode() == JoyButtonSlot::MouseRight) { result = 1; } else if (upslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && upslot->getSlotCode() == JoyButtonSlot::MouseUp && downslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && downslot->getSlotCode() == JoyButtonSlot::MouseDown && leftslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && leftslot->getSlotCode() == JoyButtonSlot::MouseRight && rightslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && rightslot->getSlotCode() == JoyButtonSlot::MouseLeft) { result = 2; } else if (upslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && upslot->getSlotCode() == JoyButtonSlot::MouseDown && downslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && downslot->getSlotCode() == JoyButtonSlot::MouseUp && leftslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && leftslot->getSlotCode() == JoyButtonSlot::MouseLeft && rightslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && rightslot->getSlotCode() == JoyButtonSlot::MouseRight) { result = 3; } else if (upslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && upslot->getSlotCode() == JoyButtonSlot::MouseDown && downslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && downslot->getSlotCode() == JoyButtonSlot::MouseUp && leftslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && leftslot->getSlotCode() == JoyButtonSlot::MouseRight && rightslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && rightslot->getSlotCode() == JoyButtonSlot::MouseLeft) { result = 4; } else if (upslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(upslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Up) && downslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(downslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Down) && leftslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(leftslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Left) && rightslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(rightslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Right)) { result = 5; } else if (upslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(upslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_W) && downslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(downslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_S) && leftslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(leftslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_A) && rightslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(rightslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_D)) { result = 6; } else if (upslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(upslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_8) && downslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(downslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_2) && leftslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(leftslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_4) && rightslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(rightslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_6)) { result = 7; } } else if (upslots->length() == 0 && downslots->length() == 0 && leftslots->length() == 0 && rightslots->length() == 0) { result = 8; } PadderCommon::inputDaemonMutex.unlock(); return result; } void JoyControlStickContextMenu::openMouseSettingsDialog() { MouseControlStickSettingsDialog *dialog = new MouseControlStickSettingsDialog(stick, parentWidget()); dialog->show(); } antimicro-2.23/src/joycontrolstickcontextmenu.h000066400000000000000000000025661300750276700221370ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYCONTROLSTICKCONTEXTMENU_H #define JOYCONTROLSTICKCONTEXTMENU_H #include #include "joycontrolstick.h" #include "uihelpers/joycontrolstickcontextmenuhelper.h" class JoyControlStickContextMenu : public QMenu { Q_OBJECT public: explicit JoyControlStickContextMenu(JoyControlStick *stick, QWidget *parent = 0); void buildMenu(); protected: int getPresetIndex(); JoyControlStick *stick; JoyControlStickContextMenuHelper helper; signals: public slots: private slots: void setStickPreset(); void setStickMode(); void openMouseSettingsDialog(); }; #endif // JOYCONTROLSTICKCONTEXTMENU_H antimicro-2.23/src/joycontrolstickdirectionstype.h000066400000000000000000000021561300750276700226260ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYCONTROLSTICKDIRECTIONSTYPE_H #define JOYCONTROLSTICKDIRECTIONSTYPE_H class JoyStickDirectionsType { public: enum JoyStickDirections { StickCentered = 0, StickUp = 1, StickRight = 3, StickDown = 5, StickLeft = 7, StickRightUp = 2, StickRightDown = 4, StickLeftUp = 8, StickLeftDown = 6 }; }; #endif // JOYCONTROLSTICKDIRECTIONSTYPE_H antimicro-2.23/src/joycontrolstickeditdialog.cpp000066400000000000000000000641051300750276700222230ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include #include "joycontrolstickeditdialog.h" #include "ui_joycontrolstickeditdialog.h" #include "mousedialog/mousecontrolsticksettingsdialog.h" #include "event.h" #include "antkeymapper.h" #include "setjoystick.h" #include "buttoneditdialog.h" #include "inputdevice.h" #include "common.h" JoyControlStickEditDialog::JoyControlStickEditDialog(JoyControlStick *stick, QWidget *parent) : QDialog(parent, Qt::Window), ui(new Ui::JoyControlStickEditDialog), helper(stick) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); this->stick = stick; helper.moveToThread(stick->thread()); PadderCommon::inputDaemonMutex.lock(); updateWindowTitleStickName(); ui->deadZoneSlider->setValue(stick->getDeadZone()); ui->deadZoneSpinBox->setValue(stick->getDeadZone()); ui->maxZoneSlider->setValue(stick->getMaxZone()); ui->maxZoneSpinBox->setValue(stick->getMaxZone()); ui->diagonalRangeSlider->setValue(stick->getDiagonalRange()); ui->diagonalRangeSpinBox->setValue(stick->getDiagonalRange()); QString xCoorString = QString::number(stick->getXCoordinate()); if (stick->getCircleAdjust() > 0.0) { xCoorString.append(QString(" (%1)").arg(stick->getCircleXCoordinate())); } ui->xCoordinateLabel->setText(xCoorString); QString yCoorString = QString::number(stick->getYCoordinate()); if (stick->getCircleAdjust() > 0.0) { yCoorString.append(QString(" (%1)").arg(stick->getCircleYCoordinate())); } ui->yCoordinateLabel->setText(yCoorString); ui->distanceLabel->setText(QString::number(stick->getAbsoluteRawDistance())); ui->diagonalLabel->setText(QString::number(stick->calculateBearing())); if (stick->getJoyMode() == JoyControlStick::StandardMode) { ui->joyModeComboBox->setCurrentIndex(0); } else if (stick->getJoyMode() == JoyControlStick::EightWayMode) { ui->joyModeComboBox->setCurrentIndex(1); } else if (stick->getJoyMode() == JoyControlStick::FourWayCardinal) { ui->joyModeComboBox->setCurrentIndex(2); ui->diagonalRangeSlider->setEnabled(false); ui->diagonalRangeSpinBox->setEnabled(false); } else if (stick->getJoyMode() == JoyControlStick::FourWayDiagonal) { ui->joyModeComboBox->setCurrentIndex(3); ui->diagonalRangeSlider->setEnabled(false); ui->diagonalRangeSpinBox->setEnabled(false); } ui->stickStatusBoxWidget->setStick(stick); selectCurrentPreset(); ui->stickNameLineEdit->setText(stick->getStickName()); double validDistance = stick->getDistanceFromDeadZone() * 100.0; ui->fromSafeZoneValueLabel->setText(QString::number(validDistance)); double circleValue = stick->getCircleAdjust(); ui->squareStickSlider->setValue(circleValue * 100); ui->squareStickSpinBox->setValue(circleValue * 100); unsigned int stickDelay = stick->getStickDelay(); ui->stickDelaySlider->setValue(stickDelay * .1); ui->stickDelayDoubleSpinBox->setValue(stickDelay * .001); ui->modifierPushButton->setText(stick->getModifierButton()->getSlotsSummary()); stick->getModifierButton()->establishPropertyUpdatedConnections(); PadderCommon::inputDaemonMutex.unlock(); connect(ui->presetsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(implementPresets(int))); connect(ui->joyModeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(implementModes(int))); connect(ui->deadZoneSlider, SIGNAL(valueChanged(int)), ui->deadZoneSpinBox, SLOT(setValue(int))); connect(ui->maxZoneSlider, SIGNAL(valueChanged(int)), ui->maxZoneSpinBox, SLOT(setValue(int))); connect(ui->diagonalRangeSlider, SIGNAL(valueChanged(int)), ui->diagonalRangeSpinBox, SLOT(setValue(int))); connect(ui->squareStickSlider, SIGNAL(valueChanged(int)), ui->squareStickSpinBox, SLOT(setValue(int))); connect(ui->deadZoneSpinBox, SIGNAL(valueChanged(int)), ui->deadZoneSlider, SLOT(setValue(int))); connect(ui->maxZoneSpinBox, SIGNAL(valueChanged(int)), ui->maxZoneSlider, SLOT(setValue(int))); connect(ui->maxZoneSpinBox, SIGNAL(valueChanged(int)), this, SLOT(checkMaxZone(int))); connect(ui->diagonalRangeSpinBox, SIGNAL(valueChanged(int)), ui->diagonalRangeSlider, SLOT(setValue(int))); connect(ui->squareStickSpinBox, SIGNAL(valueChanged(int)), ui->squareStickSlider, SLOT(setValue(int))); connect(ui->stickDelaySlider, SIGNAL(valueChanged(int)), &helper, SLOT(updateControlStickDelay(int))); connect(ui->deadZoneSpinBox, SIGNAL(valueChanged(int)), stick, SLOT(setDeadZone(int))); connect(ui->diagonalRangeSpinBox, SIGNAL(valueChanged(int)), stick, SLOT(setDiagonalRange(int))); connect(ui->squareStickSpinBox, SIGNAL(valueChanged(int)), this, SLOT(changeCircleAdjust(int))); connect(stick, SIGNAL(stickDelayChanged(int)), this, SLOT(updateStickDelaySpinBox(int))); connect(ui->stickDelayDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(updateStickDelaySlider(double))); connect(stick, SIGNAL(moved(int,int)), this, SLOT(refreshStickStats(int,int))); connect(ui->mouseSettingsPushButton, SIGNAL(clicked()), this, SLOT(openMouseSettingsDialog())); connect(ui->stickNameLineEdit, SIGNAL(textEdited(QString)), stick, SLOT(setStickName(QString))); connect(stick, SIGNAL(stickNameChanged()), this, SLOT(updateWindowTitleStickName())); connect(ui->modifierPushButton, SIGNAL(clicked()), this, SLOT(openModifierEditDialog())); connect(stick->getModifierButton(), SIGNAL(slotsChanged()), this, SLOT(changeModifierSummary())); } JoyControlStickEditDialog::~JoyControlStickEditDialog() { delete ui; } void JoyControlStickEditDialog::implementPresets(int index) { JoyButtonSlot *upButtonSlot = 0; JoyButtonSlot *downButtonSlot = 0; JoyButtonSlot *leftButtonSlot = 0; JoyButtonSlot *rightButtonSlot = 0; JoyButtonSlot *upLeftButtonSlot = 0; JoyButtonSlot *upRightButtonSlot = 0; JoyButtonSlot *downLeftButtonSlot = 0; JoyButtonSlot *downRightButtonSlot = 0; if (index == 1) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); downButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); leftButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); rightButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); PadderCommon::inputDaemonMutex.unlock(); ui->joyModeComboBox->setCurrentIndex(0); ui->diagonalRangeSlider->setValue(65); } else if (index == 2) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); downButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); leftButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); rightButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); PadderCommon::inputDaemonMutex.unlock(); ui->joyModeComboBox->setCurrentIndex(0); ui->diagonalRangeSlider->setValue(65); } else if (index == 3) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); downButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); leftButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); rightButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); PadderCommon::inputDaemonMutex.unlock(); ui->joyModeComboBox->setCurrentIndex(0); ui->diagonalRangeSlider->setValue(65); } else if (index == 4) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); downButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); leftButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); rightButtonSlot = new JoyButtonSlot(JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); PadderCommon::inputDaemonMutex.unlock(); ui->joyModeComboBox->setCurrentIndex(0); ui->diagonalRangeSlider->setValue(65); } else if (index == 5) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Up), Qt::Key_Up, JoyButtonSlot::JoyKeyboard, this); downButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Down), Qt::Key_Down, JoyButtonSlot::JoyKeyboard, this); leftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Left), Qt::Key_Left, JoyButtonSlot::JoyKeyboard, this); rightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Right), Qt::Key_Right, JoyButtonSlot::JoyKeyboard, this); PadderCommon::inputDaemonMutex.unlock(); ui->joyModeComboBox->setCurrentIndex(0); ui->diagonalRangeSlider->setValue(45); } else if (index == 6) { PadderCommon::inputDaemonMutex.lock(); upButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_W), Qt::Key_W, JoyButtonSlot::JoyKeyboard, this); downButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_S), Qt::Key_S, JoyButtonSlot::JoyKeyboard, this); leftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_A), Qt::Key_A, JoyButtonSlot::JoyKeyboard, this); rightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_D), Qt::Key_D, JoyButtonSlot::JoyKeyboard, this); PadderCommon::inputDaemonMutex.unlock(); ui->joyModeComboBox->setCurrentIndex(0); ui->diagonalRangeSlider->setValue(45); } else if (index == 7) { PadderCommon::inputDaemonMutex.lock(); if (ui->joyModeComboBox->currentIndex() == 0 || ui->joyModeComboBox->currentIndex() == 2) { upButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_8), QtKeyMapperBase::AntKey_KP_8, JoyButtonSlot::JoyKeyboard, this); downButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_2), QtKeyMapperBase::AntKey_KP_2, JoyButtonSlot::JoyKeyboard, this); leftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_4), QtKeyMapperBase::AntKey_KP_4, JoyButtonSlot::JoyKeyboard, this); rightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_6), QtKeyMapperBase::AntKey_KP_6, JoyButtonSlot::JoyKeyboard, this); } else if (ui->joyModeComboBox->currentIndex() == 1) { upButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_8), QtKeyMapperBase::AntKey_KP_8, JoyButtonSlot::JoyKeyboard, this); downButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_2), QtKeyMapperBase::AntKey_KP_2, JoyButtonSlot::JoyKeyboard, this); leftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_4), QtKeyMapperBase::AntKey_KP_4, JoyButtonSlot::JoyKeyboard, this); rightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_6), QtKeyMapperBase::AntKey_KP_6, JoyButtonSlot::JoyKeyboard, this); upLeftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_7), QtKeyMapperBase::AntKey_KP_7, JoyButtonSlot::JoyKeyboard, this); upRightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_9), QtKeyMapperBase::AntKey_KP_9, JoyButtonSlot::JoyKeyboard, this); downLeftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_1), QtKeyMapperBase::AntKey_KP_1, JoyButtonSlot::JoyKeyboard, this); downRightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_3), QtKeyMapperBase::AntKey_KP_3, JoyButtonSlot::JoyKeyboard, this); } else if (ui->joyModeComboBox->currentIndex() == 3) { upLeftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_7), QtKeyMapperBase::AntKey_KP_7, JoyButtonSlot::JoyKeyboard, this); upRightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_9), QtKeyMapperBase::AntKey_KP_9, JoyButtonSlot::JoyKeyboard, this); downLeftButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_1), QtKeyMapperBase::AntKey_KP_1, JoyButtonSlot::JoyKeyboard, this); downRightButtonSlot = new JoyButtonSlot(AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_3), QtKeyMapperBase::AntKey_KP_3, JoyButtonSlot::JoyKeyboard, this); } PadderCommon::inputDaemonMutex.unlock(); ui->diagonalRangeSlider->setValue(45); } else if (index == 8) { QMetaObject::invokeMethod(&helper, "clearButtonsSlotsEventReset", Qt::BlockingQueuedConnection); ui->diagonalRangeSlider->setValue(45); } QHash tempHash; tempHash.insert(JoyControlStick::StickUp, upButtonSlot); tempHash.insert(JoyControlStick::StickDown, downButtonSlot); tempHash.insert(JoyControlStick::StickLeft, leftButtonSlot); tempHash.insert(JoyControlStick::StickRight, rightButtonSlot); tempHash.insert(JoyControlStick::StickLeftUp, upLeftButtonSlot); tempHash.insert(JoyControlStick::StickRightUp, upRightButtonSlot); tempHash.insert(JoyControlStick::StickLeftDown, downLeftButtonSlot); tempHash.insert(JoyControlStick::StickRightDown, downRightButtonSlot); helper.setPendingSlots(&tempHash); QMetaObject::invokeMethod(&helper, "setFromPendingSlots", Qt::BlockingQueuedConnection); } void JoyControlStickEditDialog::refreshStickStats(int x, int y) { Q_UNUSED(x); Q_UNUSED(y); PadderCommon::inputDaemonMutex.lock(); QString xCoorString = QString::number(stick->getXCoordinate()); if (stick->getCircleAdjust() > 0.0) { xCoorString.append(QString(" (%1)").arg(stick->getCircleXCoordinate())); } ui->xCoordinateLabel->setText(xCoorString); QString yCoorString = QString::number(stick->getYCoordinate()); if (stick->getCircleAdjust() > 0.0) { yCoorString.append(QString(" (%1)").arg(stick->getCircleYCoordinate())); } ui->yCoordinateLabel->setText(yCoorString); ui->distanceLabel->setText(QString::number(stick->getAbsoluteRawDistance())); ui->diagonalLabel->setText(QString::number(stick->calculateBearing())); double validDistance = stick->getDistanceFromDeadZone() * 100.0; ui->fromSafeZoneValueLabel->setText(QString::number(validDistance)); PadderCommon::inputDaemonMutex.unlock(); } void JoyControlStickEditDialog::checkMaxZone(int value) { if (value > ui->deadZoneSpinBox->value()) { QMetaObject::invokeMethod(stick, "setMaxZone", Q_ARG(int, value)); } } void JoyControlStickEditDialog::implementModes(int index) { PadderCommon::inputDaemonMutex.lock(); stick->releaseButtonEvents(); if (index == 0) { stick->setJoyMode(JoyControlStick::StandardMode); ui->diagonalRangeSlider->setEnabled(true); ui->diagonalRangeSpinBox->setEnabled(true); } else if (index == 1) { stick->setJoyMode(JoyControlStick::EightWayMode); ui->diagonalRangeSlider->setEnabled(true); ui->diagonalRangeSpinBox->setEnabled(true); } else if (index == 2) { stick->setJoyMode(JoyControlStick::FourWayCardinal); ui->diagonalRangeSlider->setEnabled(false); ui->diagonalRangeSpinBox->setEnabled(false); } else if (index == 3) { stick->setJoyMode(JoyControlStick::FourWayDiagonal); ui->diagonalRangeSlider->setEnabled(false); ui->diagonalRangeSpinBox->setEnabled(false); } PadderCommon::inputDaemonMutex.unlock(); } void JoyControlStickEditDialog::selectCurrentPreset() { JoyControlStickButton *upButton = stick->getDirectionButton(JoyControlStick::StickUp); QList *upslots = upButton->getAssignedSlots(); JoyControlStickButton *downButton = stick->getDirectionButton(JoyControlStick::StickDown); QList *downslots = downButton->getAssignedSlots(); JoyControlStickButton *leftButton = stick->getDirectionButton(JoyControlStick::StickLeft); QList *leftslots = leftButton->getAssignedSlots(); JoyControlStickButton *rightButton = stick->getDirectionButton(JoyControlStick::StickRight); QList *rightslots = rightButton->getAssignedSlots(); if (upslots->length() == 1 && downslots->length() == 1 && leftslots->length() == 1 && rightslots->length() == 1) { JoyButtonSlot *upslot = upslots->at(0); JoyButtonSlot *downslot = downslots->at(0); JoyButtonSlot *leftslot = leftslots->at(0); JoyButtonSlot *rightslot = rightslots->at(0); if (upslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && upslot->getSlotCode() == JoyButtonSlot::MouseUp && downslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && downslot->getSlotCode() == JoyButtonSlot::MouseDown && leftslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && leftslot->getSlotCode() == JoyButtonSlot::MouseLeft && rightslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && rightslot->getSlotCode() == JoyButtonSlot::MouseRight) { ui->presetsComboBox->setCurrentIndex(1); } else if (upslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && upslot->getSlotCode() == JoyButtonSlot::MouseUp && downslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && downslot->getSlotCode() == JoyButtonSlot::MouseDown && leftslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && leftslot->getSlotCode() == JoyButtonSlot::MouseRight && rightslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && rightslot->getSlotCode() == JoyButtonSlot::MouseLeft) { ui->presetsComboBox->setCurrentIndex(2); } else if (upslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && upslot->getSlotCode() == JoyButtonSlot::MouseDown && downslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && downslot->getSlotCode() == JoyButtonSlot::MouseUp && leftslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && leftslot->getSlotCode() == JoyButtonSlot::MouseLeft && rightslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && rightslot->getSlotCode() == JoyButtonSlot::MouseRight) { ui->presetsComboBox->setCurrentIndex(3); } else if (upslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && upslot->getSlotCode() == JoyButtonSlot::MouseDown && downslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && downslot->getSlotCode() == JoyButtonSlot::MouseUp && leftslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && leftslot->getSlotCode() == JoyButtonSlot::MouseRight && rightslot->getSlotMode() == JoyButtonSlot::JoyMouseMovement && rightslot->getSlotCode() == JoyButtonSlot::MouseLeft) { ui->presetsComboBox->setCurrentIndex(4); } else if (upslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(upslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Up) && downslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(downslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Down) && leftslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(leftslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Left) && rightslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(rightslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Right)) { ui->presetsComboBox->setCurrentIndex(5); } else if (upslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(upslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_W) && downslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(downslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_S) && leftslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(leftslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_A) && rightslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(rightslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_D)) { ui->presetsComboBox->setCurrentIndex(6); } else if (upslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(upslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_8) && downslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(downslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_2) && leftslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(leftslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_4) && rightslot->getSlotMode() == JoyButtonSlot::JoyKeyboard && static_cast(rightslot->getSlotCode()) == AntKeyMapper::getInstance()->returnVirtualKey(QtKeyMapperBase::AntKey_KP_6)) { ui->presetsComboBox->setCurrentIndex(7); } } else if (upslots->length() == 0 && downslots->length() == 0 && leftslots->length() == 0 && rightslots->length() == 0) { ui->presetsComboBox->setCurrentIndex(8); } } void JoyControlStickEditDialog::updateMouseMode(int index) { PadderCommon::inputDaemonMutex.lock(); if (index == 1) { stick->setButtonsMouseMode(JoyButton::MouseCursor); } else if (index == 2) { stick->setButtonsMouseMode(JoyButton::MouseSpring); } PadderCommon::inputDaemonMutex.unlock(); } void JoyControlStickEditDialog::openMouseSettingsDialog() { ui->mouseSettingsPushButton->setEnabled(false); MouseControlStickSettingsDialog *dialog = new MouseControlStickSettingsDialog(this->stick, this); dialog->show(); connect(this, SIGNAL(finished(int)), dialog, SLOT(close())); connect(dialog, SIGNAL(finished(int)), this, SLOT(enableMouseSettingButton())); } void JoyControlStickEditDialog::enableMouseSettingButton() { ui->mouseSettingsPushButton->setEnabled(true); } void JoyControlStickEditDialog::updateWindowTitleStickName() { QString temp = QString(tr("Set")).append(" "); if (!stick->getStickName().isEmpty()) { temp.append(stick->getPartialName(false, true)); } else { temp.append(stick->getPartialName()); } if (stick->getParentSet()->getIndex() != 0) { unsigned int setIndex = stick->getParentSet()->getRealIndex(); temp.append(" [").append(tr("Set %1").arg(setIndex)); QString setName = stick->getParentSet()->getName(); if (!setName.isEmpty()) { temp.append(": ").append(setName); } temp.append("]"); } setWindowTitle(temp); } void JoyControlStickEditDialog::changeCircleAdjust(int value) { QMetaObject::invokeMethod(stick, "setCircleAdjust", Q_ARG(double, value * 0.01)); } /** * @brief Update QDoubleSpinBox value based on updated stick delay value. * @param Delay value obtained from JoyControlStick. */ void JoyControlStickEditDialog::updateStickDelaySpinBox(int value) { double temp = static_cast(value * 0.001); ui->stickDelayDoubleSpinBox->setValue(temp); } /** * @brief Update QSlider value based on value from QDoubleSpinBox. * @param Value from QDoubleSpinBox. */ void JoyControlStickEditDialog::updateStickDelaySlider(double value) { int temp = static_cast(value * 100); if (ui->stickDelaySlider->value() != temp) { ui->stickDelaySlider->setValue(temp); } } void JoyControlStickEditDialog::openModifierEditDialog() { ButtonEditDialog *dialog = new ButtonEditDialog(stick->getModifierButton(), this); dialog->show(); } void JoyControlStickEditDialog::changeModifierSummary() { ui->modifierPushButton->setText(stick->getModifierButton()->getSlotsSummary()); } antimicro-2.23/src/joycontrolstickeditdialog.h000066400000000000000000000035671300750276700216750ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYCONTROLSTICKEDITDIALOG_H #define JOYCONTROLSTICKEDITDIALOG_H #include #include "joycontrolstick.h" #include "uihelpers/joycontrolstickeditdialoghelper.h" namespace Ui { class JoyControlStickEditDialog; } class JoyControlStickEditDialog : public QDialog { Q_OBJECT public: explicit JoyControlStickEditDialog(JoyControlStick *stick, QWidget *parent = 0); ~JoyControlStickEditDialog(); protected: void selectCurrentPreset(); JoyControlStick *stick; JoyControlStickEditDialogHelper helper; private: Ui::JoyControlStickEditDialog *ui; private slots: void implementPresets(int index); void implementModes(int index); void refreshStickStats(int x, int y); void updateMouseMode(int index); void checkMaxZone(int value); void openMouseSettingsDialog(); void enableMouseSettingButton(); void updateWindowTitleStickName(); void changeCircleAdjust(int value); void updateStickDelaySpinBox(int value); void updateStickDelaySlider(double value); void openModifierEditDialog(); void changeModifierSummary(); }; #endif // JOYCONTROLSTICKEDITDIALOG_H antimicro-2.23/src/joycontrolstickeditdialog.ui000066400000000000000000000641611300750276700220600ustar00rootroot00000000000000 JoyControlStickEditDialog 0 0 702 464 0 0 0 0 Dialog JoyControlStickButtonPushButton[isflashing="true"] { background-color: rgb(0, 0, 255); color: rgb(205, 197, 191); } true 20 0 0 200 200 16777215 16777215 0 0 200 200 Qt::Vertical QSizePolicy::Fixed 20 20 10 0 0 X: 0 0 0 0 0 Y: 0 0 0 0 0 Distance: 0 0 0 0 0 Bearing: 0 0 0 0 0 % Safe Zone: 0 0 0 Qt::Vertical QSizePolicy::Fixed 20 20 10 Presets: 282 0 Mouse (Normal) Mouse (Inverted Horizontal) Mouse (Inverted Vertical) Mouse (Inverted Horizontal + Vertical) Arrows Keys: W | A | S | D NumPad None Stick Mode: 282 0 Standard: 8 region stick with two direction buttons active when the stick is in a diagonal region. Eight Way: 8 region stick with each direction having its own dedicated button. Only one button is ever active at at time. Useful for rougelike games. 4 Way Cardinal: 4 region stick with regions corresponding to the cardinal directions of the stick. Useful for menus. 4 Way Diagonal: 4 region stick with each region corresponding to a diagonal zone of the stick. Standard Eight Way 4 Way Cardinal 4 Way Diagonal Qt::Vertical QSizePolicy::MinimumExpanding 20 20 6 Dead Zone: Dead zone value to use for an analog stick. 1 32737 100 1000 6000 Qt::Horizontal Dead zone value to use for an analog stick. 1 32737 8000 Max Zone: Value when an analog stick is considered moved 100%. 1 32737 100 1000 32000 Qt::Horizontal Value when an analog stick is considered moved 100%. 1 32737 32000 Diagonal Range: The area (in degrees) that each diagonal region occupies. 1 90 Qt::Horizontal The area (in degrees) that each diagonal region occupies. 1 90 45 Square Stick: Percentage to modify a square stick coordinates to confine values to a circle 0 100 1 10 0 0 Qt::Horizontal Percentage to modify a square stick coordinates to confine values to a circle % 0 100 1 0 Stick Delay: Time lapsed before a direction change is taken into effect. 0 100 1 10 0 0 Qt::Horizontal QSlider::TicksBelow 0 Time lapsed before a direction change is taken into effect. false s 2 1.000000000000000 0.010000000000000 0 Modifier: Edit button that is active while the stick is active. This button is useful for assigning zones with modifier keys that can be used to assign walk/run functionality to an analog stick. PushButton Qt::Vertical QSizePolicy::Fixed 20 20 10 6 Name: stickNameLineEdit Specify the name of an analog stick. Mouse Settings Qt::Horizontal Qt::Horizontal QDialogButtonBox::Close JoyControlStickStatusBox QWidget
joycontrolstickstatusbox.h
1
buttonBox accepted() JoyControlStickEditDialog accept() 248 254 157 274 buttonBox rejected() JoyControlStickEditDialog reject() 316 260 286 274
antimicro-2.23/src/joycontrolstickpushbutton.cpp000066400000000000000000000054331300750276700223300ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "joycontrolstickpushbutton.h" #include "joycontrolstickcontextmenu.h" JoyControlStickPushButton::JoyControlStickPushButton(JoyControlStick *stick, bool displayNames, QWidget *parent) : FlashButtonWidget(displayNames, parent) { this->stick = stick; refreshLabel(); tryFlash(); this->setContextMenuPolicy(Qt::CustomContextMenu); connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint&))); connect(stick, SIGNAL(active(int, int)), this, SLOT(flash()), Qt::QueuedConnection); connect(stick, SIGNAL(released(int, int)), this, SLOT(unflash()), Qt::QueuedConnection); connect(stick, SIGNAL(stickNameChanged()), this, SLOT(refreshLabel())); } JoyControlStick* JoyControlStickPushButton::getStick() { return stick; } /** * @brief Generate the string that will be displayed on the button * @return Display string */ QString JoyControlStickPushButton::generateLabel() { QString temp; if (!stick->getStickName().isEmpty() && displayNames) { temp.append(stick->getPartialName(false, true)); } else { temp.append(stick->getPartialName(false)); } return temp; } void JoyControlStickPushButton::disableFlashes() { disconnect(stick, SIGNAL(active(int, int)), this, SLOT(flash())); disconnect(stick, SIGNAL(released(int, int)), this, SLOT(unflash())); this->unflash(); } void JoyControlStickPushButton::enableFlashes() { connect(stick, SIGNAL(active(int, int)), this, SLOT(flash()), Qt::QueuedConnection); connect(stick, SIGNAL(released(int, int)), this, SLOT(unflash()), Qt::QueuedConnection); } void JoyControlStickPushButton::showContextMenu(const QPoint &point) { QPoint globalPos = this->mapToGlobal(point); JoyControlStickContextMenu *contextMenu = new JoyControlStickContextMenu(stick, this); contextMenu->buildMenu(); contextMenu->popup(globalPos); } void JoyControlStickPushButton::tryFlash() { if (stick->getCurrentDirection() != JoyControlStick::StickCentered) { flash(); } } antimicro-2.23/src/joycontrolstickpushbutton.h000066400000000000000000000026101300750276700217670ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYCONTROLSTICKPUSHBUTTON_H #define JOYCONTROLSTICKPUSHBUTTON_H #include #include "flashbuttonwidget.h" #include "joycontrolstick.h" class JoyControlStickPushButton : public FlashButtonWidget { Q_OBJECT public: explicit JoyControlStickPushButton(JoyControlStick *stick, bool displayNames, QWidget *parent = 0); JoyControlStick* getStick(); void tryFlash(); protected: virtual QString generateLabel(); JoyControlStick *stick; signals: public slots: void disableFlashes(); void enableFlashes(); private slots: void showContextMenu(const QPoint &point); }; #endif // JOYCONTROLSTICKPUSHBUTTON_H antimicro-2.23/src/joycontrolstickstatusbox.cpp000066400000000000000000000413601300750276700221500ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include #include #include #include "joycontrolstickstatusbox.h" #include "common.h" JoyControlStickStatusBox::JoyControlStickStatusBox(QWidget *parent) : QWidget(parent) { this->stick = 0; } JoyControlStickStatusBox::JoyControlStickStatusBox(JoyControlStick *stick, QWidget *parent) : QWidget(parent) { this->stick = stick; connect(stick, SIGNAL(deadZoneChanged(int)), this, SLOT(update())); connect(stick, SIGNAL(moved(int,int)), this, SLOT(update())); connect(stick, SIGNAL(diagonalRangeChanged(int)), this, SLOT(update())); connect(stick, SIGNAL(maxZoneChanged(int)), this, SLOT(update())); connect(stick, SIGNAL(joyModeChanged()), this, SLOT(update())); connect(stick, SIGNAL(circleAdjustChange(double)), this, SLOT(update())); } void JoyControlStickStatusBox::setStick(JoyControlStick *stick) { if (stick) { disconnect(stick, SIGNAL(deadZoneChanged(int)), this, 0); disconnect(stick, SIGNAL(moved(int,int)), this, 0); disconnect(stick, SIGNAL(diagonalRangeChanged(int)), this, 0); disconnect(stick, SIGNAL(maxZoneChanged(int)), this, 0); disconnect(stick, SIGNAL(joyModeChanged()), this, 0); } this->stick = stick; connect(stick, SIGNAL(deadZoneChanged(int)), this, SLOT(update())); connect(stick, SIGNAL(moved(int,int)), this, SLOT(update())); connect(stick, SIGNAL(diagonalRangeChanged(int)), this, SLOT(update())); connect(stick, SIGNAL(maxZoneChanged(int)), this, SLOT(update())); connect(stick, SIGNAL(joyModeChanged()), this, SLOT(update())); } JoyControlStick* JoyControlStickStatusBox::getStick() { return stick; } int JoyControlStickStatusBox::heightForWidth(int width) const { return width; } QSize JoyControlStickStatusBox::sizeHint() const { return QSize(-1, -1); } void JoyControlStickStatusBox::paintEvent(QPaintEvent *event) { Q_UNUSED(event); PadderCommon::inputDaemonMutex.lock(); if (stick->getJoyMode() == JoyControlStick::StandardMode || stick->getJoyMode() == JoyControlStick::EightWayMode) { drawEightWayBox(); } else if (stick->getJoyMode() == JoyControlStick::FourWayCardinal) { drawFourWayCardinalBox(); } else if (stick->getJoyMode() == JoyControlStick::FourWayDiagonal) { drawFourWayDiagonalBox(); } PadderCommon::inputDaemonMutex.unlock(); } void JoyControlStickStatusBox::drawEightWayBox() { QPainter paint (this); paint.setRenderHint(QPainter::Antialiasing, true); int side = qMin(width()-2, height()-2); QPixmap pix(side, side); pix.fill(Qt::transparent); QPainter painter(&pix); painter.setRenderHint(QPainter::Antialiasing, true); // Draw box outline QPen penny; penny.setColor(Qt::black); penny.setWidth(1); painter.setBrush(Qt::NoBrush); painter.drawRect(0, 0, side-1, side-1); painter.save(); painter.scale(side / (double)(JoyAxis::AXISMAX*2.0), side / (double)(JoyAxis::AXISMAX*2.0)); painter.translate(JoyAxis::AXISMAX, JoyAxis::AXISMAX); // Draw diagonal zones QList anglesList = stick->getDiagonalZoneAngles(); /*QListIterator iter(anglesList); qDebug() << "LIST START"; qDebug() << "DIAGONAL RANGE: " << stick->getDiagonalRange(); while (iter.hasNext()) { qDebug() << "ANGLE: " << iter.next(); } qDebug() << "LIST END"; qDebug(); */ penny.setWidth(0); penny.setColor(Qt::black); painter.setPen(penny); painter.setBrush(QBrush(Qt::green)); painter.drawPie(-JoyAxis::AXISMAX, -JoyAxis::AXISMAX, JoyAxis::AXISMAX*2, JoyAxis::AXISMAX*2, anglesList.value(2)*16, stick->getDiagonalRange()*16); painter.drawPie(-JoyAxis::AXISMAX, -JoyAxis::AXISMAX, JoyAxis::AXISMAX*2, JoyAxis::AXISMAX*2, anglesList.value(4)*16, stick->getDiagonalRange()*16); painter.drawPie(-JoyAxis::AXISMAX, -JoyAxis::AXISMAX, JoyAxis::AXISMAX*2, JoyAxis::AXISMAX*2, anglesList.value(6)*16, stick->getDiagonalRange()*16); painter.drawPie(-JoyAxis::AXISMAX, -JoyAxis::AXISMAX, JoyAxis::AXISMAX*2, JoyAxis::AXISMAX*2, anglesList.value(8)*16, stick->getDiagonalRange()*16); // Draw deadzone circle penny.setWidth(0); penny.setColor(Qt::blue); painter.setPen(penny); painter.setBrush(QBrush(Qt::red)); painter.drawEllipse(-stick->getDeadZone(), -stick->getDeadZone(), stick->getDeadZone()*2, stick->getDeadZone()*2); painter.restore(); painter.save(); penny.setWidth(0); penny.setColor(Qt::gray); painter.setPen(penny); painter.scale(side / 2.0, side / 2.0); painter.translate(1, 1); // Draw Y line painter.drawLine(0, -1, 0, 1); // Draw X line painter.drawLine(-1, 0, 1, 0); painter.restore(); painter.save(); painter.scale(side / (double)(JoyAxis::AXISMAX*2.0), side / (double)(JoyAxis::AXISMAX*2.0)); painter.translate(JoyAxis::AXISMAX, JoyAxis::AXISMAX); penny.setWidth(0); painter.setBrush(QBrush(Qt::black)); penny.setColor(Qt::black); painter.setPen(penny); // Draw raw crosshair int linexstart = stick->getXCoordinate()-1000; int lineystart = stick->getYCoordinate()-1000; if (linexstart < JoyAxis::AXISMIN) { linexstart = JoyAxis::AXISMIN; } if (lineystart < JoyAxis::AXISMIN) { lineystart = JoyAxis::AXISMIN; } painter.drawRect(linexstart, lineystart, 2000, 2000); painter.setBrush(QBrush(Qt::darkBlue)); penny.setColor(Qt::darkBlue); painter.setPen(penny); // Draw adjusted crosshair linexstart = stick->getCircleXCoordinate()-1000; lineystart = stick->getCircleYCoordinate()-1000; if (linexstart < JoyAxis::AXISMIN) { linexstart = JoyAxis::AXISMIN; } if (lineystart < JoyAxis::AXISMIN) { lineystart = JoyAxis::AXISMIN; } painter.drawRect(linexstart, lineystart, 2000, 2000); painter.restore(); // Reset pen penny.setColor(Qt::black); painter.setPen(penny); // Draw primary pixmap painter.setCompositionMode(QPainter::CompositionMode_DestinationOver); painter.setPen(Qt::NoPen); painter.fillRect(0, 0, side, side, palette().background().color()); paint.drawPixmap(pix.rect(), pix); paint.save(); paint.scale(side / (double)(JoyAxis::AXISMAX*2.0), side / (double)(JoyAxis::AXISMAX*2.0)); paint.translate(JoyAxis::AXISMAX, JoyAxis::AXISMAX); // Draw max zone and initial inner clear circle int maxzone = stick->getMaxZone(); int diffmaxzone = JoyAxis::AXISMAX - maxzone; paint.setOpacity(0.5); paint.setBrush(Qt::darkGreen); paint.drawEllipse(-JoyAxis::AXISMAX, -JoyAxis::AXISMAX, JoyAxis::AXISMAX*2, JoyAxis::AXISMAX*2); paint.setCompositionMode(QPainter::CompositionMode_Clear); paint.setPen(Qt::NoPen); paint.drawEllipse(-JoyAxis::AXISMAX+diffmaxzone, -JoyAxis::AXISMAX+diffmaxzone, JoyAxis::AXISMAX*2-(diffmaxzone*2), JoyAxis::AXISMAX*2-(diffmaxzone*2)); painter.setCompositionMode(QPainter::CompositionMode_SourceOver); paint.setOpacity(1.0); paint.restore(); // Re-draw pixmap so the inner circle will be transparent paint.setCompositionMode(QPainter::CompositionMode_DestinationOver); paint.drawPixmap(pix.rect(), pix); paint.setCompositionMode(QPainter::CompositionMode_SourceOver); } void JoyControlStickStatusBox::drawFourWayCardinalBox() { QPainter paint(this); paint.setRenderHint(QPainter::Antialiasing, true); int side = qMin(width()-2, height()-2); QPixmap pix(side, side); pix.fill(Qt::transparent); QPainter painter(&pix); painter.setRenderHint(QPainter::Antialiasing, true); // Draw box outline QPen penny; penny.setColor(Qt::black); penny.setWidth(1); painter.setBrush(Qt::NoBrush); painter.drawRect(0, 0, side-1, side-1); painter.save(); painter.scale(side / (double)(JoyAxis::AXISMAX*2.0), side / (double)(JoyAxis::AXISMAX*2.0)); painter.translate(JoyAxis::AXISMAX, JoyAxis::AXISMAX); // Draw diagonal zones QList anglesList = stick->getFourWayCardinalZoneAngles(); penny.setWidth(0); penny.setColor(Qt::black); painter.setPen(penny); painter.setOpacity(0.25); painter.setBrush(QBrush(Qt::black)); painter.drawPie(-JoyAxis::AXISMAX, -JoyAxis::AXISMAX, JoyAxis::AXISMAX*2, JoyAxis::AXISMAX*2, anglesList.value(1)*16, 90*16); painter.drawPie(-JoyAxis::AXISMAX, -JoyAxis::AXISMAX, JoyAxis::AXISMAX*2, JoyAxis::AXISMAX*2, anglesList.value(3)*16, 90*16); painter.setOpacity(1.0); // Draw deadzone circle penny.setWidth(0); penny.setColor(Qt::blue); painter.setPen(penny); painter.setBrush(QBrush(Qt::red)); painter.drawEllipse(-stick->getDeadZone(), -stick->getDeadZone(), stick->getDeadZone()*2, stick->getDeadZone()*2); painter.restore(); painter.save(); penny.setWidth(0); penny.setColor(Qt::black); painter.setPen(penny); painter.setOpacity(0.5); painter.scale(side / 2.0, side / 2.0); painter.translate(1, 1); // Draw Y line painter.drawLine(0, -1, 0, 1); // Draw X line painter.drawLine(-1, 0, 1, 0); painter.setOpacity(1.0); painter.restore(); painter.save(); painter.scale(side / (double)(JoyAxis::AXISMAX*2.0), side / (double)(JoyAxis::AXISMAX*2.0)); painter.translate(JoyAxis::AXISMAX, JoyAxis::AXISMAX); penny.setWidth(0); painter.setBrush(QBrush(Qt::black)); penny.setColor(Qt::black); painter.setPen(penny); // Draw raw crosshair int linexstart = stick->getXCoordinate()-1000; int lineystart = stick->getYCoordinate()-1000; if (linexstart < JoyAxis::AXISMIN) { linexstart = JoyAxis::AXISMIN; } if (lineystart < JoyAxis::AXISMIN) { lineystart = JoyAxis::AXISMIN; } painter.drawRect(linexstart, lineystart, 2000, 2000); painter.setBrush(QBrush(Qt::darkBlue)); penny.setColor(Qt::darkBlue); painter.setPen(penny); // Draw adjusted crosshair linexstart = stick->getCircleXCoordinate()-1000; lineystart = stick->getCircleYCoordinate()-1000; if (linexstart < JoyAxis::AXISMIN) { linexstart = JoyAxis::AXISMIN; } if (lineystart < JoyAxis::AXISMIN) { lineystart = JoyAxis::AXISMIN; } painter.drawRect(linexstart, lineystart, 2000, 2000); painter.restore(); // Reset pen penny.setColor(Qt::black); painter.setPen(penny); // Draw primary pixmap painter.setCompositionMode(QPainter::CompositionMode_DestinationOver); painter.setPen(Qt::NoPen); painter.fillRect(0, 0, side, side, palette().background().color()); paint.drawPixmap(pix.rect(), pix); paint.save(); paint.scale(side / (double)(JoyAxis::AXISMAX*2.0), side / (double)(JoyAxis::AXISMAX*2.0)); paint.translate(JoyAxis::AXISMAX, JoyAxis::AXISMAX); // Draw max zone and initial inner clear circle int maxzone = stick->getMaxZone(); int diffmaxzone = JoyAxis::AXISMAX - maxzone; paint.setOpacity(0.5); paint.setBrush(Qt::darkGreen); paint.drawEllipse(-JoyAxis::AXISMAX, -JoyAxis::AXISMAX, JoyAxis::AXISMAX*2, JoyAxis::AXISMAX*2); paint.setCompositionMode(QPainter::CompositionMode_Clear); paint.setPen(Qt::NoPen); paint.drawEllipse(-JoyAxis::AXISMAX+diffmaxzone, -JoyAxis::AXISMAX+diffmaxzone, JoyAxis::AXISMAX*2-(diffmaxzone*2), JoyAxis::AXISMAX*2-(diffmaxzone*2)); painter.setCompositionMode(QPainter::CompositionMode_SourceOver); paint.setOpacity(1.0); paint.restore(); // Re-draw pixmap so the inner circle will be transparent paint.setCompositionMode(QPainter::CompositionMode_DestinationOver); paint.drawPixmap(pix.rect(), pix); paint.setCompositionMode(QPainter::CompositionMode_SourceOver); } void JoyControlStickStatusBox::drawFourWayDiagonalBox() { QPainter paint(this); paint.setRenderHint(QPainter::Antialiasing, true); int side = qMin(width()-2, height()-2); QPixmap pix(side, side); pix.fill(Qt::transparent); QPainter painter(&pix); painter.setRenderHint(QPainter::Antialiasing, true); // Draw box outline QPen penny; penny.setColor(Qt::black); penny.setWidth(1); painter.setBrush(Qt::NoBrush); painter.drawRect(0, 0, side-1, side-1); painter.save(); painter.scale(side / (double)(JoyAxis::AXISMAX*2.0), side / (double)(JoyAxis::AXISMAX*2.0)); painter.translate(JoyAxis::AXISMAX, JoyAxis::AXISMAX); // Draw diagonal zones QList anglesList = stick->getFourWayDiagonalZoneAngles(); penny.setWidth(0); penny.setColor(Qt::black); painter.setPen(penny); painter.setBrush(QBrush(Qt::black)); painter.setOpacity(0.25); painter.drawPie(-JoyAxis::AXISMAX, -JoyAxis::AXISMAX, JoyAxis::AXISMAX*2, JoyAxis::AXISMAX*2, anglesList.value(1)*16, 90*16); painter.drawPie(-JoyAxis::AXISMAX, -JoyAxis::AXISMAX, JoyAxis::AXISMAX*2, JoyAxis::AXISMAX*2, anglesList.value(3)*16, 90*16); painter.setOpacity(1.0); // Draw deadzone circle penny.setWidth(0); penny.setColor(Qt::blue); painter.setPen(penny); painter.setBrush(QBrush(Qt::red)); painter.drawEllipse(-stick->getDeadZone(), -stick->getDeadZone(), stick->getDeadZone()*2, stick->getDeadZone()*2); painter.restore(); painter.save(); penny.setWidth(0); penny.setColor(Qt::black); painter.setOpacity(0.5); painter.setPen(penny); painter.scale(side / 2.0, side / 2.0); painter.translate(1, 1); // Draw Y line painter.drawLine(0, -1, 0, 1); // Draw X line painter.drawLine(-1, 0, 1, 0); painter.setOpacity(1.0); painter.restore(); painter.save(); painter.scale(side / (double)(JoyAxis::AXISMAX*2.0), side / (double)(JoyAxis::AXISMAX*2.0)); painter.translate(JoyAxis::AXISMAX, JoyAxis::AXISMAX); penny.setWidth(0); painter.setBrush(QBrush(Qt::black)); penny.setColor(Qt::black); painter.setPen(penny); // Draw raw crosshair int linexstart = stick->getXCoordinate()-1000; int lineystart = stick->getYCoordinate()-1000; if (linexstart < JoyAxis::AXISMIN) { linexstart = JoyAxis::AXISMIN; } if (lineystart < JoyAxis::AXISMIN) { lineystart = JoyAxis::AXISMIN; } painter.drawRect(linexstart, lineystart, 2000, 2000); painter.setBrush(QBrush(Qt::darkBlue)); penny.setColor(Qt::darkBlue); painter.setPen(penny); // Draw adjusted crosshair linexstart = stick->getCircleXCoordinate()-1000; lineystart = stick->getCircleYCoordinate()-1000; if (linexstart < JoyAxis::AXISMIN) { linexstart = JoyAxis::AXISMIN; } if (lineystart < JoyAxis::AXISMIN) { lineystart = JoyAxis::AXISMIN; } painter.drawRect(linexstart, lineystart, 2000, 2000); painter.restore(); // Reset pen penny.setColor(Qt::black); painter.setPen(penny); // Draw primary pixmap painter.setCompositionMode(QPainter::CompositionMode_DestinationOver); painter.setPen(Qt::NoPen); painter.fillRect(0, 0, side, side, palette().background().color()); paint.drawPixmap(pix.rect(), pix); paint.save(); paint.scale(side / (double)(JoyAxis::AXISMAX*2.0), side / (double)(JoyAxis::AXISMAX*2.0)); paint.translate(JoyAxis::AXISMAX, JoyAxis::AXISMAX); // Draw max zone and initial inner clear circle int maxzone = stick->getMaxZone(); int diffmaxzone = JoyAxis::AXISMAX - maxzone; paint.setOpacity(0.5); paint.setBrush(Qt::darkGreen); paint.drawEllipse(-JoyAxis::AXISMAX, -JoyAxis::AXISMAX, JoyAxis::AXISMAX*2, JoyAxis::AXISMAX*2); paint.setCompositionMode(QPainter::CompositionMode_Clear); paint.setPen(Qt::NoPen); paint.drawEllipse(-JoyAxis::AXISMAX+diffmaxzone, -JoyAxis::AXISMAX+diffmaxzone, JoyAxis::AXISMAX*2-(diffmaxzone*2), JoyAxis::AXISMAX*2-(diffmaxzone*2)); painter.setCompositionMode(QPainter::CompositionMode_SourceOver); paint.setOpacity(1.0); paint.restore(); // Re-draw pixmap so the inner circle will be transparent paint.setCompositionMode(QPainter::CompositionMode_DestinationOver); paint.drawPixmap(pix.rect(), pix); paint.setCompositionMode(QPainter::CompositionMode_SourceOver); } antimicro-2.23/src/joycontrolstickstatusbox.h000066400000000000000000000030151300750276700216100ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYCONTROLSTICKSTATUSBOX_H #define JOYCONTROLSTICKSTATUSBOX_H #include #include #include "joycontrolstick.h" #include "joyaxis.h" class JoyControlStickStatusBox : public QWidget { Q_OBJECT public: explicit JoyControlStickStatusBox(QWidget *parent = 0); explicit JoyControlStickStatusBox(JoyControlStick *stick, QWidget *parent = 0); void setStick(JoyControlStick *stick); JoyControlStick* getStick(); virtual int heightForWidth(int width) const; QSize sizeHint() const; protected: virtual void paintEvent(QPaintEvent *event); void drawEightWayBox(); void drawFourWayCardinalBox(); void drawFourWayDiagonalBox(); JoyControlStick *stick; signals: public slots: }; #endif // JOYCONTROLSTICKSTATUSBOX_H antimicro-2.23/src/joydpad.cpp000066400000000000000000001071761300750276700163750ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include "joydpad.h" #include "inputdevice.h" const QString JoyDPad::xmlName = "dpad"; const unsigned int JoyDPad::DEFAULTDPADDELAY = 0; JoyDPad::JoyDPad(int index, int originset, SetJoystick *parentSet, QObject *parent) : QObject(parent) { this->index = index; buttons = QHash (); activeDiagonalButton = 0; prevDirection = JoyDPadButton::DpadCentered; pendingDirection = prevDirection; this->originset = originset; currentMode = StandardMode; this->parentSet = parentSet; this->dpadDelay = DEFAULTDPADDELAY; populateButtons(); pendingEvent = false; pendingEventDirection = prevDirection; pendingIgnoreSets = false; directionDelayTimer.setSingleShot(true); connect(&directionDelayTimer, SIGNAL(timeout()), this, SLOT(dpadDirectionChangeEvent())); } JoyDPad::~JoyDPad() { QHashIterator iter(buttons); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); delete button; button = 0; } buttons.clear(); } JoyDPadButton *JoyDPad::getJoyButton(int index) { return buttons.value(index); } void JoyDPad::populateButtons() { JoyDPadButton* button = new JoyDPadButton (JoyDPadButton::DpadUp, originset, this, parentSet, this); buttons.insert(JoyDPadButton::DpadUp, button); button = new JoyDPadButton (JoyDPadButton::DpadDown, originset, this, parentSet, this); buttons.insert(JoyDPadButton::DpadDown, button); button = new JoyDPadButton(JoyDPadButton::DpadRight, originset, this, parentSet, this); buttons.insert(JoyDPadButton::DpadRight, button); button = new JoyDPadButton(JoyDPadButton::DpadLeft, originset, this, parentSet, this); buttons.insert(JoyDPadButton::DpadLeft, button); button = new JoyDPadButton(JoyDPadButton::DpadLeftUp, originset, this, parentSet, this); buttons.insert(JoyDPadButton::DpadLeftUp, button); button = new JoyDPadButton(JoyDPadButton::DpadRightUp, originset, this, parentSet, this); buttons.insert(JoyDPadButton::DpadRightUp, button); button = new JoyDPadButton(JoyDPadButton::DpadRightDown, originset, this, parentSet, this); buttons.insert(JoyDPadButton::DpadRightDown, button); button = new JoyDPadButton(JoyDPadButton::DpadLeftDown, originset, this, parentSet, this); buttons.insert(JoyDPadButton::DpadLeftDown, button); } QString JoyDPad::getName(bool fullForceFormat, bool displayNames) { QString label; if (!dpadName.isEmpty() && displayNames) { if (fullForceFormat) { label.append(tr("DPad")).append(" "); } label.append(dpadName); } else if (!defaultDPadName.isEmpty()) { if (fullForceFormat) { label.append(tr("DPad")).append(" "); } label.append(defaultDPadName); } else { label.append(tr("DPad")).append(" "); label.append(QString::number(getRealJoyNumber())); } return label; } int JoyDPad::getJoyNumber() { return index; } int JoyDPad::getIndex() { return index; } int JoyDPad::getRealJoyNumber() { return index + 1; } QString JoyDPad::getXmlName() { return this->xmlName; } void JoyDPad::readConfig(QXmlStreamReader *xml) { if (xml->isStartElement() && xml->name() == getXmlName()) { xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != getXmlName())) { bool found = readMainConfig(xml); if (!found) { xml->skipCurrentElement(); } xml->readNextStartElement(); } } } bool JoyDPad::readMainConfig(QXmlStreamReader *xml) { bool found = false; if (xml->name() == "dpadbutton" && xml->isStartElement()) { found = true; int index = xml->attributes().value("index").toString().toInt(); JoyDPadButton* button = this->getJoyButton(index); if (button) { button->readConfig(xml); } else { xml->skipCurrentElement(); } } else if (xml->name() == "mode" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); if (temptext == "eight-way") { this->setJoyMode(EightWayMode); } else if (temptext == "four-way") { this->setJoyMode(FourWayCardinal); } else if (temptext == "diagonal") { this->setJoyMode(FourWayDiagonal); } } else if (xml->name() == "dpadDelay" && xml->isStartElement()) { found = true; QString temptext = xml->readElementText(); int tempchoice = temptext.toInt(); this->setDPadDelay(tempchoice); } return found; } void JoyDPad::writeConfig(QXmlStreamWriter *xml) { if (!isDefault()) { xml->writeStartElement(getXmlName()); xml->writeAttribute("index", QString::number(index+1)); if (currentMode == EightWayMode) { xml->writeTextElement("mode", "eight-way"); } else if (currentMode == FourWayCardinal) { xml->writeTextElement("mode", "four-way"); } else if (currentMode == FourWayDiagonal) { xml->writeTextElement("mode", "diagonal"); } if (dpadDelay > DEFAULTDPADDELAY) { xml->writeTextElement("dpadDelay", QString::number(dpadDelay)); } QHashIterator iter(buttons); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); button->writeConfig(xml); } xml->writeEndElement(); } } void JoyDPad::queuePendingEvent(int value, bool ignoresets) { pendingEvent = true; pendingEventDirection = value; pendingIgnoreSets = ignoresets; } void JoyDPad::activatePendingEvent() { if (pendingEvent) { joyEvent(pendingEventDirection, pendingIgnoreSets); pendingEvent = false; pendingEventDirection = static_cast(JoyDPadButton::DpadCentered); pendingIgnoreSets = false; } } bool JoyDPad::hasPendingEvent() { return pendingEvent; } void JoyDPad::clearPendingEvent() { pendingEvent = false; pendingEventDirection = static_cast(JoyDPadButton::DpadCentered); pendingIgnoreSets = false; } void JoyDPad::joyEvent(int value, bool ignoresets) { if (value != (int)pendingDirection) { if (value != (int)JoyDPadButton::DpadCentered) { if (prevDirection == JoyDPadButton::DpadCentered) { emit active(value); } pendingDirection = (JoyDPadButton::JoyDPadDirections)value; if (ignoresets || dpadDelay == 0) { if (directionDelayTimer.isActive()) { directionDelayTimer.stop(); } createDeskEvent(ignoresets); } else if (pendingDirection != prevDirection) { if (!directionDelayTimer.isActive()) { directionDelayTimer.start(dpadDelay); } } else { if (directionDelayTimer.isActive()) { directionDelayTimer.stop(); } } } else { emit released(value); pendingDirection = JoyDPadButton::DpadCentered; if (ignoresets || dpadDelay == 0) { if (directionDelayTimer.isActive()) { directionDelayTimer.stop(); } createDeskEvent(ignoresets); } else { if (!directionDelayTimer.isActive()) { directionDelayTimer.start(dpadDelay); } } //directionDelayTimer.stop(); //createDeskEvent(ignoresets); } } } QHash* JoyDPad::getJoyButtons() { return &buttons; } int JoyDPad::getCurrentDirection() { return prevDirection; } void JoyDPad::setJoyMode(JoyMode mode) { currentMode = mode; emit joyModeChanged(); emit propertyUpdated(); } JoyDPad::JoyMode JoyDPad::getJoyMode() { return currentMode; } void JoyDPad::releaseButtonEvents() { QHashIterator iter(buttons); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); button->joyEvent(false, true); } } QHash* JoyDPad::getButtons() { return &buttons; } bool JoyDPad::isDefault() { bool value = true; value = value && (currentMode == StandardMode); value = value && (dpadDelay == DEFAULTDPADDELAY); QHashIterator iter(buttons); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); value = value && (button->isDefault()); } return value; } void JoyDPad::setButtonsMouseMode(JoyButton::JoyMouseMovementMode mode) { QHashIterator iter(buttons); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); button->setMouseMode(mode); } } bool JoyDPad::hasSameButtonsMouseMode() { bool result = true; JoyButton::JoyMouseMovementMode initialMode = JoyButton::MouseCursor; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyDPadButton *button = iter.next().value(); initialMode = button->getMouseMode(); } else { JoyDPadButton *button = iter.next().value(); JoyButton::JoyMouseMovementMode temp = button->getMouseMode(); if (temp != initialMode) { result = false; iter.toBack(); } } } return result; } JoyButton::JoyMouseMovementMode JoyDPad::getButtonsPresetMouseMode() { JoyButton::JoyMouseMovementMode resultMode = JoyButton::MouseCursor; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyDPadButton *button = iter.next().value(); resultMode = button->getMouseMode(); } else { JoyDPadButton *button = iter.next().value(); JoyButton::JoyMouseMovementMode temp = button->getMouseMode(); if (temp != resultMode) { resultMode = JoyButton::MouseCursor; iter.toBack(); } } } return resultMode; } void JoyDPad::setButtonsMouseCurve(JoyButton::JoyMouseCurve mouseCurve) { QHashIterator iter(buttons); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); button->setMouseCurve(mouseCurve); } } bool JoyDPad::hasSameButtonsMouseCurve() { bool result = true; JoyButton::JoyMouseCurve initialCurve = JoyButton::LinearCurve; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyDPadButton *button = iter.next().value(); initialCurve = button->getMouseCurve(); } else { JoyDPadButton *button = iter.next().value(); JoyButton::JoyMouseCurve temp = button->getMouseCurve(); if (temp != initialCurve) { result = false; iter.toBack(); } } } return result; } JoyButton::JoyMouseCurve JoyDPad::getButtonsPresetMouseCurve() { JoyButton::JoyMouseCurve resultCurve = JoyButton::LinearCurve; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyDPadButton *button = iter.next().value(); resultCurve = button->getMouseCurve(); } else { JoyDPadButton *button = iter.next().value(); JoyButton::JoyMouseCurve temp = button->getMouseCurve(); if (temp != resultCurve) { resultCurve = JoyButton::LinearCurve; iter.toBack(); } } } return resultCurve; } void JoyDPad::setButtonsSpringWidth(int value) { QHashIterator iter(buttons); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); button->setSpringWidth(value); } } void JoyDPad::setButtonsSpringHeight(int value) { QHashIterator iter(buttons); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); button->setSpringHeight(value); } } int JoyDPad::getButtonsPresetSpringWidth() { int presetSpringWidth = 0; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyDPadButton *button = iter.next().value(); presetSpringWidth = button->getSpringWidth(); } else { JoyDPadButton *button = iter.next().value(); int temp = button->getSpringWidth(); if (temp != presetSpringWidth) { presetSpringWidth = 0; iter.toBack(); } } } return presetSpringWidth; } int JoyDPad::getButtonsPresetSpringHeight() { int presetSpringHeight = 0; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyDPadButton *button = iter.next().value(); presetSpringHeight = button->getSpringHeight(); } else { JoyDPadButton *button = iter.next().value(); int temp = button->getSpringHeight(); if (temp != presetSpringHeight) { presetSpringHeight = 0; iter.toBack(); } } } return presetSpringHeight; } void JoyDPad::setButtonsSensitivity(double value) { QHashIterator iter(buttons); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); button->setSensitivity(value); } } double JoyDPad::getButtonsPresetSensitivity() { double presetSensitivity = 1.0; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyDPadButton *button = iter.next().value(); presetSensitivity = button->getSensitivity(); } else { JoyDPadButton *button = iter.next().value(); double temp = button->getSensitivity(); if (temp != presetSensitivity) { presetSensitivity = 1.0; iter.toBack(); } } } return presetSensitivity; } QHash JoyDPad::getApplicableButtons() { QHash temphash; if (currentMode == StandardMode || currentMode == EightWayMode || currentMode == FourWayCardinal) { temphash.insert(JoyDPadButton::DpadUp, buttons.value(JoyDPadButton::DpadUp)); temphash.insert(JoyDPadButton::DpadDown, buttons.value(JoyDPadButton::DpadDown)); temphash.insert(JoyDPadButton::DpadLeft, buttons.value(JoyDPadButton::DpadLeft)); temphash.insert(JoyDPadButton::DpadRight, buttons.value(JoyDPadButton::DpadRight)); } if (currentMode == EightWayMode || currentMode == FourWayDiagonal) { temphash.insert(JoyDPadButton::DpadLeftUp, buttons.value(JoyDPadButton::DpadLeftUp)); temphash.insert(JoyDPadButton::DpadRightUp, buttons.value(JoyDPadButton::DpadRightUp)); temphash.insert(JoyDPadButton::DpadRightDown, buttons.value(JoyDPadButton::DpadRightDown)); temphash.insert(JoyDPadButton::DpadLeftDown, buttons.value(JoyDPadButton::DpadLeftDown)); } return temphash; } void JoyDPad::setDPadName(QString tempName) { if (tempName.length() <= 20 && tempName != dpadName) { dpadName = tempName; emit dpadNameChanged(); emit propertyUpdated(); } } QString JoyDPad::getDpadName() { return dpadName; } void JoyDPad::setButtonsWheelSpeedX(int value) { QHashIterator iter(buttons); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); button->setWheelSpeedX(value); } } void JoyDPad::setButtonsWheelSpeedY(int value) { QHashIterator iter(buttons); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); button->setWheelSpeedY(value); } } void JoyDPad::setDefaultDPadName(QString tempname) { defaultDPadName = tempname; emit dpadNameChanged(); } QString JoyDPad::getDefaultDPadName() { return defaultDPadName; } SetJoystick* JoyDPad::getParentSet() { return parentSet; } void JoyDPad::establishPropertyUpdatedConnection() { connect(this, SIGNAL(propertyUpdated()), getParentSet()->getInputDevice(), SLOT(profileEdited())); } void JoyDPad::disconnectPropertyUpdatedConnection() { disconnect(this, SIGNAL(propertyUpdated()), getParentSet()->getInputDevice(), SLOT(profileEdited())); } bool JoyDPad::hasSlotsAssigned() { bool hasSlots = false; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); if (button) { if (button->getAssignedSlots()->count() > 0) { hasSlots = true; iter.toBack(); } } } return hasSlots; } void JoyDPad::setButtonsSpringRelativeStatus(bool value) { QHashIterator iter(buttons); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); button->setSpringRelativeStatus(value); } } bool JoyDPad::isRelativeSpring() { bool relative = false; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyDPadButton *button = iter.next().value(); relative = button->isRelativeSpring(); } else { JoyDPadButton *button = iter.next().value(); bool temp = button->isRelativeSpring(); if (temp != relative) { relative = false; iter.toBack(); } } } return relative; } void JoyDPad::copyAssignments(JoyDPad *destDPad) { destDPad->activeDiagonalButton = activeDiagonalButton; destDPad->prevDirection = prevDirection; destDPad->currentMode = currentMode; destDPad->dpadDelay = dpadDelay; QHashIterator iter(destDPad->buttons); while (iter.hasNext()) { JoyDPadButton *destButton = iter.next().value(); if (destButton) { JoyDPadButton *sourceButton = buttons.value(destButton->getDirection()); if (sourceButton) { sourceButton->copyAssignments(destButton); } } } if (!destDPad->isDefault()) { emit propertyUpdated(); } } void JoyDPad::createDeskEvent(bool ignoresets) { JoyDPadButton *curButton = 0; JoyDPadButton *prevButton = 0; JoyDPadButton::JoyDPadDirections value = pendingDirection; if (pendingDirection != prevDirection) { if (activeDiagonalButton) { activeDiagonalButton->joyEvent(false, ignoresets); activeDiagonalButton = 0; } else { if (currentMode == StandardMode) { if ((prevDirection & JoyDPadButton::DpadUp) && (!(value & JoyDPadButton::DpadUp))) { prevButton = buttons.value(JoyDPadButton::DpadUp); prevButton->joyEvent(false, ignoresets); } if ((prevDirection & JoyDPadButton::DpadDown) && (!(value & JoyDPadButton::DpadDown))) { prevButton = buttons.value(JoyDPadButton::DpadDown); prevButton->joyEvent(false, ignoresets); } if ((prevDirection & JoyDPadButton::DpadLeft) && (!(value & JoyDPadButton::DpadLeft))) { prevButton = buttons.value(JoyDPadButton::DpadLeft); prevButton->joyEvent(false, ignoresets); } if ((prevDirection & JoyDPadButton::DpadRight) && (!(value & JoyDPadButton::DpadRight))) { prevButton = buttons.value(JoyDPadButton::DpadRight); prevButton->joyEvent(false, ignoresets); } } else if (currentMode == EightWayMode && prevDirection) { prevButton = buttons.value(prevDirection); prevButton->joyEvent(false, ignoresets); } else if (currentMode == FourWayCardinal && prevDirection) { if ((prevDirection == JoyDPadButton::DpadUp || prevDirection == JoyDPadButton::DpadRightUp) && (value != JoyDPadButton::DpadUp && value != JoyDPadButton::DpadRightUp)) { prevButton = buttons.value(JoyDPadButton::DpadUp); } else if ((prevDirection == JoyDPadButton::DpadDown || prevDirection == JoyDPadButton::DpadLeftDown) && (value != JoyDPadButton::DpadDown && value != JoyDPadButton::DpadLeftDown)) { prevButton = buttons.value(JoyDPadButton::DpadDown); } else if ((prevDirection == JoyDPadButton::DpadLeft || prevDirection == JoyDPadButton::DpadLeftUp) && (value != JoyDPadButton::DpadLeft && value != JoyDPadButton::DpadLeftUp)) { prevButton = buttons.value(JoyDPadButton::DpadLeft); } else if ((prevDirection == JoyDPadButton::DpadRight || prevDirection == JoyDPadButton::DpadRightDown) && (value != JoyDPadButton::DpadRight && value != JoyDPadButton::DpadRightDown)) { prevButton = buttons.value(JoyDPadButton::DpadRight); } if (prevButton) { prevButton->joyEvent(false, ignoresets); } } else if (currentMode == FourWayDiagonal && prevDirection) { prevButton = buttons.value(prevDirection); prevButton->joyEvent(false, ignoresets); } } if (currentMode == StandardMode) { if ((value & JoyDPadButton::DpadUp) && (!(prevDirection & JoyDPadButton::DpadUp))) { curButton = buttons.value(JoyDPadButton::DpadUp); curButton->joyEvent(true, ignoresets); } if ((value & JoyDPadButton::DpadDown) && (!(prevDirection & JoyDPadButton::DpadDown))) { curButton = buttons.value(JoyDPadButton::DpadDown); curButton->joyEvent(true, ignoresets); } if ((value & JoyDPadButton::DpadLeft) && (!(prevDirection & JoyDPadButton::DpadLeft))) { curButton = buttons.value(JoyDPadButton::DpadLeft); curButton->joyEvent(true, ignoresets); } if ((value & JoyDPadButton::DpadRight) && (!(prevDirection & JoyDPadButton::DpadRight))) { curButton = buttons.value(JoyDPadButton::DpadRight); curButton->joyEvent(true, ignoresets); } } else if (currentMode == EightWayMode) { if (value == JoyDPadButton::DpadLeftUp) { activeDiagonalButton = buttons.value(JoyDPadButton::DpadLeftUp); activeDiagonalButton->joyEvent(true, ignoresets); } else if (value == JoyDPadButton::DpadRightUp) { activeDiagonalButton = buttons.value(JoyDPadButton::DpadRightUp); activeDiagonalButton->joyEvent(true, ignoresets); } else if (value == JoyDPadButton::DpadRightDown) { activeDiagonalButton = buttons.value(JoyDPadButton::DpadRightDown); activeDiagonalButton->joyEvent(true, ignoresets); } else if (value == JoyDPadButton::DpadLeftDown) { activeDiagonalButton = buttons.value(JoyDPadButton::DpadLeftDown); activeDiagonalButton->joyEvent(true, ignoresets); } else if (value == JoyDPadButton::DpadUp) { curButton = buttons.value(JoyDPadButton::DpadUp); curButton->joyEvent(true, ignoresets); } else if (value == JoyDPadButton::DpadDown) { curButton = buttons.value(JoyDPadButton::DpadDown); curButton->joyEvent(true, ignoresets); } else if (value == JoyDPadButton::DpadLeft) { curButton = buttons.value(JoyDPadButton::DpadLeft); curButton->joyEvent(true, ignoresets); } else if (value == JoyDPadButton::DpadRight) { curButton = buttons.value(JoyDPadButton::DpadRight); curButton->joyEvent(true, ignoresets); } } else if (currentMode == FourWayCardinal) { if (value == JoyDPadButton::DpadUp || value == JoyDPadButton::DpadRightUp) { curButton = buttons.value(JoyDPadButton::DpadUp); curButton->joyEvent(true, ignoresets); } else if (value == JoyDPadButton::DpadDown || value == JoyDPadButton::DpadLeftDown) { curButton = buttons.value(JoyDPadButton::DpadDown); curButton->joyEvent(true, ignoresets); } else if (value == JoyDPadButton::DpadLeft || value == JoyDPadButton::DpadLeftUp) { curButton = buttons.value(JoyDPadButton::DpadLeft); curButton->joyEvent(true, ignoresets); } else if (value == JoyDPadButton::DpadRight || value == JoyDPadButton::DpadRightDown) { curButton = buttons.value(JoyDPadButton::DpadRight); curButton->joyEvent(true, ignoresets); } } else if (currentMode == FourWayDiagonal) { if (value == JoyDPadButton::DpadLeftUp) { activeDiagonalButton = buttons.value(JoyDPadButton::DpadLeftUp); activeDiagonalButton->joyEvent(true, ignoresets); } else if (value == JoyDPadButton::DpadRightUp) { activeDiagonalButton = buttons.value(JoyDPadButton::DpadRightUp); activeDiagonalButton->joyEvent(true, ignoresets); } else if (value == JoyDPadButton::DpadRightDown) { activeDiagonalButton = buttons.value(JoyDPadButton::DpadRightDown); activeDiagonalButton->joyEvent(true, ignoresets); } else if (value == JoyDPadButton::DpadLeftDown) { activeDiagonalButton = buttons.value(JoyDPadButton::DpadLeftDown); activeDiagonalButton->joyEvent(true, ignoresets); } } prevDirection = pendingDirection; } } void JoyDPad::dpadDirectionChangeEvent() { createDeskEvent(); } void JoyDPad::setDPadDelay(int value) { if ((value >= 10 && value <= 1000) || (value == 0)) { this->dpadDelay = value; emit dpadDelayChanged(value); emit propertyUpdated(); } } unsigned int JoyDPad::getDPadDelay() { return dpadDelay; } void JoyDPad::setButtonsEasingDuration(double value) { QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); button->setEasingDuration(value); } } double JoyDPad::getButtonsEasingDuration() { double result = JoyButton::DEFAULTEASINGDURATION; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyDPadButton *button = iter.next().value(); result = button->getEasingDuration(); } else { JoyDPadButton *button = iter.next().value(); double temp = button->getEasingDuration(); if (temp != result) { result = JoyButton::DEFAULTEASINGDURATION; iter.toBack(); } } } return result; } void JoyDPad::setButtonsSpringDeadCircleMultiplier(int value) { QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); button->setSpringDeadCircleMultiplier(value); } } int JoyDPad::getButtonsSpringDeadCircleMultiplier() { int result = JoyButton::DEFAULTSPRINGRELEASERADIUS; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyDPadButton *button = iter.next().value(); result = button->getSpringDeadCircleMultiplier(); } else { JoyDPadButton *button = iter.next().value(); int temp = button->getSpringDeadCircleMultiplier(); if (temp != result) { result = JoyButton::DEFAULTSPRINGRELEASERADIUS; iter.toBack(); } } } return result; } void JoyDPad::setButtonsExtraAccelerationCurve(JoyButton::JoyExtraAccelerationCurve curve) { QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); button->setExtraAccelerationCurve(curve); } } JoyButton::JoyExtraAccelerationCurve JoyDPad::getButtonsExtraAccelerationCurve() { JoyButton::JoyExtraAccelerationCurve result = JoyButton::LinearAccelCurve; QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { if (!iter.hasPrevious()) { JoyDPadButton *button = iter.next().value(); result = button->getExtraAccelerationCurve(); } else { JoyDPadButton *button = iter.next().value(); JoyButton::JoyExtraAccelerationCurve temp = button->getExtraAccelerationCurve(); if (temp != result) { result = JoyButton::LinearAccelCurve; iter.toBack(); } } } return result; } QHash JoyDPad::getDirectionButtons(JoyDPadButton::JoyDPadDirections direction) { QHash temphash; if (currentMode == StandardMode) { if (direction & JoyDPadButton::DpadUp) { temphash.insert(JoyDPadButton::DpadUp, buttons.value(JoyDPadButton::DpadUp)); } if (direction & JoyDPadButton::DpadDown) { temphash.insert(JoyDPadButton::DpadDown, buttons.value(JoyDPadButton::DpadDown)); } if (direction & JoyDPadButton::DpadLeft) { temphash.insert(JoyDPadButton::DpadLeft, buttons.value(JoyDPadButton::DpadLeft)); } if (direction & JoyDPadButton::DpadRight) { temphash.insert(JoyDPadButton::DpadRight, buttons.value(JoyDPadButton::DpadRight)); } } else if (currentMode == EightWayMode) { if (direction != JoyDPadButton::DpadCentered) { temphash.insert(direction, buttons.value(direction)); } } else if (currentMode == FourWayCardinal) { if (direction == JoyDPadButton::DpadUp || direction == JoyDPadButton::DpadDown || direction == JoyDPadButton::DpadLeft || direction == JoyDPadButton::DpadRight) { temphash.insert(direction, buttons.value(direction)); } } else if (currentMode == FourWayDiagonal) { if (direction == JoyDPadButton::DpadRightUp || direction == JoyDPadButton::DpadRightDown || direction == JoyDPadButton::DpadLeftDown || direction == JoyDPadButton::DpadLeftUp) { temphash.insert(direction, buttons.value(direction)); } } return temphash; } void JoyDPad::setDirButtonsUpdateInitAccel(JoyDPadButton::JoyDPadDirections direction, bool state) { QHash apphash = getDirectionButtons(direction); QHashIterator iter(apphash); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); if (button) { button->setUpdateInitAccel(state); } } } void JoyDPad::copyLastDistanceValues(JoyDPad *srcDPad) { QHash apphash = srcDPad->getApplicableButtons(); QHashIterator iter(apphash); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); if (button && button->getButtonState()) { this->buttons.value(iter.key())->copyLastAccelerationDistance(button); this->buttons.value(iter.key())->copyLastMouseDistanceFromDeadZone(button); } } } void JoyDPad::eventReset() { QHash temphash = getApplicableButtons(); QHashIterator iter(temphash); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); button->eventReset(); } } antimicro-2.23/src/joydpad.h000066400000000000000000000113741300750276700160340ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYDPAD_H #define JOYDPAD_H #include #include #include #include #include #include #include "joybuttontypes/joydpadbutton.h" class JoyDPad : public QObject { Q_OBJECT public: explicit JoyDPad(int index, int originset, SetJoystick *parentSet, QObject *parent=0); ~JoyDPad(); enum JoyMode {StandardMode=0, EightWayMode, FourWayCardinal, FourWayDiagonal}; JoyDPadButton* getJoyButton(int index); QHash* getJoyButtons(); int getCurrentDirection(); int getJoyNumber(); int getIndex(); int getRealJoyNumber(); virtual QString getName(bool fullForceFormat=false, bool displayNames=false); void joyEvent(int value, bool ignoresets=false); void queuePendingEvent(int value, bool ignoresets=false); void activatePendingEvent(); bool hasPendingEvent(); void clearPendingEvent(); void setJoyMode(JoyMode mode); JoyMode getJoyMode(); void releaseButtonEvents(); void setButtonsMouseMode(JoyButton::JoyMouseMovementMode mode); bool hasSameButtonsMouseMode(); JoyButton::JoyMouseMovementMode getButtonsPresetMouseMode(); void setButtonsMouseCurve(JoyButton::JoyMouseCurve mouseCurve); bool hasSameButtonsMouseCurve(); JoyButton::JoyMouseCurve getButtonsPresetMouseCurve(); void setButtonsSpringWidth(int value); int getButtonsPresetSpringWidth(); void setButtonsSpringHeight(int value); int getButtonsPresetSpringHeight(); void setButtonsSensitivity(double value); double getButtonsPresetSensitivity(); void setButtonsWheelSpeedX(int value); void setButtonsWheelSpeedY(int value); QString getDpadName(); virtual bool isDefault(); QHash* getButtons(); void readConfig(QXmlStreamReader *xml); void writeConfig(QXmlStreamWriter *xml); virtual QString getXmlName(); virtual void setDefaultDPadName(QString tempname); virtual QString getDefaultDPadName(); SetJoystick* getParentSet(); bool hasSlotsAssigned(); bool isRelativeSpring(); void copyAssignments(JoyDPad *destDPad); unsigned int getDPadDelay(); double getButtonsEasingDuration(); void setButtonsSpringDeadCircleMultiplier(int value); int getButtonsSpringDeadCircleMultiplier(); void setButtonsExtraAccelerationCurve(JoyButton::JoyExtraAccelerationCurve curve); JoyButton::JoyExtraAccelerationCurve getButtonsExtraAccelerationCurve(); QHash getDirectionButtons(JoyDPadButton::JoyDPadDirections direction); void setDirButtonsUpdateInitAccel(JoyDPadButton::JoyDPadDirections direction, bool state); void copyLastDistanceValues(JoyDPad *srcDPad); virtual void eventReset(); static const QString xmlName; static const unsigned int DEFAULTDPADDELAY; protected: void populateButtons(); void createDeskEvent(bool ignoresets = false); QHash getApplicableButtons(); bool readMainConfig(QXmlStreamReader *xml); QHash buttons; int index; JoyDPadButton::JoyDPadDirections prevDirection; JoyDPadButton::JoyDPadDirections pendingDirection; JoyDPadButton *activeDiagonalButton; int originset; JoyMode currentMode; QString dpadName; QString defaultDPadName; SetJoystick *parentSet; QTimer directionDelayTimer; unsigned int dpadDelay; bool pendingEvent; int pendingEventDirection; bool pendingIgnoreSets; signals: void active(int value); void released(int value); void dpadNameChanged(); void dpadDelayChanged(int value); void joyModeChanged(); void propertyUpdated(); public slots: void setDPadName(QString tempName); void setButtonsSpringRelativeStatus(bool value); void setDPadDelay(int value); void setButtonsEasingDuration(double value); void establishPropertyUpdatedConnection(); void disconnectPropertyUpdatedConnection(); private slots: void dpadDirectionChangeEvent(); }; #endif // JOYDPAD_H antimicro-2.23/src/joydpadbuttonwidget.cpp000066400000000000000000000026301300750276700210220ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "joydpadbuttonwidget.h" JoyDPadButtonWidget::JoyDPadButtonWidget(JoyButton *button, bool displayNames, QWidget *parent) : JoyButtonWidget(button, displayNames, parent) { // Ensure that JoyDPadButtonWidget::generateLabel is called. refreshLabel(); } /** * @brief Generate the string that will be displayed on the button * @return Display string */ QString JoyDPadButtonWidget::generateLabel() { QString temp; if (!button->getActionName().isEmpty() && displayNames) { temp = button->getActionName(); } else { temp = button->getCalculatedActiveZoneSummary(); } temp.replace("&", "&&"); return temp; } antimicro-2.23/src/joydpadbuttonwidget.h000066400000000000000000000021501300750276700204640ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYDPADBUTTONWIDGET_H #define JOYDPADBUTTONWIDGET_H #include "joybuttonwidget.h" class JoyDPadButtonWidget : public JoyButtonWidget { Q_OBJECT public: explicit JoyDPadButtonWidget(JoyButton* button, bool displayNames, QWidget *parent = 0); protected: virtual QString generateLabel(); signals: public slots: }; #endif // JOYDPADBUTTONWIDGET_H antimicro-2.23/src/joykeyrepeathelper.cpp000066400000000000000000000040131300750276700206400ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "joykeyrepeathelper.h" #include "event.h" JoyKeyRepeatHelper::JoyKeyRepeatHelper(QObject *parent) : QObject(parent) { lastActiveKey = 0; keyRepeatTimer.setParent(this); connect(&keyRepeatTimer, SIGNAL(timeout()), this, SLOT(repeatKeysEvent())); } QTimer* JoyKeyRepeatHelper::getRepeatTimer() { return &keyRepeatTimer; } void JoyKeyRepeatHelper::repeatKeysEvent() { if (lastActiveKey) { JoyButtonSlot *slot = lastActiveKey; // Send another key press to fake a key repeat sendevent(slot); keyRepeatTimer.start(keyRepeatRate); } else { keyRepeatTimer.stop(); } } void JoyKeyRepeatHelper::setLastActiveKey(JoyButtonSlot *slot) { lastActiveKey = slot; } JoyButtonSlot* JoyKeyRepeatHelper::getLastActiveKey() { return lastActiveKey; } /*void JoyKeyRepeatHelper::setKeyRepeatDelay(unsigned int repeatDelay) { if (repeatDelay > 0) { keyRepeatDelay = repeatDelay; } } unsigned int JoyKeyRepeatHelper::getKeyRepeatDelay() { return keyRepeatDelay; } */ void JoyKeyRepeatHelper::setKeyRepeatRate(unsigned int repeatRate) { if (repeatRate > 0) { keyRepeatRate = repeatRate; } } unsigned int JoyKeyRepeatHelper::getKeyRepeatRate() { return keyRepeatRate; } antimicro-2.23/src/joykeyrepeathelper.h000066400000000000000000000027741300750276700203210ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYKEYREPEATHELPER_H #define JOYKEYREPEATHELPER_H #include #include #include "joybuttonslot.h" class JoyKeyRepeatHelper : public QObject { Q_OBJECT public: explicit JoyKeyRepeatHelper(QObject *parent = 0); QTimer* getRepeatTimer(); void setLastActiveKey(JoyButtonSlot *slot); JoyButtonSlot* getLastActiveKey(); //void setKeyRepeatDelay(unsigned int repeatDelay); //unsigned int getKeyRepeatDelay(); void setKeyRepeatRate(unsigned int repeatRate); unsigned int getKeyRepeatRate(); protected: QTimer keyRepeatTimer; JoyButtonSlot *lastActiveKey; unsigned int keyRepeatDelay; unsigned int keyRepeatRate; signals: private slots: void repeatKeysEvent(); }; #endif // JOYKEYREPEATHELPER_H antimicro-2.23/src/joystick.cpp000066400000000000000000000054661300750276700166010ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include "joystick.h" const QString Joystick::xmlName = "joystick"; Joystick::Joystick(SDL_Joystick *joyhandle, int deviceIndex, AntiMicroSettings *settings, QObject *parent) : InputDevice(deviceIndex, settings, parent) { this->joyhandle = joyhandle; #ifdef USE_SDL_2 joystickID = SDL_JoystickInstanceID(joyhandle); #else joyNumber = SDL_JoystickIndex(joyhandle); #endif for (int i=0; i < NUMBER_JOYSETS; i++) { SetJoystick *setstick = new SetJoystick(this, i, this); joystick_sets.insert(i, setstick); enableSetConnections(setstick); } } QString Joystick::getName() { return QString(tr("Joystick")).append(" ").append(QString::number(getRealJoyNumber())); } QString Joystick::getSDLName() { QString temp; #ifdef USE_SDL_2 if (joyhandle) { temp = SDL_JoystickName(joyhandle); } #else temp = SDL_JoystickName(joyNumber); #endif return temp; } QString Joystick::getGUIDString() { QString temp; #ifdef USE_SDL_2 SDL_JoystickGUID tempGUID = SDL_JoystickGetGUID(joyhandle); char guidString[65] = {'0'}; SDL_JoystickGetGUIDString(tempGUID, guidString, sizeof(guidString)); temp = QString(guidString); #endif // Not available on SDL 1.2. Return empty string in that case. return temp; } QString Joystick::getXmlName() { return this->xmlName; } void Joystick::closeSDLDevice() { #ifdef USE_SDL_2 if (joyhandle && SDL_JoystickGetAttached(joyhandle)) { SDL_JoystickClose(joyhandle); } #else if (joyhandle && SDL_JoystickOpened(joyNumber)) { SDL_JoystickClose(joyhandle); } #endif } int Joystick::getNumberRawButtons() { int numbuttons = SDL_JoystickNumButtons(joyhandle); return numbuttons; } int Joystick::getNumberRawAxes() { int numaxes = SDL_JoystickNumAxes(joyhandle); return numaxes; } int Joystick::getNumberRawHats() { int numhats = SDL_JoystickNumHats(joyhandle); return numhats; } #ifdef USE_SDL_2 SDL_JoystickID Joystick::getSDLJoystickID() { return joystickID; } #endif antimicro-2.23/src/joystick.h000066400000000000000000000031121300750276700162300ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYSTICK_H #define JOYSTICK_H #include #include #include #include "inputdevice.h" class Joystick : public InputDevice { Q_OBJECT public: explicit Joystick(SDL_Joystick *joyhandle, int deviceIndex, AntiMicroSettings *settings, QObject *parent=0); virtual QString getName(); virtual QString getSDLName(); virtual QString getGUIDString(); // GUID available on SDL 2. virtual QString getXmlName(); virtual void closeSDLDevice(); #ifdef USE_SDL_2 virtual SDL_JoystickID getSDLJoystickID(); #endif virtual int getNumberRawButtons(); virtual int getNumberRawAxes(); virtual int getNumberRawHats(); static const QString xmlName; protected: SDL_Joystick *joyhandle; signals: public slots: }; Q_DECLARE_METATYPE(Joystick*) #endif // JOYSTICK_H antimicro-2.23/src/joystickstatuswindow.cpp000066400000000000000000000143501300750276700212650ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include #include #include #include #include "joystickstatuswindow.h" #include "ui_joystickstatuswindow.h" #include "joybuttonstatusbox.h" JoystickStatusWindow::JoystickStatusWindow(InputDevice *joystick, QWidget *parent) : QDialog(parent), ui(new Ui::JoystickStatusWindow) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); this->joystick = joystick; PadderCommon::inputDaemonMutex.lock(); setWindowTitle(tr("%1 (#%2) Properties").arg(joystick->getSDLName()) .arg(joystick->getRealJoyNumber())); ui->joystickNameLabel->setText(joystick->getSDLName()); ui->joystickNumberLabel->setText(QString::number(joystick->getRealJoyNumber())); ui->joystickAxesLabel->setText(QString::number(joystick->getNumberRawAxes())); ui->joystickButtonsLabel->setText(QString::number(joystick->getNumberRawButtons())); ui->joystickHatsLabel->setText(QString::number(joystick->getNumberRawHats())); joystick->getActiveSetJoystick()->setIgnoreEventState(true); joystick->getActiveSetJoystick()->release(); joystick->resetButtonDownCount(); QVBoxLayout *axesBox = new QVBoxLayout(); axesBox->setSpacing(4); for (int i=0; i < joystick->getNumberAxes(); i++) { JoyAxis *axis = joystick->getActiveSetJoystick()->getJoyAxis(i); if (axis) { QHBoxLayout *hbox = new QHBoxLayout(); QLabel *axisLabel = new QLabel(); axisLabel->setText(tr("Axis %1").arg(axis->getRealJoyIndex())); QProgressBar *axisBar = new QProgressBar(); axisBar->setMinimum(JoyAxis::AXISMIN); axisBar->setMaximum(JoyAxis::AXISMAX); axisBar->setFormat("%v"); axisBar->setValue(axis->getCurrentRawValue()); hbox->addWidget(axisLabel); hbox->addWidget(axisBar); hbox->addSpacing(10); axesBox->addLayout(hbox); connect(axis, SIGNAL(moved(int)), axisBar, SLOT(setValue(int))); } } ui->axesScrollArea->setLayout(axesBox); QGridLayout *buttonsGrid = new QGridLayout(); buttonsGrid->setHorizontalSpacing(10); buttonsGrid->setVerticalSpacing(10); int currentRow = 0; int currentColumn = 0; for (int i=0; i < joystick->getNumberButtons(); i++) { JoyButton *button = joystick->getActiveSetJoystick()->getJoyButton(i); if (button) { JoyButtonStatusBox *statusbox = new JoyButtonStatusBox(button); statusbox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); buttonsGrid->addWidget(statusbox, currentRow, currentColumn); currentColumn++; if (currentColumn >= 6) { currentRow++; currentColumn = 0; } } } ui->buttonsScrollArea->setLayout(buttonsGrid); QVBoxLayout *hatsBox = new QVBoxLayout(); hatsBox->setSpacing(4); for (int i=0; i < joystick->getNumberHats(); i++) { JoyDPad *dpad = joystick->getActiveSetJoystick()->getJoyDPad(i); if (dpad) { QHBoxLayout *hbox = new QHBoxLayout(); QLabel *dpadLabel = new QLabel(); dpadLabel->setText(tr("Hat %1").arg(dpad->getRealJoyNumber())); QProgressBar *dpadBar = new QProgressBar(); dpadBar->setMinimum(JoyDPadButton::DpadCentered); dpadBar->setMaximum(JoyDPadButton::DpadLeftDown); dpadBar->setFormat("%v"); dpadBar->setValue(dpad->getCurrentDirection()); hbox->addWidget(dpadLabel); hbox->addWidget(dpadBar); hbox->addSpacing(10); hatsBox->addLayout(hbox); connect(dpad, SIGNAL(active(int)), dpadBar, SLOT(setValue(int))); connect(dpad, SIGNAL(released(int)), dpadBar, SLOT(setValue(int))); } } hatsBox->addSpacerItem(new QSpacerItem(20, 20, QSizePolicy::Preferred, QSizePolicy::Fixed)); if (ui->hatsGroupBox->layout()) { delete ui->hatsGroupBox->layout(); } ui->hatsGroupBox->setLayout(hatsBox); QString guidString = joystick->getGUIDString(); if (!guidString.isEmpty()) { ui->guidHeaderLabel->show(); ui->guidLabel->setText(guidString); ui->guidLabel->show(); } else { ui->guidHeaderLabel->hide(); ui->guidLabel->hide(); } #ifdef USE_SDL_2 QString usingGameController = tr("No"); if (joystick->isGameController()) { usingGameController = tr("Yes"); } ui->sdlGameControllerLabel->setText(usingGameController); #else ui->sdlcontrollerHeaderLabel->setVisible(false); ui->sdlGameControllerLabel->setVisible(false); #endif PadderCommon::inputDaemonMutex.unlock(); connect(joystick, SIGNAL(destroyed()), this, SLOT(obliterate())); connect(this, SIGNAL(finished(int)), this, SLOT(restoreButtonStates(int))); } JoystickStatusWindow::~JoystickStatusWindow() { delete ui; } void JoystickStatusWindow::restoreButtonStates(int code) { if (code == QDialogButtonBox::AcceptRole) { PadderCommon::inputDaemonMutex.lock(); joystick->getActiveSetJoystick()->setIgnoreEventState(false); joystick->getActiveSetJoystick()->release(); PadderCommon::inputDaemonMutex.unlock(); } } void JoystickStatusWindow::obliterate() { this->done(QDialogButtonBox::DestructiveRole); } antimicro-2.23/src/joystickstatuswindow.h000066400000000000000000000024061300750276700207310ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYSTICKSTATUSWINDOW_H #define JOYSTICKSTATUSWINDOW_H #include #include "inputdevice.h" namespace Ui { class JoystickStatusWindow; } class JoystickStatusWindow : public QDialog { Q_OBJECT public: explicit JoystickStatusWindow(InputDevice *joystick, QWidget *parent = 0); ~JoystickStatusWindow(); protected: InputDevice *joystick; private: Ui::JoystickStatusWindow *ui; private slots: void restoreButtonStates(int code); void obliterate(); }; #endif // JOYSTICKSTATUSWINDOW_H antimicro-2.23/src/joystickstatuswindow.ui000066400000000000000000000320511300750276700211160ustar00rootroot00000000000000 JoystickStatusWindow Qt::ApplicationModal 0 0 580 480 580 440 Properties JoyButtonStatusBox { border: 1px solid rgb(0, 0, 0); } JoyButtonStatusBox[isflashing="true"] { background-color: rgb(0, 0, 255); color: rgb(205, 197, 191); } true 200 0 Details 75 true Name: %1 10 75 true Number: %1 10 75 true Axes: %1 10 75 true Buttons: %1 10 75 true Hats: %1 10 true 75 true GUID: %1 true 10 Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse true 75 true Game Controller: %1 true 10 Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse Axes 4 4 4 4 QFrame::NoFrame QFrame::Sunken 1 true 0 0 338 142 Qt::Vertical QSizePolicy::Fixed 20 10 Buttons 4 4 4 4 false QFrame::NoFrame true 0 0 338 141 Qt::Vertical QSizePolicy::Fixed 20 10 Hats 4 4 4 14 Qt::Horizontal QDialogButtonBox::Close buttonBox accepted() JoystickStatusWindow accept() 248 254 157 274 buttonBox rejected() JoystickStatusWindow reject() 316 260 286 274 antimicro-2.23/src/joytabwidget.cpp000066400000000000000000002402651300750276700174340ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include #include #include #include #include #include "joytabwidget.h" #include "joyaxiswidget.h" #include "joybuttonwidget.h" #include "xmlconfigreader.h" #include "xmlconfigwriter.h" #include "buttoneditdialog.h" #include "advancestickassignmentdialog.h" #include "quicksetdialog.h" #include "extraprofilesettingsdialog.h" #include "setnamesdialog.h" #include "stickpushbuttongroup.h" #include "dpadpushbuttongroup.h" #include "common.h" #ifdef USE_SDL_2 #include "gamecontroller/gamecontroller.h" #include "gamecontrollermappingdialog.h" #endif JoyTabWidget::JoyTabWidget(InputDevice *joystick, AntiMicroSettings *settings, QWidget *parent) : QWidget(parent), tabHelper(joystick) { this->joystick = joystick; this->settings = settings; tabHelper.moveToThread(joystick->thread()); comboBoxIndex = 0; hideEmptyButtons = false; verticalLayout = new QVBoxLayout (this); verticalLayout->setContentsMargins(4, 4, 4, 4); configHorizontalLayout = new QHBoxLayout(); configBox = new QComboBox(this); configBox->addItem(tr(""), ""); configBox->setObjectName(QString::fromUtf8("configBox")); configBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); configHorizontalLayout->addWidget(configBox); spacer1 = new QSpacerItem(30, 20, QSizePolicy::Fixed, QSizePolicy::Fixed); configHorizontalLayout->addItem(spacer1); removeButton = new QPushButton(tr("Remove"), this); removeButton->setObjectName(QString::fromUtf8("removeButton")); removeButton->setToolTip(tr("Remove configuration from recent list.")); //removeButton->setFixedWidth(100); removeButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); removeButton->setIcon(QIcon::fromTheme("edit-clear-list")); configHorizontalLayout->addWidget(removeButton); loadButton = new QPushButton(tr("Load"), this); loadButton->setObjectName(QString::fromUtf8("loadButton")); loadButton->setToolTip(tr("Load configuration file.")); //loadButton->setFixedWidth(100); loadButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); loadButton->setIcon(QIcon::fromTheme("document-open")); configHorizontalLayout->addWidget(loadButton); saveButton = new QPushButton(tr("Save"), this); saveButton->setObjectName(QString::fromUtf8("saveButton")); saveButton->setToolTip(tr("Save changes to configuration file.")); //saveButton->setFixedWidth(100); saveButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); saveButton->setIcon(QIcon::fromTheme("document-save")); configHorizontalLayout->addWidget(saveButton); //configHorizontalLayout->setSpacing(-1); saveAsButton = new QPushButton(tr("Save As"), this); saveAsButton->setObjectName(QString::fromUtf8("saveAsButton")); saveAsButton->setToolTip(tr("Save changes to a new configuration file.")); //saveAsButton->setFixedWidth(100); saveAsButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); saveAsButton->setIcon(QIcon::fromTheme("document-save-as")); configHorizontalLayout->addWidget(saveAsButton); verticalLayout->addLayout(configHorizontalLayout); verticalLayout->setStretchFactor(configHorizontalLayout, 1); spacer2 = new QSpacerItem(20, 5, QSizePolicy::Fixed, QSizePolicy::Fixed); verticalLayout->addItem(spacer2); verticalSpacer_2 = new QSpacerItem(20, 5, QSizePolicy::Minimum, QSizePolicy::Fixed); verticalLayout->addItem(verticalSpacer_2); stackedWidget_2 = new QStackedWidget(this); stackedWidget_2->setObjectName(QString::fromUtf8("stackedWidget_2")); page = new QWidget(); page->setObjectName(QString::fromUtf8("page")); QVBoxLayout *tempVBoxLayout = new QVBoxLayout(page); QScrollArea *scrollArea = new QScrollArea(); scrollArea->setObjectName(QString::fromUtf8("scrollArea1")); QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); //sizePolicy.setHorizontalStretch(0); //sizePolicy.setVerticalStretch(0); scrollArea->setSizePolicy(sizePolicy); scrollArea->setWidgetResizable(true); QWidget *scrollAreaWidgetContents1 = new QWidget(); scrollAreaWidgetContents1->setObjectName(QString::fromUtf8("scrollAreaWidgetContents1")); gridLayout = new QGridLayout(scrollAreaWidgetContents1); gridLayout->setSpacing(4); gridLayout->setObjectName(QString::fromUtf8("gridLayout")); scrollArea->setWidget(scrollAreaWidgetContents1); tempVBoxLayout->addWidget(scrollArea); stackedWidget_2->addWidget(page); page_2 = new QWidget(); page_2->setObjectName(QString::fromUtf8("page_2")); tempVBoxLayout = new QVBoxLayout(page_2); QScrollArea *scrollArea2 = new QScrollArea(); scrollArea2->setObjectName(QString::fromUtf8("scrollArea2")); scrollArea2->setSizePolicy(sizePolicy); scrollArea2->setWidgetResizable(true); QWidget *scrollAreaWidgetContents2 = new QWidget(); scrollAreaWidgetContents2->setObjectName(QString::fromUtf8("scrollAreaWidgetContents2")); gridLayout2 = new QGridLayout(scrollAreaWidgetContents2); gridLayout2->setSpacing(4); gridLayout2->setObjectName(QString::fromUtf8("gridLayout2")); scrollArea2->setWidget(scrollAreaWidgetContents2); tempVBoxLayout->addWidget(scrollArea2); stackedWidget_2->addWidget(page_2); page_3 = new QWidget(); page_3->setObjectName(QString::fromUtf8("page_3")); tempVBoxLayout = new QVBoxLayout(page_3); QScrollArea *scrollArea3 = new QScrollArea(); scrollArea3->setObjectName(QString::fromUtf8("scrollArea3")); scrollArea3->setSizePolicy(sizePolicy); scrollArea3->setWidgetResizable(true); QWidget *scrollAreaWidgetContents3 = new QWidget(); scrollAreaWidgetContents3->setObjectName(QString::fromUtf8("scrollAreaWidgetContents3")); gridLayout3 = new QGridLayout(scrollAreaWidgetContents3); gridLayout3->setSpacing(4); gridLayout3->setObjectName(QString::fromUtf8("gridLayout3")); scrollArea3->setWidget(scrollAreaWidgetContents3); tempVBoxLayout->addWidget(scrollArea3); stackedWidget_2->addWidget(page_3); page_4 = new QWidget(); page_4->setObjectName(QString::fromUtf8("page_4")); tempVBoxLayout = new QVBoxLayout(page_4); QScrollArea *scrollArea4 = new QScrollArea(); scrollArea4->setObjectName(QString::fromUtf8("scrollArea4")); scrollArea4->setSizePolicy(sizePolicy); scrollArea4->setWidgetResizable(true); QWidget *scrollAreaWidgetContents4 = new QWidget(); scrollAreaWidgetContents4->setObjectName(QString::fromUtf8("scrollAreaWidgetContents4")); gridLayout4 = new QGridLayout(scrollAreaWidgetContents4); gridLayout4->setSpacing(4); gridLayout4->setObjectName(QString::fromUtf8("gridLayout4")); scrollArea4->setWidget(scrollAreaWidgetContents4); tempVBoxLayout->addWidget(scrollArea4); stackedWidget_2->addWidget(page_4); page_5 = new QWidget(); page_5->setObjectName(QString::fromUtf8("page_5")); tempVBoxLayout = new QVBoxLayout(page_5); QScrollArea *scrollArea5 = new QScrollArea(); scrollArea5->setObjectName(QString::fromUtf8("scrollArea5")); scrollArea5->setSizePolicy(sizePolicy); scrollArea5->setWidgetResizable(true); QWidget *scrollAreaWidgetContents5 = new QWidget(); scrollAreaWidgetContents5->setObjectName(QString::fromUtf8("scrollAreaWidgetContents5")); gridLayout5 = new QGridLayout(scrollAreaWidgetContents5); gridLayout5->setSpacing(4); gridLayout5->setObjectName(QString::fromUtf8("gridLayout5")); scrollArea5->setWidget(scrollAreaWidgetContents5); tempVBoxLayout->addWidget(scrollArea5); stackedWidget_2->addWidget(page_5); page_6 = new QWidget(); page_6->setObjectName(QString::fromUtf8("page_6")); tempVBoxLayout = new QVBoxLayout(page_6); QScrollArea *scrollArea6 = new QScrollArea(); scrollArea6->setObjectName(QString::fromUtf8("scrollArea6")); scrollArea6->setSizePolicy(sizePolicy); scrollArea6->setWidgetResizable(true); QWidget *scrollAreaWidgetContents6 = new QWidget(); scrollAreaWidgetContents6->setObjectName(QString::fromUtf8("scrollAreaWidgetContents6")); gridLayout6 = new QGridLayout(scrollAreaWidgetContents6); gridLayout6->setSpacing(4); gridLayout6->setObjectName(QString::fromUtf8("gridLayout6")); scrollArea6->setWidget(scrollAreaWidgetContents6); tempVBoxLayout->addWidget(scrollArea6); stackedWidget_2->addWidget(page_6); page_7 = new QWidget(); page_7->setObjectName(QString::fromUtf8("page_7")); tempVBoxLayout = new QVBoxLayout(page_7); QScrollArea *scrollArea7 = new QScrollArea(); scrollArea7->setObjectName(QString::fromUtf8("scrollArea7")); scrollArea7->setSizePolicy(sizePolicy); scrollArea7->setWidgetResizable(true); QWidget *scrollAreaWidgetContents7 = new QWidget(); scrollAreaWidgetContents7->setObjectName(QString::fromUtf8("scrollAreaWidgetContents7")); gridLayout7 = new QGridLayout(scrollAreaWidgetContents7); gridLayout7->setSpacing(4); gridLayout7->setObjectName(QString::fromUtf8("gridLayout7")); scrollArea7->setWidget(scrollAreaWidgetContents7); tempVBoxLayout->addWidget(scrollArea7); stackedWidget_2->addWidget(page_7); page_8 = new QWidget(); page_8->setObjectName(QString::fromUtf8("page_8")); tempVBoxLayout = new QVBoxLayout(page_8); QScrollArea *scrollArea8 = new QScrollArea(); scrollArea8->setObjectName(QString::fromUtf8("scrollArea8")); scrollArea8->setSizePolicy(sizePolicy); scrollArea8->setWidgetResizable(true); QWidget *scrollAreaWidgetContents8 = new QWidget(); scrollAreaWidgetContents8->setObjectName(QString::fromUtf8("scrollAreaWidgetContents8")); gridLayout8 = new QGridLayout(scrollAreaWidgetContents8); gridLayout8->setSpacing(4); gridLayout8->setObjectName(QString::fromUtf8("gridLayout8")); scrollArea8->setWidget(scrollAreaWidgetContents8); tempVBoxLayout->addWidget(scrollArea8); stackedWidget_2->addWidget(page_8); verticalLayout->addWidget(stackedWidget_2); verticalSpacer_3 = new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Fixed); verticalLayout->addItem(verticalSpacer_3); horizontalLayout_2 = new QHBoxLayout(); horizontalLayout_2->setSpacing(6); horizontalLayout_2->setObjectName(QString::fromUtf8("horizontalLayout_2")); setsMenuButton = new QPushButton(tr("Sets"), this); QMenu *setMenu = new QMenu(setsMenuButton); copySetMenu = new QMenu(tr("Copy from Set"), setMenu); QAction *setSettingsAction = new QAction(tr("Settings"), setMenu); connect(setSettingsAction, SIGNAL(triggered()), this, SLOT(showSetNamesDialog())); setMenu->addAction(setSettingsAction); setMenu->addMenu(copySetMenu); setMenu->addSeparator(); refreshCopySetActions(); setAction1 = new QAction(tr("Set 1"), setMenu); connect(setAction1, SIGNAL(triggered()), this, SLOT(changeSetOne())); setMenu->addAction(setAction1); setAction2 = new QAction(tr("Set 2"), setMenu); connect(setAction2, SIGNAL(triggered()), this, SLOT(changeSetTwo())); setMenu->addAction(setAction2); setAction3 = new QAction(tr("Set 3"), setMenu); connect(setAction3, SIGNAL(triggered()), this, SLOT(changeSetThree())); setMenu->addAction(setAction3); setAction4 = new QAction(tr("Set 4"), setMenu); connect(setAction4, SIGNAL(triggered()), this, SLOT(changeSetFour())); setMenu->addAction(setAction4); setAction5 = new QAction(tr("Set 5"), setMenu); connect(setAction5, SIGNAL(triggered()), this, SLOT(changeSetFive())); setMenu->addAction(setAction5); setAction6 = new QAction(tr("Set 6"), setMenu); connect(setAction6, SIGNAL(triggered()), this, SLOT(changeSetSix())); setMenu->addAction(setAction6); setAction7 = new QAction(tr("Set 7"), setMenu); connect(setAction7, SIGNAL(triggered()), this, SLOT(changeSetSeven())); setMenu->addAction(setAction7); setAction8 = new QAction(tr("Set 8"), setMenu); connect(setAction8, SIGNAL(triggered()), this, SLOT(changeSetEight())); setMenu->addAction(setAction8); setsMenuButton->setMenu(setMenu); horizontalLayout_2->addWidget(setsMenuButton); setPushButton1 = new QPushButton("1", this); setPushButton1->setObjectName(QString::fromUtf8("setPushButton1")); setPushButton1->setProperty("setActive", true); horizontalLayout_2->addWidget(setPushButton1); setPushButton2 = new QPushButton("2", this); setPushButton2->setObjectName(QString::fromUtf8("setPushButton2")); setPushButton2->setProperty("setActive", false); horizontalLayout_2->addWidget(setPushButton2); setPushButton3 = new QPushButton("3", this); setPushButton3->setObjectName(QString::fromUtf8("setPushButton3")); setPushButton3->setProperty("setActive", false); horizontalLayout_2->addWidget(setPushButton3); setPushButton4 = new QPushButton("4", this); setPushButton4->setObjectName(QString::fromUtf8("setPushButton4")); setPushButton4->setProperty("setActive", false); horizontalLayout_2->addWidget(setPushButton4); setPushButton5 = new QPushButton("5", this); setPushButton5->setObjectName(QString::fromUtf8("setPushButton5")); setPushButton5->setProperty("setActive", false); horizontalLayout_2->addWidget(setPushButton5); setPushButton6 = new QPushButton("6", this); setPushButton6->setObjectName(QString::fromUtf8("setPushButton6")); setPushButton6->setProperty("setActive", false); horizontalLayout_2->addWidget(setPushButton6); setPushButton7 = new QPushButton("7", this); setPushButton7->setObjectName(QString::fromUtf8("setPushButton7")); setPushButton7->setProperty("setActive", false); horizontalLayout_2->addWidget(setPushButton7); setPushButton8 = new QPushButton("8", this); setPushButton8->setObjectName(QString::fromUtf8("setPushButton8")); setPushButton8->setProperty("setActive", false); horizontalLayout_2->addWidget(setPushButton8); refreshSetButtons(); verticalLayout->addLayout(horizontalLayout_2); spacer3 = new QSpacerItem(20, 5, QSizePolicy::Fixed, QSizePolicy::Fixed); verticalLayout->addItem(spacer3); horizontalLayout_3 = new QHBoxLayout(); horizontalLayout_3->setSpacing(6); horizontalLayout_3->setObjectName(QString::fromUtf8("horizontalLayout_3")); stickAssignPushButton = new QPushButton(tr("Stick/Pad Assign"), this); stickAssignPushButton->setObjectName(QString::fromUtf8("stickAssignPushButton")); QIcon icon7(QIcon::fromTheme(QString::fromUtf8("games-config-options"))); stickAssignPushButton->setIcon(icon7); horizontalLayout_3->addWidget(stickAssignPushButton); gameControllerMappingPushButton = new QPushButton(tr("Controller Mapping"), this); gameControllerMappingPushButton->setObjectName(QString::fromUtf8("gameControllerMappingPushButton")); gameControllerMappingPushButton->setIcon(QIcon::fromTheme("games-config-options")); gameControllerMappingPushButton->setEnabled(false); gameControllerMappingPushButton->setVisible(false); horizontalLayout_3->addWidget(gameControllerMappingPushButton); quickSetPushButton = new QPushButton(tr("Quick Set"), this); quickSetPushButton->setObjectName(QString::fromUtf8("quickSetPushButton")); horizontalLayout_3->addWidget(quickSetPushButton); QSpacerItem *horizontalSpacer_2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); horizontalLayout_3->addItem(horizontalSpacer_2); namesPushButton = new QPushButton(tr("Names"), this); namesPushButton->setObjectName(QString::fromUtf8("namesPushButton")); namesPushButton->setToolTip(tr("Toggle button name displaying.")); namesPushButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); namesPushButton->setIcon(QIcon::fromTheme("text-field")); horizontalLayout_3->addWidget(namesPushButton); delayButton = new QPushButton(tr("Pref"), this); delayButton->setObjectName(QString::fromUtf8("delayButton")); delayButton->setToolTip(tr("Change global profile settings.")); delayButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); horizontalLayout_3->addWidget(delayButton); resetButton = new QPushButton(tr("Reset"), this); resetButton->setObjectName(QString::fromUtf8("resetButton")); resetButton->setToolTip(tr("Revert changes to the configuration. Reload configuration file.")); resetButton->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); resetButton->setIcon(QIcon::fromTheme("document-revert")); //verticalLayout->addWidget(resetButton, 0, Qt::AlignRight); horizontalLayout_3->addWidget(resetButton); verticalLayout->addLayout(horizontalLayout_3); displayingNames = false; #ifdef USE_SDL_2 stickAssignPushButton->setEnabled(false); stickAssignPushButton->setVisible(false); gameControllerMappingPushButton->setEnabled(true); gameControllerMappingPushButton->setVisible(true); #endif #ifdef Q_OS_WIN deviceKeyRepeatSettings(); #endif checkHideEmptyOption(); connect(loadButton, SIGNAL(clicked()), this, SLOT(openConfigFileDialog())); connect(saveButton, SIGNAL(clicked()), this, SLOT(saveConfigFile())); connect(resetButton, SIGNAL(clicked()), this, SLOT(resetJoystick())); connect(namesPushButton, SIGNAL(clicked()), this, SLOT(toggleNames())); connect(saveAsButton, SIGNAL(clicked()), this, SLOT(saveAsConfig())); connect(delayButton, SIGNAL(clicked()), this, SLOT(showKeyDelayDialog())); connect(removeButton, SIGNAL(clicked()), this, SLOT(removeConfig())); connect(setPushButton1, SIGNAL(clicked()), this, SLOT(changeSetOne())); connect(setPushButton2, SIGNAL(clicked()), this, SLOT(changeSetTwo())); connect(setPushButton3, SIGNAL(clicked()), this, SLOT(changeSetThree())); connect(setPushButton4, SIGNAL(clicked()), this, SLOT(changeSetFour())); connect(setPushButton5, SIGNAL(clicked()), this, SLOT(changeSetFive())); connect(setPushButton6, SIGNAL(clicked()), this, SLOT(changeSetSix())); connect(setPushButton7, SIGNAL(clicked()), this, SLOT(changeSetSeven())); connect(setPushButton8, SIGNAL(clicked()), this, SLOT(changeSetEight())); connect(stickAssignPushButton, SIGNAL(clicked()), this, SLOT(showStickAssignmentDialog())); #ifdef USE_SDL_2 connect(gameControllerMappingPushButton, SIGNAL(clicked()), this, SLOT(openGameControllerMappingWindow())); #endif connect(quickSetPushButton, SIGNAL(clicked()), this, SLOT(showQuickSetDialog())); connect(this, SIGNAL(joystickConfigChanged(int)), this, SLOT(refreshSetButtons())); connect(this, SIGNAL(joystickConfigChanged(int)), this, SLOT(refreshCopySetActions())); connect(joystick, SIGNAL(profileUpdated()), this, SLOT(displayProfileEditNotification())); connect(joystick, SIGNAL(requestProfileLoad(QString)), this, SLOT(loadConfigFile(QString)), Qt::QueuedConnection); reconnectCheckUnsavedEvent(); reconnectMainComboBoxEvents(); } void JoyTabWidget::openConfigFileDialog() { settings->getLock()->lock(); int numberRecentProfiles = settings->value("NumberRecentProfiles", DEFAULTNUMBERPROFILES).toInt(); QString lookupDir = PadderCommon::preferredProfileDir(settings); QString filename = QFileDialog::getOpenFileName(this, tr("Open Config"), lookupDir, tr("Config Files (*.amgp *.xml)")); settings->getLock()->unlock(); if (!filename.isNull() && !filename.isEmpty()) { QFileInfo fileinfo(filename); int searchIndex = configBox->findData(fileinfo.absoluteFilePath()); if (searchIndex == -1) { if (numberRecentProfiles > 0 && configBox->count() == numberRecentProfiles + 1) { configBox->removeItem(numberRecentProfiles); } configBox->insertItem(1, PadderCommon::getProfileName(fileinfo), fileinfo.absoluteFilePath()); configBox->setCurrentIndex(1); saveDeviceSettings(); emit joystickConfigChanged(joystick->getJoyNumber()); } else { configBox->setCurrentIndex(searchIndex); saveDeviceSettings(); emit joystickConfigChanged(joystick->getJoyNumber()); } QString outputFilename = fileinfo.absoluteDir().absolutePath(); #if defined(Q_OS_WIN) && defined(WIN_PORTABLE_PACKAGE) if (fileinfo.absoluteDir().isAbsolute()) { QDir tempDir = fileinfo.dir(); tempDir.cdUp(); if (tempDir.path() == qApp->applicationDirPath()) { outputFilename = QString("%1/").arg(fileinfo.dir().dirName()); } } #endif settings->getLock()->lock(); settings->setValue("LastProfileDir", outputFilename); settings->sync(); settings->getLock()->unlock(); } } /** * @brief Create and render all push buttons corresponding to joystick * controls for all sets. */ void JoyTabWidget::fillButtons() { joystick->establishPropertyUpdatedConnection(); connect(joystick, SIGNAL(setChangeActivated(int)), this, SLOT(changeCurrentSet(int)), Qt::QueuedConnection); for (int i=0; i < Joystick::NUMBER_JOYSETS; i++) { SetJoystick *currentSet = joystick->getSetJoystick(i); fillSetButtons(currentSet); } refreshCopySetActions(); } void JoyTabWidget::showButtonDialog() { JoyButtonWidget *buttonWidget = static_cast(sender()); JoyButton *button = buttonWidget->getJoyButton(); ButtonEditDialog *dialog = new ButtonEditDialog(button, this); dialog->show(); } void JoyTabWidget::showAxisDialog() { JoyAxisWidget *axisWidget = static_cast(sender()); JoyAxis *axis = axisWidget->getAxis(); axisDialog = new AxisEditDialog (axis, this); axisDialog->show(); } void JoyTabWidget::saveConfigFile() { int index = configBox->currentIndex(); settings->getLock()->lock(); int numberRecentProfiles = settings->value("NumberRecentProfiles", DEFAULTNUMBERPROFILES).toInt(); QString filename; if (index == 0) { QString lookupDir = PadderCommon::preferredProfileDir(settings); settings->getLock()->unlock(); QString tempfilename = QFileDialog::getSaveFileName(this, tr("Save Config"), lookupDir, tr("Config File (*.%1.amgp)").arg(joystick->getXmlName())); if (!tempfilename.isEmpty()) { filename = tempfilename; QFileInfo fileinfo(filename); QString deviceTypeName = joystick->getXmlName(); QString fileSuffix = deviceTypeName.append(".amgp"); if (fileinfo.suffix() != "xml" && fileinfo.suffix() != "amgp") { filename = filename.append(".").append(fileSuffix); } } } else { settings->getLock()->unlock(); filename = configBox->itemData(index).toString(); } if (!filename.isEmpty()) { //PadderCommon::inputDaemonMutex.lock(); QFileInfo fileinfo(filename); QMetaObject::invokeMethod(&tabHelper, "writeConfigFile", Qt::BlockingQueuedConnection, Q_ARG(QString, fileinfo.absoluteFilePath())); XMLConfigWriter *writer = tabHelper.getWriter(); /*XMLConfigWriter writer; writer.setFileName(fileinfo.absoluteFilePath()); writer.write(joystick); */ //PadderCommon::inputDaemonMutex.unlock(); if (writer->hasError() && this->window()->isEnabled()) { QMessageBox msg; msg.setStandardButtons(QMessageBox::Close); msg.setText(writer->getErrorString()); msg.setModal(true); msg.exec(); } else if (writer->hasError() && !this->window()->isEnabled()) { QTextStream error(stderr); error << writer->getErrorString() << endl; } else { int existingIndex = configBox->findData(fileinfo.absoluteFilePath()); if (existingIndex == -1) { //PadderCommon::inputDaemonMutex.lock(); if (numberRecentProfiles > 0 && configBox->count() == numberRecentProfiles+1) { configBox->removeItem(numberRecentProfiles); } joystick->revertProfileEdited(); QString tempProfileName = PadderCommon::getProfileName(fileinfo); if (!joystick->getProfileName().isEmpty()) { oldProfileName = joystick->getProfileName(); tempProfileName = oldProfileName; } disconnectCheckUnsavedEvent(); disconnectMainComboBoxEvents(); configBox->insertItem(1, tempProfileName, fileinfo.absoluteFilePath()); reconnectCheckUnsavedEvent(); reconnectMainComboBoxEvents(); configBox->setCurrentIndex(1); saveDeviceSettings(true); //PadderCommon::inputDaemonMutex.unlock(); emit joystickConfigChanged(joystick->getJoyNumber()); } else { //PadderCommon::inputDaemonMutex.lock(); joystick->revertProfileEdited(); if (!joystick->getProfileName().isEmpty()) { oldProfileName = joystick->getProfileName(); } configBox->setItemIcon(existingIndex, QIcon()); saveDeviceSettings(true); //PadderCommon::inputDaemonMutex.unlock(); emit joystickConfigChanged(joystick->getJoyNumber()); } } } } void JoyTabWidget::resetJoystick() { int currentIndex = configBox->currentIndex(); if (currentIndex != 0) { QString filename = configBox->itemData(currentIndex).toString(); removeCurrentButtons(); QMetaObject::invokeMethod(&tabHelper, "readConfigFileWithRevert", Qt::BlockingQueuedConnection, Q_ARG(QString, filename)); fillButtons(); refreshSetButtons(); refreshCopySetActions(); XMLConfigReader *reader = tabHelper.getReader(); if (!reader->hasError()) { configBox->setItemIcon(currentIndex, QIcon()); QString tempProfileName; if (!joystick->getProfileName().isEmpty()) { tempProfileName = joystick->getProfileName(); configBox->setItemText(currentIndex, tempProfileName); } else { tempProfileName = oldProfileName; configBox->setItemText(currentIndex, oldProfileName); } oldProfileName = tempProfileName; } else if (reader->hasError() && this->window()->isEnabled()) { QMessageBox msg; msg.setStandardButtons(QMessageBox::Close); msg.setText(reader->getErrorString()); msg.setModal(true); msg.exec(); } else if (reader->hasError() && !this->window()->isEnabled()) { QTextStream error(stderr); error << reader->getErrorString() << endl; } } else { configBox->setItemText(0, tr("")); configBox->setItemIcon(0, QIcon()); removeCurrentButtons(); QMetaObject::invokeMethod(&tabHelper, "reInitDevice", Qt::BlockingQueuedConnection); fillButtons(); refreshSetButtons(); refreshCopySetActions(); } } void JoyTabWidget::saveAsConfig() { int index = configBox->currentIndex(); settings->getLock()->lock(); int numberRecentProfiles = settings->value("NumberRecentProfiles", DEFAULTNUMBERPROFILES).toInt(); QString filename; if (index == 0) { QString lookupDir = PadderCommon::preferredProfileDir(settings); settings->getLock()->unlock(); QString tempfilename = QFileDialog::getSaveFileName(this, tr("Save Config"), lookupDir, tr("Config File (*.%1.amgp)").arg(joystick->getXmlName())); if (!tempfilename.isEmpty()) { filename = tempfilename; } } else { settings->getLock()->unlock(); QString configPath = configBox->itemData(index).toString(); QFileInfo temp(configPath); QString tempfilename = QFileDialog::getSaveFileName(this, tr("Save Config"), temp.absoluteDir().absolutePath(), tr("Config File (*.%1.amgp)").arg(joystick->getXmlName())); if (!tempfilename.isEmpty()) { filename = tempfilename; } } if (!filename.isEmpty()) { QFileInfo fileinfo(filename); QString deviceTypeName = joystick->getXmlName(); QString fileSuffix = deviceTypeName.append(".amgp"); if (fileinfo.suffix() != "xml" && fileinfo.suffix() != "amgp") { filename = filename.append(".").append(fileSuffix); } fileinfo.setFile(filename); /*XMLConfigWriter writer; writer.setFileName(fileinfo.absoluteFilePath()); writer.write(joystick); */ QMetaObject::invokeMethod(&tabHelper, "writeConfigFile", Qt::BlockingQueuedConnection, Q_ARG(QString, fileinfo.absoluteFilePath())); XMLConfigWriter *writer = tabHelper.getWriter(); if (writer->hasError() && this->window()->isEnabled()) { QMessageBox msg; msg.setStandardButtons(QMessageBox::Close); msg.setText(writer->getErrorString()); msg.setModal(true); msg.exec(); } else if (writer->hasError() && !this->window()->isEnabled()) { QTextStream error(stderr); error << writer->getErrorString() << endl; } else { int existingIndex = configBox->findData(fileinfo.absoluteFilePath()); if (existingIndex == -1) { disconnectCheckUnsavedEvent(); disconnectMainComboBoxEvents(); if (numberRecentProfiles > 0 && configBox->count() == numberRecentProfiles+1) { configBox->removeItem(numberRecentProfiles); } joystick->revertProfileEdited(); QString tempProfileName = PadderCommon::getProfileName(fileinfo); if (!joystick->getProfileName().isEmpty()) { oldProfileName = joystick->getProfileName(); tempProfileName = oldProfileName; } configBox->insertItem(1, tempProfileName, fileinfo.absoluteFilePath()); reconnectCheckUnsavedEvent(); reconnectMainComboBoxEvents(); configBox->setCurrentIndex(1); saveDeviceSettings(true); emit joystickConfigChanged(joystick->getJoyNumber()); } else { joystick->revertProfileEdited(); if (!joystick->getProfileName().isEmpty()) { oldProfileName = joystick->getProfileName(); } configBox->setItemIcon(existingIndex, QIcon()); saveDeviceSettings(true); emit joystickConfigChanged(joystick->getJoyNumber()); } } } } void JoyTabWidget::changeJoyConfig(int index) { disconnect(joystick, SIGNAL(profileUpdated()), this, SLOT(displayProfileEditNotification())); QString filename; if (index > 0) { filename = configBox->itemData(index).toString(); } if (!filename.isEmpty()) { removeCurrentButtons(); emit forceTabUnflash(this); QMetaObject::invokeMethod(&tabHelper, "readConfigFile", Qt::BlockingQueuedConnection, Q_ARG(QString, filename)); fillButtons(); refreshSetButtons(); refreshCopySetActions(); configBox->setItemText(0, tr("")); XMLConfigReader *reader = tabHelper.getReader(); if (!reader->hasError()) { QString profileName; if (!joystick->getProfileName().isEmpty()) { profileName = joystick->getProfileName(); oldProfileName = profileName; } else { QFileInfo profile(filename); oldProfileName = PadderCommon::getProfileName(profile); profileName = oldProfileName; } configBox->setItemText(index, profileName); } else if (reader->hasError() && this->window()->isEnabled()) { QMessageBox msg; msg.setStandardButtons(QMessageBox::Close); msg.setText(reader->getErrorString()); msg.setModal(true); msg.exec(); } else if (reader->hasError() && !this->window()->isEnabled()) { QTextStream error(stderr); error << reader->getErrorString() << endl; } } else if (index == 0) { removeCurrentButtons(); emit forceTabUnflash(this); QMetaObject::invokeMethod(&tabHelper, "reInitDevice", Qt::BlockingQueuedConnection); fillButtons(); refreshSetButtons(); refreshCopySetActions(); configBox->setItemText(0, tr("")); oldProfileName = ""; } comboBoxIndex = index; connect(joystick, SIGNAL(profileUpdated()), this, SLOT(displayProfileEditNotification())); } void JoyTabWidget::saveSettings() { QString filename = ""; QString lastfile = ""; settings->getLock()->lock(); int index = configBox->currentIndex(); int currentjoy = 1; QString identifier = joystick->getStringIdentifier(); QString controlEntryPrefix = QString("Controller%1").arg(identifier); QString controlEntryString = QString("Controller%1ConfigFile%2").arg(identifier); QString controlEntryLastSelected = QString("Controller%1LastSelected").arg(identifier); QString controlEntryProfileName = QString("Controller%1ProfileName%2").arg(joystick->getStringIdentifier()); // Remove current settings for a controller QStringList tempkeys = settings->allKeys(); QStringListIterator iter(tempkeys); while (iter.hasNext()) { QString tempstring = iter.next(); if (!identifier.isEmpty() && tempstring.startsWith(controlEntryPrefix)) { settings->remove(tempstring); } } // Output currently selected profile as first profile on the list if (index != 0) { filename = lastfile = configBox->itemData(index).toString(); QString profileText = configBox->itemText(index); if (!identifier.isEmpty()) { QFileInfo profileBaseFile(filename); QString outputFilename = filename; #if defined(Q_OS_WIN) && defined(WIN_PORTABLE_PACKAGE) if (profileBaseFile.isAbsolute()) { QDir tempDir = profileBaseFile.dir(); tempDir.cdUp(); if (tempDir.path() == qApp->applicationDirPath()) { outputFilename = QString("%1/%2") .arg(profileBaseFile.dir().dirName()) .arg(profileBaseFile.fileName()); } } #endif settings->setValue(controlEntryString.arg(currentjoy), outputFilename); if (PadderCommon::getProfileName(profileBaseFile) != profileText) { settings->setValue(controlEntryProfileName.arg(currentjoy), profileText); } } currentjoy++; } else { lastfile = ""; } // Write the remaining profile locations to the settings file for (int i=1; i < configBox->count(); i++) { if (i != index) { filename = configBox->itemData(i).toString(); QString profileText = configBox->itemText(i); if (!identifier.isEmpty()) { QFileInfo profileBaseFile(filename); QString outputFilename = filename; #if defined(Q_OS_WIN) && defined(WIN_PORTABLE_PACKAGE) if (profileBaseFile.isAbsolute()) { QDir tempDir = profileBaseFile.dir(); tempDir.cdUp(); if (tempDir.path() == qApp->applicationDirPath()) { outputFilename = QString("%1/%2") .arg(profileBaseFile.dir().dirName()) .arg(profileBaseFile.fileName()); } } #endif settings->setValue(controlEntryString.arg(currentjoy), outputFilename); if (PadderCommon::getProfileName(profileBaseFile) != profileText) { settings->setValue(controlEntryProfileName.arg(currentjoy), profileText); } } currentjoy++; } } if (!identifier.isEmpty()) { QFileInfo profileBaseFile(lastfile); QString outputFilename = lastfile; #if defined(Q_OS_WIN) && defined(WIN_PORTABLE_PACKAGE) if (profileBaseFile.isAbsolute()) { QDir tempDir = profileBaseFile.dir(); tempDir.cdUp(); if (tempDir.path() == qApp->applicationDirPath()) { outputFilename = QString("%1/%2") .arg(profileBaseFile.dir().dirName()) .arg(profileBaseFile.fileName()); } } #endif settings->setValue(controlEntryLastSelected, outputFilename); } settings->getLock()->unlock(); } void JoyTabWidget::loadSettings(bool forceRefresh) { disconnect(configBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeJoyConfig(int))); settings->getLock()->lock(); if (configBox->count() > 1) { configBox->clear(); configBox->addItem(tr(""), ""); configBox->setCurrentIndex(-1); } else if (forceRefresh) { configBox->setCurrentIndex(-1); } int shouldisplaynames = settings->value("DisplayNames", "0").toInt(); if (shouldisplaynames == 1) { changeNameDisplay(shouldisplaynames); } int numberRecentProfiles = settings->value("NumberRecentProfiles", DEFAULTNUMBERPROFILES).toInt(); bool autoOpenLastProfile = settings->value("AutoOpenLastProfile", true).toBool(); settings->beginGroup("Controllers"); QString controlEntryString = QString("Controller%1ConfigFile%2").arg(joystick->getStringIdentifier()); QString controlEntryLastSelected = QString("Controller%1LastSelected").arg(joystick->getStringIdentifier()); QString controlEntryProfileName = QString("Controller%1ProfileName%2").arg(joystick->getStringIdentifier()); bool finished = false; for (int i=1; !finished; i++) { QString tempfilepath; if (!joystick->getStringIdentifier().isEmpty()) { tempfilepath = settings->value(controlEntryString.arg(i), "").toString(); } if (!tempfilepath.isEmpty()) { QFileInfo fileInfo(tempfilepath); if (fileInfo.exists() && configBox->findData(fileInfo.absoluteFilePath()) == -1) { QString profileName = settings->value(controlEntryProfileName.arg(i), "").toString(); profileName = !profileName.isEmpty() ? profileName : PadderCommon::getProfileName(fileInfo); configBox->addItem(profileName, fileInfo.absoluteFilePath()); } } else { finished = true; } if (numberRecentProfiles > 0 && (i == numberRecentProfiles)) { finished = true; } } connect(configBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeJoyConfig(int)), Qt::QueuedConnection); QString lastfile; if (!joystick->getStringIdentifier().isEmpty() && autoOpenLastProfile) { lastfile = settings->value(controlEntryLastSelected, "").toString(); } settings->endGroup(); settings->getLock()->unlock(); if (!lastfile.isEmpty()) { QString lastFileAbsolute = lastfile; #if defined(Q_OS_WIN) && defined(WIN_PORTABLE_PACKAGE) QFileInfo lastFileInfo(lastfile); lastFileAbsolute = lastFileInfo.absoluteFilePath(); #endif int lastindex = configBox->findData(lastFileAbsolute); if (lastindex > 0) { configBox->setCurrentIndex(lastindex); emit joystickConfigChanged(joystick->getJoyNumber()); } else if (configBox->currentIndex() != 0) { configBox->setCurrentIndex(0); emit joystickConfigChanged(joystick->getJoyNumber()); } } else if (configBox->currentIndex() != 0) { configBox->setCurrentIndex(0); emit joystickConfigChanged(joystick->getJoyNumber()); } } QHash* JoyTabWidget::recentConfigs() { QHash *temp = new QHash(); for (int i=1; i < configBox->count(); i++) { QString current = configBox->itemText(i); temp->insert(i, current); } return temp; } void JoyTabWidget::setCurrentConfig(int index) { // Allow 0 to select new/'null' config and therefore disable any mapping if (index >= 0 && index < configBox->count()) { configBox->setCurrentIndex(index); } } int JoyTabWidget::getCurrentConfigIndex() { return configBox->currentIndex(); } QString JoyTabWidget::getCurrentConfigName() { return configBox->currentText(); } QString JoyTabWidget::getConfigName(int index) { return configBox->itemText(index); } void JoyTabWidget::changeCurrentSet(int index) { int currentPage = stackedWidget_2->currentIndex(); QPushButton *oldSetButton = 0; QPushButton *activeSetButton = 0; switch (currentPage) { case 0: oldSetButton = setPushButton1; break; case 1: oldSetButton = setPushButton2; break; case 2: oldSetButton = setPushButton3; break; case 3: oldSetButton = setPushButton4; break; case 4: oldSetButton = setPushButton5; break; case 5: oldSetButton = setPushButton6; break; case 6: oldSetButton = setPushButton7; break; case 7: oldSetButton = setPushButton8; break; default: break; } if (oldSetButton) { oldSetButton->setProperty("setActive", false); oldSetButton->style()->unpolish(oldSetButton); oldSetButton->style()->polish(oldSetButton); } joystick->setActiveSetNumber(index); stackedWidget_2->setCurrentIndex(index); switch (index) { case 0: activeSetButton = setPushButton1; break; case 1: activeSetButton = setPushButton2; break; case 2: activeSetButton = setPushButton3; break; case 3: activeSetButton = setPushButton4; break; case 4: activeSetButton = setPushButton5; break; case 5: activeSetButton = setPushButton6; break; case 6: activeSetButton = setPushButton7; break; case 7: activeSetButton = setPushButton8; break; default: break; } if (activeSetButton) { activeSetButton->setProperty("setActive", true); activeSetButton->style()->unpolish(activeSetButton); activeSetButton->style()->polish(activeSetButton); } } void JoyTabWidget::changeSetOne() { changeCurrentSet(0); } void JoyTabWidget::changeSetTwo() { changeCurrentSet(1); } void JoyTabWidget::changeSetThree() { changeCurrentSet(2); } void JoyTabWidget::changeSetFour() { changeCurrentSet(3); } void JoyTabWidget::changeSetFive() { changeCurrentSet(4); } void JoyTabWidget::changeSetSix() { changeCurrentSet(5); } void JoyTabWidget::changeSetSeven() { changeCurrentSet(6); } void JoyTabWidget::changeSetEight() { changeCurrentSet(7); } void JoyTabWidget::showStickAssignmentDialog() { Joystick *temp = static_cast(joystick); AdvanceStickAssignmentDialog *dialog = new AdvanceStickAssignmentDialog(temp, this); connect(dialog, SIGNAL(finished(int)), this, SLOT(refreshButtons())); dialog->show(); } void JoyTabWidget::loadConfigFile(QString fileLocation) { checkForUnsavedProfile(-1); if (!joystick->isDeviceEdited()) { int numberRecentProfiles = settings->value("NumberRecentProfiles", DEFAULTNUMBERPROFILES).toInt(); QFileInfo fileinfo(fileLocation); if (fileinfo.exists() && (fileinfo.suffix() == "xml" || fileinfo.suffix() == "amgp")) { int searchIndex = configBox->findData(fileinfo.absoluteFilePath()); if (searchIndex == -1) { disconnectCheckUnsavedEvent(); disconnectMainComboBoxEvents(); if (numberRecentProfiles > 0 && configBox->count() == numberRecentProfiles+1) { configBox->removeItem(numberRecentProfiles-1); //configBox->removeItem(5); } configBox->insertItem(1, PadderCommon::getProfileName(fileinfo), fileinfo.absoluteFilePath()); reconnectCheckUnsavedEvent(); reconnectMainComboBoxEvents(); configBox->setCurrentIndex(1); emit joystickConfigChanged(joystick->getJoyNumber()); } else if (searchIndex != configBox->currentIndex()) { configBox->setCurrentIndex(searchIndex); emit joystickConfigChanged(joystick->getJoyNumber()); } } } } void JoyTabWidget::showQuickSetDialog() { QuickSetDialog *dialog = new QuickSetDialog(joystick, this); connect(dialog, SIGNAL(finished(int)), this, SLOT(refreshButtons())); dialog->show(); } void JoyTabWidget::showKeyDelayDialog() { ExtraProfileSettingsDialog *dialog = new ExtraProfileSettingsDialog(joystick, this); dialog->show(); } void JoyTabWidget::showSetNamesDialog() { SetNamesDialog *dialog = new SetNamesDialog(joystick, this); connect(dialog, SIGNAL(accepted()), this, SLOT(refreshSetButtons())); connect(dialog, SIGNAL(accepted()), this, SLOT(refreshCopySetActions())); dialog->show(); } void JoyTabWidget::removeCurrentButtons() { joystick->disconnectPropertyUpdatedConnection(); disconnect(joystick, SIGNAL(setChangeActivated(int)), this, SLOT(changeCurrentSet(int))); for (int i=0; i < Joystick::NUMBER_JOYSETS; i++) { SetJoystick *currentSet = joystick->getSetJoystick(i); removeSetButtons(currentSet); } } InputDevice *JoyTabWidget::getJoystick() { return joystick; } void JoyTabWidget::removeConfig() { int currentIndex = configBox->currentIndex(); if (currentIndex > 0) { configBox->removeItem(currentIndex); saveDeviceSettings(true); emit joystickConfigChanged(joystick->getJoyNumber()); } } void JoyTabWidget::toggleNames() { displayingNames = !displayingNames; namesPushButton->setProperty("isDisplayingNames", displayingNames); namesPushButton->style()->unpolish(namesPushButton); namesPushButton->style()->polish(namesPushButton); emit namesDisplayChanged(displayingNames); } void JoyTabWidget::unloadConfig() { configBox->setCurrentIndex(0); } void JoyTabWidget::saveDeviceSettings(bool sync) { settings->getLock()->lock(); settings->beginGroup("Controllers"); settings->getLock()->unlock(); saveSettings(); settings->getLock()->lock(); settings->endGroup(); if (sync) { settings->sync(); } settings->getLock()->unlock(); } void JoyTabWidget::loadDeviceSettings() { //settings.beginGroup("Controllers"); loadSettings(); //settings.endGroup(); } bool JoyTabWidget::isDisplayingNames() { return displayingNames; } void JoyTabWidget::changeNameDisplay(bool displayNames) { displayingNames = displayNames; namesPushButton->setProperty("isDisplayingNames", displayingNames); namesPushButton->style()->unpolish(namesPushButton); namesPushButton->style()->polish(namesPushButton); } void JoyTabWidget::refreshSetButtons() { for (int i=0; i < InputDevice::NUMBER_JOYSETS; i++) { QPushButton *tempSetButton = 0; QAction *tempSetAction = 0; SetJoystick *tempSet = joystick->getSetJoystick(i); switch (i) { case 0: tempSetButton = setPushButton1; tempSetAction = setAction1; break; case 1: tempSetButton = setPushButton2; tempSetAction = setAction2; break; case 2: tempSetButton = setPushButton3; tempSetAction = setAction3; break; case 3: tempSetButton = setPushButton4; tempSetAction = setAction4; break; case 4: tempSetButton = setPushButton5; tempSetAction = setAction5; break; case 5: tempSetButton = setPushButton6; tempSetAction = setAction6; break; case 6: tempSetButton = setPushButton7; tempSetAction = setAction7; break; case 7: tempSetButton = setPushButton8; tempSetAction = setAction8; break; } if (!tempSet->getName().isEmpty()) { QString tempName = tempSet->getName(); QString tempNameEscaped = tempName; tempNameEscaped.replace("&", "&&"); tempSetButton->setText(tempNameEscaped); tempSetButton->setToolTip(tempName); tempSetAction->setText(tr("Set").append(" %1: %2").arg(i+1).arg(tempNameEscaped)); } else { tempSetButton->setText(QString::number(i+1)); tempSetButton->setToolTip(""); tempSetAction->setText(tr("Set").append(" %1").arg(i+1)); } } } void JoyTabWidget::displayProfileEditNotification() { int currentIndex = configBox->currentIndex(); configBox->setItemIcon(currentIndex, QIcon::fromTheme("document-save-as", QIcon(":/icons/16x16/actions/document-save.png"))); } void JoyTabWidget::removeProfileEditNotification() { for (int i=0; i < configBox->count(); i++) { if (!configBox->itemIcon(i).isNull()) { configBox->setItemIcon(i, QIcon()); } } } void JoyTabWidget::retranslateUi() { removeButton->setText(tr("Remove")); removeButton->setToolTip(tr("Remove configuration from recent list.")); loadButton->setText(tr("Load")); loadButton->setToolTip(tr("Load configuration file.")); saveButton->setText(tr("Save")); saveButton->setToolTip(tr("Save changes to configuration file.")); saveAsButton->setText(tr("Save As")); saveAsButton->setToolTip(tr("Save changes to a new configuration file.")); setsMenuButton->setText(tr("Sets")); setAction1->setText(tr("Set 1")); setAction2->setText(tr("Set 2")); setAction3->setText(tr("Set 3")); setAction4->setText(tr("Set 4")); setAction5->setText(tr("Set 5")); setAction6->setText(tr("Set 6")); setAction7->setText(tr("Set 7")); setAction8->setText(tr("Set 8")); refreshSetButtons(); refreshCopySetActions(); gameControllerMappingPushButton->setText(tr("Controller Mapping")); stickAssignPushButton->setText(tr("Stick/Pad Assign")); quickSetPushButton->setText(tr("Quick Set")); resetButton->setText(tr("Reset")); namesPushButton->setText(tr("Names")); namesPushButton->setToolTip(tr("Toggle button name displaying.")); delayButton->setText(tr("Pref")); delayButton->setToolTip(tr("Change global profile settings.")); resetButton->setText(tr("Reset")); resetButton->setToolTip(tr("Revert changes to the configuration. Reload configuration file.")); refreshButtons(); } void JoyTabWidget::checkForUnsavedProfile(int newindex) { if (joystick->isDeviceEdited()) { disconnectCheckUnsavedEvent(); disconnectMainComboBoxEvents(); if (configBox->currentIndex() != comboBoxIndex) { configBox->setCurrentIndex(comboBoxIndex); } QMessageBox msg; msg.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); msg.setWindowTitle(tr("Save Profile Changes?")); if (comboBoxIndex == 0) { msg.setText(tr("Changes to the new profile have not been saved. Would you like to save or discard the current profile?")); } else { msg.setText(tr("Changes to the profile \"%1\" have not been saved. Would you like to save or discard changes to the current profile?") .arg(configBox->currentText())); } int status = msg.exec(); if (status == QMessageBox::Save) { saveConfigFile(); reconnectCheckUnsavedEvent(); reconnectMainComboBoxEvents(); if (newindex > -1) { configBox->setCurrentIndex(newindex); } } else if (status == QMessageBox::Discard) { joystick->revertProfileEdited(); configBox->setItemText(comboBoxIndex, oldProfileName); reconnectCheckUnsavedEvent(); reconnectMainComboBoxEvents(); if (newindex > -1) { configBox->setCurrentIndex(newindex); } } else if (status == QMessageBox::Cancel) { reconnectCheckUnsavedEvent(); reconnectMainComboBoxEvents(); } } } bool JoyTabWidget::discardUnsavedProfileChanges() { bool discarded = true; if (joystick->isDeviceEdited()) { disconnectCheckUnsavedEvent(); QMessageBox msg; msg.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); msg.setWindowTitle(tr("Save Profile Changes?")); int currentIndex = configBox->currentIndex(); if (currentIndex == 0) { msg.setText(tr("Changes to the new profile have not been saved. Would you like to save or discard the current profile?")); } else { msg.setText(tr("Changes to the profile \"%1\" have not been saved. Would you like to save or discard changes to the current profile?") .arg(configBox->currentText())); } int status = msg.exec(); if (status == QMessageBox::Save) { saveConfigFile(); if (currentIndex == 0 && currentIndex == configBox->currentIndex()) { discarded = false; } } else if (status == QMessageBox::Discard) { joystick->revertProfileEdited(); configBox->setItemText(currentIndex, oldProfileName); resetJoystick(); } else if (status == QMessageBox::Cancel) { discarded = false; } disconnectMainComboBoxEvents(); reconnectCheckUnsavedEvent(); reconnectMainComboBoxEvents(); } return discarded; } void JoyTabWidget::disconnectMainComboBoxEvents() { disconnect(configBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeJoyConfig(int))); disconnect(configBox, SIGNAL(currentIndexChanged(int)), this, SLOT(removeProfileEditNotification())); disconnect(joystick, SIGNAL(profileNameEdited(QString)), this, SLOT(editCurrentProfileItemText(QString))); } void JoyTabWidget::reconnectMainComboBoxEvents() { connect(configBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeJoyConfig(int)), Qt::QueuedConnection); connect(configBox, SIGNAL(currentIndexChanged(int)), this, SLOT(removeProfileEditNotification()), Qt::QueuedConnection); connect(joystick, SIGNAL(profileNameEdited(QString)), this, SLOT(editCurrentProfileItemText(QString))); } void JoyTabWidget::disconnectCheckUnsavedEvent() { disconnect(configBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkForUnsavedProfile(int))); } void JoyTabWidget::reconnectCheckUnsavedEvent() { connect(configBox, SIGNAL(currentIndexChanged(int)), this, SLOT(checkForUnsavedProfile(int))); } void JoyTabWidget::refreshButtons() { removeCurrentButtons(); fillButtons(); } void JoyTabWidget::checkStickDisplay() { JoyControlStickButton *button = static_cast(sender()); JoyControlStick *stick = button->getStick(); if (stick && stick->hasSlotsAssigned()) { SetJoystick *currentSet = joystick->getActiveSetJoystick(); removeSetButtons(currentSet); fillSetButtons(currentSet); } } void JoyTabWidget::checkDPadButtonDisplay() { JoyDPadButton *button = static_cast(sender()); JoyDPad *dpad = button->getDPad(); if (dpad && dpad->hasSlotsAssigned()) { SetJoystick *currentSet = joystick->getActiveSetJoystick(); removeSetButtons(currentSet); fillSetButtons(currentSet); } } void JoyTabWidget::checkAxisButtonDisplay() { JoyAxisButton *button = static_cast(sender()); if (button->getAssignedSlots()->count() > 0) { SetJoystick *currentSet = joystick->getActiveSetJoystick(); removeSetButtons(currentSet); fillSetButtons(currentSet); } } void JoyTabWidget::checkButtonDisplay() { JoyButton *button = static_cast(sender()); if (button->getAssignedSlots()->count() > 0) { SetJoystick *currentSet = joystick->getActiveSetJoystick(); removeSetButtons(currentSet); fillSetButtons(currentSet); } } void JoyTabWidget::checkStickEmptyDisplay() { StickPushButtonGroup *group = static_cast(sender()); JoyControlStick *stick = group->getStick(); //JoyControlStickButton *button = static_cast(sender()); //JoyControlStick *stick = button->getStick(); if (stick && !stick->hasSlotsAssigned()) { SetJoystick *currentSet = joystick->getActiveSetJoystick(); removeSetButtons(currentSet); fillSetButtons(currentSet); } } void JoyTabWidget::checkDPadButtonEmptyDisplay() { DPadPushButtonGroup *group = static_cast(sender()); JoyDPad *dpad = group->getDPad(); //JoyDPadButton *button = static_cast(sender()); //JoyDPad *dpad = button->getDPad(); if (dpad && !dpad->hasSlotsAssigned()) { SetJoystick *currentSet = joystick->getActiveSetJoystick(); removeSetButtons(currentSet); fillSetButtons(currentSet); } } void JoyTabWidget::checkAxisButtonEmptyDisplay() { JoyAxisButton *button = static_cast(sender()); if (button->getAssignedSlots()->count() == 0) { SetJoystick *currentSet = joystick->getActiveSetJoystick(); removeSetButtons(currentSet); fillSetButtons(currentSet); } } void JoyTabWidget::checkButtonEmptyDisplay() { JoyButton *button = static_cast(sender()); if (button->getAssignedSlots()->count() == 0) { SetJoystick *currentSet = joystick->getActiveSetJoystick(); removeSetButtons(currentSet); fillSetButtons(currentSet); } } void JoyTabWidget::checkHideEmptyOption() { bool currentHideEmptyButtons = settings->value("HideEmptyButtons", false).toBool(); if (currentHideEmptyButtons != hideEmptyButtons) { hideEmptyButtons = currentHideEmptyButtons; refreshButtons(); } } void JoyTabWidget::fillSetButtons(SetJoystick *set) { int row = 0; int column = 0; //QWidget *child = 0; QGridLayout *current_layout = 0; switch (set->getIndex()) { case 0: { current_layout = gridLayout; break; } case 1: { current_layout = gridLayout2; break; } case 2: { current_layout = gridLayout3; break; } case 3: { current_layout = gridLayout4; break; } case 4: { current_layout = gridLayout5; break; } case 5: { current_layout = gridLayout6; break; } case 6: { current_layout = gridLayout7; break; } case 7: { current_layout = gridLayout8; break; } default: break; } /*while (current_layout && current_layout->count() > 0) { child = current_layout->takeAt(0)->widget(); current_layout->removeWidget (child); delete child; child = 0; } */ SetJoystick *currentSet = set; currentSet->establishPropertyUpdatedConnection(); QGridLayout *stickGrid = 0; QGroupBox *stickGroup = 0; int stickGridColumn = 0; int stickGridRow = 0; for (int j=0; j < joystick->getNumberSticks(); j++) { JoyControlStick *stick = currentSet->getJoyStick(j); stick->establishPropertyUpdatedConnection(); QHash *stickButtons = stick->getButtons(); if (!hideEmptyButtons || stick->hasSlotsAssigned()) { if (!stickGroup) { stickGroup = new QGroupBox(tr("Sticks"), this); } if (!stickGrid) { stickGrid = new QGridLayout(); stickGridColumn = 0; stickGridRow = 0; } QWidget *groupContainer = new QWidget(stickGroup); StickPushButtonGroup *stickButtonGroup = new StickPushButtonGroup(stick, displayingNames, groupContainer); if (hideEmptyButtons) { connect(stickButtonGroup, SIGNAL(buttonSlotChanged()), this, SLOT(checkStickEmptyDisplay())); } connect(namesPushButton, SIGNAL(clicked()), stickButtonGroup, SLOT(toggleNameDisplay())); if (stickGridColumn > 1) { stickGridColumn = 0; stickGridRow++; } groupContainer->setLayout(stickButtonGroup); stickGrid->addWidget(groupContainer, stickGridRow, stickGridColumn); stickGridColumn++; } else { QHashIterator tempiter(*stickButtons); while (tempiter.hasNext()) { JoyControlStickButton *button = tempiter.next().value(); button->establishPropertyUpdatedConnections(); connect(button, SIGNAL(slotsChanged()), this, SLOT(checkStickDisplay())); } } } if (stickGroup) { QSpacerItem *tempspacer = new QSpacerItem(10, 4, QSizePolicy::Minimum, QSizePolicy::Fixed); QVBoxLayout *tempvbox = new QVBoxLayout; tempvbox->addLayout(stickGrid); tempvbox->addItem(tempspacer); stickGroup->setLayout(tempvbox); current_layout->addWidget(stickGroup, row, column, 1, 2, Qt::AlignTop); row++; } column = 0; QGridLayout *hatGrid = 0; QGroupBox *hatGroup = 0; int hatGridColumn = 0; int hatGridRow = 0; for (int j=0; j < joystick->getNumberHats(); j++) { JoyDPad *dpad = currentSet->getJoyDPad(j); dpad->establishPropertyUpdatedConnection(); QHash *buttons = dpad->getJoyButtons(); if (!hideEmptyButtons || dpad->hasSlotsAssigned()) { if (!hatGroup) { hatGroup = new QGroupBox(tr("DPads"), this); } if (!hatGrid) { hatGrid = new QGridLayout(); hatGridColumn = 0; hatGridRow = 0; } QWidget *groupContainer = new QWidget(hatGroup); DPadPushButtonGroup *dpadButtonGroup = new DPadPushButtonGroup(dpad, displayingNames, groupContainer); if (hideEmptyButtons) { connect(dpadButtonGroup, SIGNAL(buttonSlotChanged()), this, SLOT(checkDPadButtonEmptyDisplay())); } connect(namesPushButton, SIGNAL(clicked()), dpadButtonGroup, SLOT(toggleNameDisplay())); if (hatGridColumn > 1) { hatGridColumn = 0; hatGridRow++; } groupContainer->setLayout(dpadButtonGroup); hatGrid->addWidget(groupContainer, hatGridRow, hatGridColumn); hatGridColumn++; } else { QHashIterator tempiter(*buttons); while (tempiter.hasNext()) { JoyDPadButton *button = tempiter.next().value(); button->establishPropertyUpdatedConnections(); connect(button, SIGNAL(slotsChanged()), this, SLOT(checkDPadButtonDisplay())); } } } for (int j=0; j < joystick->getNumberVDPads(); j++) { VDPad *vdpad = currentSet->getVDPad(j); vdpad->establishPropertyUpdatedConnection(); QHash *buttons = vdpad->getButtons(); if (!hideEmptyButtons || vdpad->hasSlotsAssigned()) { if (!hatGroup) { hatGroup = new QGroupBox(tr("DPads"), this); } if (!hatGrid) { hatGrid = new QGridLayout(); hatGridColumn = 0; hatGridRow = 0; } QWidget *groupContainer = new QWidget(hatGroup); DPadPushButtonGroup *dpadButtonGroup = new DPadPushButtonGroup(vdpad, displayingNames, groupContainer); if (hideEmptyButtons) { connect(dpadButtonGroup, SIGNAL(buttonSlotChanged()), this, SLOT(checkDPadButtonEmptyDisplay())); } connect(namesPushButton, SIGNAL(clicked()), dpadButtonGroup, SLOT(toggleNameDisplay())); if (hatGridColumn > 1) { hatGridColumn = 0; hatGridRow++; } groupContainer->setLayout(dpadButtonGroup); hatGrid->addWidget(groupContainer, hatGridRow, hatGridColumn); hatGridColumn++; } else { QHashIterator tempiter(*buttons); while (tempiter.hasNext()) { JoyDPadButton *button = tempiter.next().value(); button->establishPropertyUpdatedConnections(); connect(button, SIGNAL(slotsChanged()), this, SLOT(checkDPadButtonDisplay())); } } } if (hatGroup) { QSpacerItem *tempspacer = new QSpacerItem(10, 4, QSizePolicy::Minimum, QSizePolicy::Fixed); QVBoxLayout *tempvbox = new QVBoxLayout; tempvbox->addLayout(hatGrid); tempvbox->addItem(tempspacer); hatGroup->setLayout(tempvbox); current_layout->addWidget(hatGroup, row, column, 1, 2, Qt::AlignTop); row++; } column = 0; for (int j=0; j < joystick->getNumberAxes(); j++) { JoyAxis *axis = currentSet->getJoyAxis(j); if (!axis->isPartControlStick() && axis->hasControlOfButtons()) { JoyAxisButton *paxisbutton = axis->getPAxisButton(); JoyAxisButton *naxisbutton = axis->getNAxisButton(); if (!hideEmptyButtons || (paxisbutton->getAssignedSlots()->count() > 0 || naxisbutton->getAssignedSlots()->count() > 0)) { JoyAxisWidget *axisWidget = new JoyAxisWidget(axis, displayingNames, this); axisWidget->setText(axis->getName()); axisWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); axisWidget->setMinimumSize(200, 24); connect(axisWidget, SIGNAL(clicked()), this, SLOT(showAxisDialog())); connect(namesPushButton, SIGNAL(clicked()), axisWidget, SLOT(toggleNameDisplay())); if (hideEmptyButtons) { connect(paxisbutton, SIGNAL(slotsChanged()), this, SLOT(checkAxisButtonEmptyDisplay())); connect(naxisbutton, SIGNAL(slotsChanged()), this, SLOT(checkAxisButtonEmptyDisplay())); } if (column > 1) { column = 0; row++; } current_layout->addWidget(axisWidget, row, column); column++; } else { paxisbutton->establishPropertyUpdatedConnections(); naxisbutton->establishPropertyUpdatedConnections(); connect(paxisbutton, SIGNAL(slotsChanged()), this, SLOT(checkAxisButtonDisplay())); connect(naxisbutton, SIGNAL(slotsChanged()), this, SLOT(checkAxisButtonDisplay())); } } } for (int j=0; j < joystick->getNumberButtons(); j++) { JoyButton *button = currentSet->getJoyButton(j); if (button && !button->isPartVDPad()) { button->establishPropertyUpdatedConnections(); if (!hideEmptyButtons || button->getAssignedSlots()->count() > 0) { JoyButtonWidget *buttonWidget = new JoyButtonWidget (button, displayingNames, this); buttonWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); buttonWidget->setText(buttonWidget->text()); buttonWidget->setMinimumSize(200, 24); connect(buttonWidget, SIGNAL(clicked()), this, SLOT(showButtonDialog())); connect(namesPushButton, SIGNAL(clicked()), buttonWidget, SLOT(toggleNameDisplay())); if (hideEmptyButtons) { connect(button, SIGNAL(slotsChanged()), this, SLOT(checkButtonEmptyDisplay())); } if (column > 1) { column = 0; row++; } current_layout->addWidget(buttonWidget, row, column); column++; } else { button->establishPropertyUpdatedConnections(); connect(button, SIGNAL(slotsChanged()), this, SLOT(checkButtonDisplay())); } } } if (current_layout->count() == 0) { QLabel *newlabel = new QLabel(tr("No buttons have been assigned. Please use Quick Set to assign keys\nto buttons or disable hiding empty buttons.")); current_layout->addWidget(newlabel, 0, 0, Qt::AlignCenter); } } void JoyTabWidget::removeSetButtons(SetJoystick *set) { SetJoystick *currentSet = set; currentSet->disconnectPropertyUpdatedConnection(); QLayoutItem *child = 0; QGridLayout *current_layout = 0; switch (currentSet->getIndex()) { case 0: { current_layout = gridLayout; break; } case 1: { current_layout = gridLayout2; break; } case 2: { current_layout = gridLayout3; break; } case 3: { current_layout = gridLayout4; break; } case 4: { current_layout = gridLayout5; break; } case 5: { current_layout = gridLayout6; break; } case 6: { current_layout = gridLayout7; break; } case 7: { current_layout = gridLayout8; break; } } while (current_layout && (child = current_layout->takeAt(0)) != 0) { current_layout->removeWidget(child->widget()); delete child->widget(); delete child; child = 0; } for (int j=0; j < joystick->getNumberSticks(); j++) { JoyControlStick *stick = currentSet->getJoyStick(j); stick->disconnectPropertyUpdatedConnection(); QHash *stickButtons = stick->getButtons(); QHashIterator tempiter(*stickButtons); while (tempiter.hasNext()) { JoyControlStickButton *button = tempiter.next().value(); button->disconnectPropertyUpdatedConnections(); disconnect(button, SIGNAL(slotsChanged()), this, SLOT(checkStickDisplay())); disconnect(button, SIGNAL(slotsChanged()), this, SLOT(checkStickEmptyDisplay())); } } for (int j=0; j < joystick->getNumberHats(); j++) { JoyDPad *dpad = currentSet->getJoyDPad(j); dpad->establishPropertyUpdatedConnection(); QHash *buttons = dpad->getJoyButtons(); QHashIterator tempiter(*buttons); while (tempiter.hasNext()) { JoyDPadButton *button = tempiter.next().value(); button->disconnectPropertyUpdatedConnections(); disconnect(button, SIGNAL(slotsChanged()), this, SLOT(checkDPadButtonDisplay())); disconnect(button, SIGNAL(slotsChanged()), this, SLOT(checkDPadButtonEmptyDisplay())); } } for (int j=0; j < joystick->getNumberVDPads(); j++) { VDPad *vdpad = currentSet->getVDPad(j); vdpad->establishPropertyUpdatedConnection(); QHash *buttons = vdpad->getButtons(); QHashIterator tempiter(*buttons); while (tempiter.hasNext()) { JoyDPadButton *button = tempiter.next().value(); button->disconnectPropertyUpdatedConnections(); disconnect(button, SIGNAL(slotsChanged()), this, SLOT(checkDPadButtonDisplay())); disconnect(button, SIGNAL(slotsChanged()), this, SLOT(checkDPadButtonEmptyDisplay())); } } for (int j=0; j < joystick->getNumberAxes(); j++) { JoyAxis *axis = currentSet->getJoyAxis(j); if (!axis->isPartControlStick() && axis->hasControlOfButtons()) { JoyAxisButton *paxisbutton = axis->getPAxisButton(); JoyAxisButton *naxisbutton = axis->getNAxisButton(); paxisbutton->disconnectPropertyUpdatedConnections(); naxisbutton->disconnectPropertyUpdatedConnections(); disconnect(paxisbutton, SIGNAL(slotsChanged()), this, SLOT(checkAxisButtonDisplay())); disconnect(naxisbutton, SIGNAL(slotsChanged()), this, SLOT(checkAxisButtonDisplay())); disconnect(paxisbutton, SIGNAL(slotsChanged()), this, SLOT(checkAxisButtonEmptyDisplay())); disconnect(naxisbutton, SIGNAL(slotsChanged()), this, SLOT(checkAxisButtonEmptyDisplay())); } } for (int j=0; j < joystick->getNumberButtons(); j++) { JoyButton *button = currentSet->getJoyButton(j); if (button && !button->isPartVDPad()) { button->disconnectPropertyUpdatedConnections(); disconnect(button, SIGNAL(slotsChanged()), this, SLOT(checkButtonDisplay())); disconnect(button, SIGNAL(slotsChanged()), this, SLOT(checkButtonEmptyDisplay())); } } } void JoyTabWidget::editCurrentProfileItemText(QString text) { int currentIndex = configBox->currentIndex(); if (currentIndex >= 0) { if (!text.isEmpty()) { configBox->setItemText(currentIndex, text); } else if (currentIndex == 0) { configBox->setItemText(currentIndex, tr("")); } else if (currentIndex > 0) { QFileInfo profileName(configBox->itemData(currentIndex).toString()); configBox->setItemText(currentIndex, PadderCommon::getProfileName(profileName)); } } } #ifdef Q_OS_WIN void JoyTabWidget::deviceKeyRepeatSettings() { bool keyRepeatActive = settings->value("KeyRepeat/KeyRepeatEnabled", true).toBool(); int keyRepeatDelay = settings->value("KeyRepeat/KeyRepeatDelay", InputDevice::DEFAULTKEYREPEATDELAY).toInt(); int keyRepeatRate = settings->value("KeyRepeat/KeyRepeatRate", InputDevice::DEFAULTKEYREPEATRATE).toInt(); joystick->setKeyRepeatStatus(keyRepeatActive); joystick->setKeyRepeatDelay(keyRepeatDelay); joystick->setKeyRepeatRate(keyRepeatRate); } #endif void JoyTabWidget::refreshCopySetActions() { copySetMenu->clear(); for (int i=0; i < InputDevice::NUMBER_JOYSETS; i++) { SetJoystick *tempSet = joystick->getSetJoystick(i); QAction *newaction = 0; if (!tempSet->getName().isEmpty()) { QString tempName = tempSet->getName(); QString tempNameEscaped = tempName; tempNameEscaped.replace("&", "&&"); newaction = new QAction(tr("Set %1: %2").arg(i+1).arg(tempNameEscaped), copySetMenu); } else { newaction = new QAction(tr("Set %1").arg(i+1), copySetMenu); } newaction->setData(i); connect(newaction, SIGNAL(triggered()), this, SLOT(performSetCopy())); copySetMenu->addAction(newaction); } connect(copySetMenu, SIGNAL(aboutToShow()), this, SLOT(disableCopyCurrentSet())); } void JoyTabWidget::performSetCopy() { QAction *action = static_cast(sender()); int sourceSetIndex = action->data().toInt(); SetJoystick *sourceSet = joystick->getSetJoystick(sourceSetIndex); QString sourceName; if (!sourceSet->getName().isEmpty()) { QString tempNameEscaped = sourceSet->getName(); tempNameEscaped.replace("&", "&&"); sourceName = tr("Set %1: %2").arg(sourceSetIndex+1).arg(tempNameEscaped); } else { sourceName = tr("Set %1").arg(sourceSetIndex+1); } SetJoystick *destSet = joystick->getActiveSetJoystick(); if (sourceSet && destSet) { QMessageBox msgBox; msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setWindowTitle(tr("Copy Set Assignments")); msgBox.setText(tr("Are you sure you want to copy the assignments and device properties from %1?").arg(sourceName)); int status = msgBox.exec(); if (status == QMessageBox::Yes) { PadderCommon::lockInputDevices(); removeSetButtons(destSet); QMetaObject::invokeMethod(sourceSet, "copyAssignments", Qt::BlockingQueuedConnection, Q_ARG(SetJoystick*, destSet)); //sourceSet->copyAssignments(destSet); fillSetButtons(destSet); PadderCommon::unlockInputDevices(); } } } void JoyTabWidget::disableCopyCurrentSet() { SetJoystick *activeSet = joystick->getActiveSetJoystick(); QMenu *menu = static_cast(sender()); QList actions = menu->actions(); QListIterator iter(actions); while (iter.hasNext()) { QAction *action = iter.next(); if (action->data().toInt() == activeSet->getIndex()) { action->setEnabled(false); } else { action->setEnabled(true); } } } #ifdef USE_SDL_2 void JoyTabWidget::openGameControllerMappingWindow() { GameControllerMappingDialog *dialog = new GameControllerMappingDialog(joystick, settings, this); dialog->show(); connect(dialog, SIGNAL(mappingUpdate(QString,InputDevice*)), this, SLOT(propogateMappingUpdate(QString, InputDevice*))); } void JoyTabWidget::propogateMappingUpdate(QString mapping, InputDevice *device) { emit mappingUpdated(mapping, device); } #endif void JoyTabWidget::refreshHelperThread() { tabHelper.moveToThread(joystick->thread()); } void JoyTabWidget::changeEvent(QEvent *event) { if (event->type() == QEvent::LanguageChange) { retranslateUi(); } QWidget::changeEvent(event); } antimicro-2.23/src/joytabwidget.h000066400000000000000000000137601300750276700170770ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYTABWIDGET_H #define JOYTABWIDGET_H #include #include #include #include #include #include #include #include #include #include #include #include #include "uihelpers/joytabwidgethelper.h" #include "joystick.h" #include "axiseditdialog.h" #include "inputdevice.h" #include "antimicrosettings.h" class JoyTabWidget : public QWidget { Q_OBJECT public: explicit JoyTabWidget(InputDevice *joystick, AntiMicroSettings *settings, QWidget *parent = 0); void saveSettings(); void loadSettings(bool forceRefresh=false); QHash* recentConfigs(); void setCurrentConfig(int index); int getCurrentConfigIndex(); QString getCurrentConfigName(); QString getConfigName(int index); InputDevice *getJoystick(); void unloadConfig(); bool isDisplayingNames(); bool discardUnsavedProfileChanges(); void checkHideEmptyOption(); void refreshHelperThread(); #ifdef Q_OS_WIN void deviceKeyRepeatSettings(); #endif protected: virtual void changeEvent(QEvent *event); void removeCurrentButtons(); void retranslateUi(); void disconnectMainComboBoxEvents(); void reconnectMainComboBoxEvents(); void disconnectCheckUnsavedEvent(); void reconnectCheckUnsavedEvent(); void fillSetButtons(SetJoystick *set); void removeSetButtons(SetJoystick *set); QVBoxLayout *verticalLayout; QHBoxLayout *configHorizontalLayout; QPushButton *removeButton; QPushButton *loadButton; QPushButton *saveButton; QPushButton *resetButton; QPushButton *namesPushButton; QPushButton *saveAsButton; QPushButton *delayButton; QComboBox *configBox; QGridLayout *gridLayout; QGridLayout *gridLayout2; QGridLayout *gridLayout3; QGridLayout *gridLayout4; QGridLayout *gridLayout5; QGridLayout *gridLayout6; QGridLayout *gridLayout7; QGridLayout *gridLayout8; QSpacerItem *spacer1; QSpacerItem *spacer2; QSpacerItem *spacer3; AxisEditDialog *axisDialog; QPushButton *setPushButton1; QPushButton *setPushButton2; QPushButton *setPushButton3; QPushButton *setPushButton4; QPushButton *setPushButton5; QPushButton *setPushButton6; QPushButton *setPushButton7; QPushButton *setPushButton8; QPushButton *setsMenuButton; QAction *setAction1; QAction *setAction2; QAction *setAction3; QAction *setAction4; QAction *setAction5; QAction *setAction6; QAction *setAction7; QAction *setAction8; QMenu *copySetMenu; QHBoxLayout *horizontalLayout_2; QHBoxLayout *horizontalLayout_3; QPushButton *stickAssignPushButton; QPushButton *quickSetPushButton; QPushButton *gameControllerMappingPushButton; QSpacerItem *verticalSpacer_2; QStackedWidget *stackedWidget_2; QWidget *page; QWidget *page_2; QWidget *page_3; QWidget *page_4; QWidget *page_5; QWidget *page_6; QWidget *page_7; QWidget *page_8; QPushButton *pushButton; QSpacerItem *verticalSpacer_3; InputDevice *joystick; bool displayingNames; AntiMicroSettings *settings; int comboBoxIndex; bool hideEmptyButtons; QString oldProfileName; JoyTabWidgetHelper tabHelper; static const int DEFAULTNUMBERPROFILES = 5; signals: void joystickConfigChanged(int index); void joystickAxisRefreshLabels(int axisIndex); void namesDisplayChanged(bool status); void forceTabUnflash(JoyTabWidget *tabWidget); #ifdef USE_SDL_2 void mappingUpdated(QString mapping, InputDevice *device); #endif public slots: void openConfigFileDialog(); void fillButtons(); void saveDeviceSettings(bool sync=false); void loadDeviceSettings(); void changeNameDisplay(bool displayNames); void changeCurrentSet(int index); void loadConfigFile(QString fileLocation); void refreshButtons(); private slots: void saveConfigFile(); void resetJoystick(); void saveAsConfig(); void removeConfig(); void changeJoyConfig(int index); void showAxisDialog(); void showButtonDialog(); void showStickAssignmentDialog(); void showQuickSetDialog(); void showKeyDelayDialog(); void showSetNamesDialog(); void toggleNames(); void changeSetOne(); void changeSetTwo(); void changeSetThree(); void changeSetFour(); void changeSetFive(); void changeSetSix(); void changeSetSeven(); void changeSetEight(); void displayProfileEditNotification(); void removeProfileEditNotification(); void checkForUnsavedProfile(int newindex=-1); void checkStickDisplay(); void checkDPadButtonDisplay(); void checkAxisButtonDisplay(); void checkButtonDisplay(); void checkStickEmptyDisplay(); void checkDPadButtonEmptyDisplay(); void checkAxisButtonEmptyDisplay(); void checkButtonEmptyDisplay(); void editCurrentProfileItemText(QString text); void refreshCopySetActions(); void performSetCopy(); void disableCopyCurrentSet(); void refreshSetButtons(); #ifdef USE_SDL_2 void openGameControllerMappingWindow(); void propogateMappingUpdate(QString mapping, InputDevice *device); #endif }; #endif // JOYTABWIDGET_H antimicro-2.23/src/joytabwidgetcontainer.cpp000066400000000000000000000063071300750276700213340ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "joytabwidgetcontainer.h" JoyTabWidgetContainer::JoyTabWidgetContainer(QWidget *parent) : QTabWidget(parent) { } int JoyTabWidgetContainer::addTab(QWidget *widget, const QString &string) { return QTabWidget::addTab(widget, string); } int JoyTabWidgetContainer::addTab(JoyTabWidget *widget, const QString &string) { InputDevice *joystick = widget->getJoystick(); if (joystick) { enableFlashes(joystick); connect(widget, SIGNAL(forceTabUnflash(JoyTabWidget*)), this, SLOT(unflashTab(JoyTabWidget*))); } return QTabWidget::addTab(widget, string); } void JoyTabWidgetContainer::flash() { InputDevice *joystick = static_cast(sender()); bool found = false; for (int i = 0; i < tabBar()->count() && !found; i++) { JoyTabWidget *tab = static_cast(widget(i)); if (tab && tab->getJoystick() == joystick) { tabBar()->setTabTextColor(i, Qt::red); found = true; } } } void JoyTabWidgetContainer::unflash() { InputDevice *joystick = static_cast(sender()); bool found = false; for (int i = 0; i < tabBar()->count() && !found; i++) { JoyTabWidget *tab = static_cast(widget(i)); if (tab && tab->getJoystick() == joystick) { tabBar()->setTabTextColor(i, Qt::black); found = true; } } } void JoyTabWidgetContainer::unflashTab(JoyTabWidget *tabWidget) { bool found = false; for (int i=0; i < tabBar()->count() && !found; i++) { JoyTabWidget *tab = static_cast(widget(i)); if (tab == tabWidget) { tabBar()->setTabTextColor(i, Qt::black); } } } void JoyTabWidgetContainer::unflashAll() { for (int i = 0; i < tabBar()->count(); i++) { JoyTabWidget *tab = static_cast(widget(i)); if (tab) { tabBar()->setTabTextColor(i, Qt::black); } } } void JoyTabWidgetContainer::disableFlashes(InputDevice *joystick) { unflashAll(); disconnect(joystick, SIGNAL(clicked(int)), this, SLOT(flash())); disconnect(joystick, SIGNAL(released(int)), this, SLOT(unflash())); } void JoyTabWidgetContainer::enableFlashes(InputDevice *joystick) { connect(joystick, SIGNAL(clicked(int)), this, SLOT(flash()), Qt::QueuedConnection); connect(joystick, SIGNAL(released(int)), this, SLOT(unflash()), Qt::QueuedConnection); } antimicro-2.23/src/joytabwidgetcontainer.h000066400000000000000000000026301300750276700207740ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYTABWIDGETCONTAINER_H #define JOYTABWIDGETCONTAINER_H #include #include "joystick.h" #include "joytabwidget.h" class JoyTabWidgetContainer : public QTabWidget { Q_OBJECT public: explicit JoyTabWidgetContainer(QWidget *parent = 0); int addTab(QWidget *widget, const QString &string); int addTab(JoyTabWidget *widget, const QString &string); protected: signals: public slots: void disableFlashes(InputDevice *joystick); void enableFlashes(InputDevice *joystick); private slots: void flash(); void unflash(); void unflashAll(); void unflashTab(JoyTabWidget *tabWidget); }; #endif // JOYTABWIDGETCONTAINER_H antimicro-2.23/src/keyboard/000077500000000000000000000000001300750276700160235ustar00rootroot00000000000000antimicro-2.23/src/keyboard/virtualkeyboardmousewidget.cpp000066400000000000000000001016671300750276700242260ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include #include #include #include "virtualkeyboardmousewidget.h" #include #include #include QHash VirtualKeyboardMouseWidget::topRowKeys = QHash (); VirtualKeyboardMouseWidget::VirtualKeyboardMouseWidget(JoyButton *button, QWidget *parent) : QTabWidget(parent) { this->button = button; keyboardTab = new QWidget(this); mouseTab = new QWidget(this); noneButton = createNoneKey(); populateTopRowKeys(); this->addTab(keyboardTab, tr("Keyboard")); this->addTab(mouseTab, tr("Mouse")); this->setTabPosition(QTabWidget::South); setupVirtualKeyboardLayout(); setupMouseControlLayout(); establishVirtualKeyboardSingleSignalConnections(); establishVirtualMouseSignalConnections(); QTimer::singleShot(0, this, SLOT(setButtonFontSizes())); connect(mouseSettingsPushButton, SIGNAL(clicked()), this, SLOT(openMouseSettingsDialog())); } VirtualKeyboardMouseWidget::VirtualKeyboardMouseWidget(QWidget *parent) : QTabWidget(parent) { keyboardTab = new QWidget(this); mouseTab = new QWidget(this); noneButton = createNoneKey(); populateTopRowKeys(); this->addTab(keyboardTab, tr("Keyboard")); this->addTab(mouseTab, tr("Mouse")); this->setTabPosition(QTabWidget::South); QTimer::singleShot(0, this, SLOT(setButtonFontSizes())); } void VirtualKeyboardMouseWidget::setupVirtualKeyboardLayout() { QVBoxLayout *finalVBoxLayout = new QVBoxLayout(keyboardTab); QVBoxLayout *tempMainKeyLayout = setupMainKeyboardLayout(); QVBoxLayout *tempAuxKeyLayout = setupAuxKeyboardLayout(); QVBoxLayout *tempNumKeyPadLayout = setupKeyboardNumPadLayout(); QHBoxLayout *tempHBoxLayout = new QHBoxLayout(); tempHBoxLayout->addLayout(tempMainKeyLayout); tempHBoxLayout->addLayout(tempAuxKeyLayout); tempHBoxLayout->addLayout(tempNumKeyPadLayout); finalVBoxLayout->addLayout(tempHBoxLayout); } QVBoxLayout *VirtualKeyboardMouseWidget::setupMainKeyboardLayout() { QHBoxLayout *tempHBoxLayout = new QHBoxLayout(); tempHBoxLayout->setSpacing(0); QVBoxLayout *tempVBoxLayout = new QVBoxLayout(); QVBoxLayout *finalVBoxLayout = new QVBoxLayout(); tempHBoxLayout->addWidget(createNewKey("Escape")); tempHBoxLayout->addSpacerItem(new QSpacerItem(40, 10, QSizePolicy::Expanding)); tempHBoxLayout->addWidget(createNewKey("F1")); tempHBoxLayout->addWidget(createNewKey("F2")); tempHBoxLayout->addWidget(createNewKey("F3")); tempHBoxLayout->addWidget(createNewKey("F4")); tempHBoxLayout->addSpacerItem(new QSpacerItem(40, 10, QSizePolicy::Expanding)); tempHBoxLayout->addWidget(createNewKey("F5")); tempHBoxLayout->addWidget(createNewKey("F6")); tempHBoxLayout->addWidget(createNewKey("F7")); tempHBoxLayout->addWidget(createNewKey("F8")); tempHBoxLayout->addSpacerItem(new QSpacerItem(40, 10, QSizePolicy::Expanding)); tempHBoxLayout->addWidget(createNewKey("F9")); tempHBoxLayout->addWidget(createNewKey("F10")); tempHBoxLayout->addWidget(createNewKey("F11")); tempHBoxLayout->addWidget(createNewKey("F12")); finalVBoxLayout->addLayout(tempHBoxLayout); finalVBoxLayout->addSpacerItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Fixed)); tempHBoxLayout = new QHBoxLayout(); tempHBoxLayout->setSpacing(0); tempHBoxLayout->addWidget(createNewKey("grave")); for (int i=1; i <= 9; i++) { tempHBoxLayout->addWidget(createNewKey(QString::number(i))); } tempHBoxLayout->addWidget(createNewKey("0")); tempHBoxLayout->addWidget(createNewKey("minus")); tempHBoxLayout->addWidget(createNewKey("equal")); tempHBoxLayout->addWidget(createNewKey("BackSpace")); tempVBoxLayout->addLayout(tempHBoxLayout); QVBoxLayout *tempMiddleVLayout = new QVBoxLayout(); QHBoxLayout *tempMiddleHLayout = new QHBoxLayout(); tempHBoxLayout = new QHBoxLayout(); tempHBoxLayout->setSpacing(0); tempHBoxLayout->addWidget(createNewKey("Tab")); tempHBoxLayout->addSpacerItem(new QSpacerItem(10, 30, QSizePolicy::Fixed)); tempHBoxLayout->addWidget(createNewKey("q")); tempHBoxLayout->addWidget(createNewKey("w")); tempHBoxLayout->addWidget(createNewKey("e")); tempHBoxLayout->addWidget(createNewKey("r")); tempHBoxLayout->addWidget(createNewKey("t")); tempHBoxLayout->addWidget(createNewKey("y")); tempHBoxLayout->addWidget(createNewKey("u")); tempHBoxLayout->addWidget(createNewKey("i")); tempHBoxLayout->addWidget(createNewKey("o")); tempHBoxLayout->addWidget(createNewKey("p")); tempHBoxLayout->addWidget(createNewKey("bracketleft")); tempHBoxLayout->addWidget(createNewKey("bracketright")); if (QLocale::system().language() != QLocale::French && QLocale::system().language() != QLocale::German) { tempHBoxLayout->addWidget(createNewKey("backslash")); } tempMiddleVLayout->addLayout(tempHBoxLayout); tempHBoxLayout = new QHBoxLayout(); tempHBoxLayout->setSpacing(0); tempHBoxLayout->addWidget(createNewKey("Caps_Lock")); tempHBoxLayout->addWidget(createNewKey("a")); tempHBoxLayout->addWidget(createNewKey("s")); tempHBoxLayout->addWidget(createNewKey("d")); tempHBoxLayout->addWidget(createNewKey("f")); tempHBoxLayout->addWidget(createNewKey("g")); tempHBoxLayout->addWidget(createNewKey("h")); tempHBoxLayout->addWidget(createNewKey("j")); tempHBoxLayout->addWidget(createNewKey("k")); tempHBoxLayout->addWidget(createNewKey("l")); tempHBoxLayout->addWidget(createNewKey("semicolon")); tempHBoxLayout->addWidget(createNewKey("apostrophe")); if (QLocale::system().language() == QLocale::French || QLocale::system().language() == QLocale::German) { tempHBoxLayout->addWidget(createNewKey("asterisk")); } tempMiddleVLayout->addLayout(tempHBoxLayout); tempMiddleHLayout->addLayout(tempMiddleVLayout); tempMiddleHLayout->addWidget(createNewKey("Return")); tempVBoxLayout->addLayout(tempMiddleHLayout); tempHBoxLayout = new QHBoxLayout(); tempHBoxLayout->setSpacing(0); tempHBoxLayout->addWidget(createNewKey("Shift_L")); if (QLocale::system().language() == QLocale::French) { tempHBoxLayout->addWidget(createNewKey("less")); } tempHBoxLayout->addWidget(createNewKey("z")); tempHBoxLayout->addWidget(createNewKey("x")); tempHBoxLayout->addWidget(createNewKey("c")); tempHBoxLayout->addWidget(createNewKey("v")); tempHBoxLayout->addWidget(createNewKey("b")); tempHBoxLayout->addWidget(createNewKey("n")); tempHBoxLayout->addWidget(createNewKey("m")); tempHBoxLayout->addWidget(createNewKey("comma")); tempHBoxLayout->addWidget(createNewKey("period")); tempHBoxLayout->addWidget(createNewKey("slash")); tempHBoxLayout->addWidget(createNewKey("Shift_R")); tempVBoxLayout->addLayout(tempHBoxLayout); tempHBoxLayout = new QHBoxLayout(); tempHBoxLayout->setSpacing(0); tempHBoxLayout->addWidget(createNewKey("Control_L")); tempHBoxLayout->addWidget(createNewKey("Super_L")); tempHBoxLayout->addWidget(createNewKey("Alt_L")); tempHBoxLayout->addWidget(createNewKey("space")); tempHBoxLayout->addWidget(createNewKey("Alt_R")); tempHBoxLayout->addWidget(createNewKey("Menu")); tempHBoxLayout->addWidget(createNewKey("Control_R")); tempVBoxLayout->addLayout(tempHBoxLayout); tempVBoxLayout->setStretch(0, 1); tempVBoxLayout->setStretch(1, 2); tempVBoxLayout->setStretch(2, 1); tempVBoxLayout->setStretch(3, 1); finalVBoxLayout->addLayout(tempVBoxLayout); finalVBoxLayout->setStretch(0, 1); finalVBoxLayout->setStretch(1, 0); finalVBoxLayout->setStretch(2, 2); return finalVBoxLayout; } QVBoxLayout* VirtualKeyboardMouseWidget::setupAuxKeyboardLayout() { QHBoxLayout *tempHBoxLayout = new QHBoxLayout(); QVBoxLayout *tempVBoxLayout = new QVBoxLayout(); QGridLayout *tempGridLayout = new QGridLayout(); tempHBoxLayout->setSpacing(0); tempHBoxLayout->addWidget(createNewKey("Print")); tempHBoxLayout->addWidget(createNewKey("Scroll_Lock")); tempHBoxLayout->addWidget(createNewKey("Pause")); tempVBoxLayout->addLayout(tempHBoxLayout); tempVBoxLayout->addSpacerItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Fixed)); tempGridLayout->setSpacing(0); tempGridLayout->addWidget(createNewKey("Insert"), 1, 1, 1, 1); tempGridLayout->addWidget(createNewKey("Home"), 1, 2, 1, 1); tempGridLayout->addWidget(createNewKey("Prior"), 1, 3, 1, 1); tempGridLayout->addWidget(createNewKey("Delete"), 2, 1, 1, 1); tempGridLayout->addWidget(createNewKey("End"), 2, 2, 1, 1); tempGridLayout->addWidget(createNewKey("Next"), 2, 3, 1, 1); tempVBoxLayout->addLayout(tempGridLayout); tempVBoxLayout->addSpacerItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Fixed)); tempGridLayout = new QGridLayout(); tempGridLayout->setSpacing(0); tempGridLayout->addWidget(createNewKey("Up"), 1, 2, 1, 1); tempGridLayout->addWidget(createNewKey("Left"), 2, 1, 1, 1); tempGridLayout->addWidget(createNewKey("Down"), 2, 2, 1, 1); tempGridLayout->addWidget(createNewKey("Right"), 2, 3, 1, 1); tempVBoxLayout->addLayout(tempGridLayout); return tempVBoxLayout; } QVBoxLayout* VirtualKeyboardMouseWidget::setupKeyboardNumPadLayout() { QHBoxLayout *tempHBoxLayout = new QHBoxLayout(); QVBoxLayout *tempVBoxLayout = new QVBoxLayout(); QGridLayout *tempGridLayout = new QGridLayout(); QVBoxLayout *finalVBoxLayout = new QVBoxLayout(); QPushButton *othersKeysButton = createOtherKeysMenu(); //tempHBoxLayout->addWidget(othersKeysButton); //tempHBoxLayout->addWidget(noneButton); //finalVBoxLayout->addLayout(tempHBoxLayout); finalVBoxLayout->addWidget(noneButton); finalVBoxLayout->addWidget(othersKeysButton); finalVBoxLayout->setStretchFactor(noneButton, 1); finalVBoxLayout->setStretchFactor(othersKeysButton, 1); finalVBoxLayout->addSpacerItem(new QSpacerItem(0, 20, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding)); tempHBoxLayout = new QHBoxLayout(); tempHBoxLayout->setSpacing(0); tempHBoxLayout->addWidget(createNewKey("Num_Lock")); tempHBoxLayout->addWidget(createNewKey("KP_Divide")); tempHBoxLayout->addWidget(createNewKey("KP_Multiply")); tempHBoxLayout->addWidget(createNewKey("KP_Subtract")); tempVBoxLayout->addLayout(tempHBoxLayout); tempHBoxLayout = new QHBoxLayout(); tempHBoxLayout->setSpacing(0); tempGridLayout->addWidget(createNewKey("KP_7"), 1, 1, 1, 1); tempGridLayout->addWidget(createNewKey("KP_8"), 1, 2, 1, 1); tempGridLayout->addWidget(createNewKey("KP_9"), 1, 3, 1, 1); tempGridLayout->addWidget(createNewKey("KP_4"), 2, 1, 1, 1); tempGridLayout->addWidget(createNewKey("KP_5"), 2, 2, 1, 1); tempGridLayout->addWidget(createNewKey("KP_6"), 2, 3, 1, 1); tempHBoxLayout->addLayout(tempGridLayout); tempHBoxLayout->addWidget(createNewKey("KP_Add")); tempVBoxLayout->addLayout(tempHBoxLayout); tempHBoxLayout = new QHBoxLayout(); tempHBoxLayout->setSpacing(0); tempGridLayout = new QGridLayout(); tempGridLayout->setSpacing(0); tempGridLayout->addWidget(createNewKey("KP_1"), 1, 1, 1, 1); tempGridLayout->addWidget(createNewKey("KP_2"), 1, 2, 1, 1); tempGridLayout->addWidget(createNewKey("KP_3"), 1, 3, 1, 1); tempGridLayout->addWidget(createNewKey("KP_0"), 2, 1, 1, 2); tempGridLayout->addWidget(createNewKey("KP_Decimal"), 2, 3, 1, 1); tempHBoxLayout->addLayout(tempGridLayout); tempHBoxLayout->addWidget(createNewKey("KP_Enter")); tempVBoxLayout->addLayout(tempHBoxLayout); finalVBoxLayout->addLayout(tempVBoxLayout); finalVBoxLayout->setStretchFactor(tempVBoxLayout, 8); return finalVBoxLayout; } void VirtualKeyboardMouseWidget::setupMouseControlLayout() { QHBoxLayout *tempHBoxLayout = new QHBoxLayout(); QVBoxLayout *tempVBoxLayout = new QVBoxLayout(); QGridLayout *tempGridLayout = new QGridLayout(); QVBoxLayout *finalVBoxLayout = new QVBoxLayout(mouseTab); VirtualMousePushButton *pushButton = 0; QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); pushButton = new VirtualMousePushButton(tr("Left", "Mouse"), JoyButtonSlot::MouseLeft, JoyButtonSlot::JoyMouseMovement, this); pushButton->setSizePolicy(sizePolicy); pushButton->setMinimumHeight(50); tempVBoxLayout->addSpacerItem(new QSpacerItem(20, 50, QSizePolicy::Minimum, QSizePolicy::Expanding)); tempVBoxLayout->addWidget(pushButton); tempVBoxLayout->addSpacerItem(new QSpacerItem(20, 50, QSizePolicy::Minimum, QSizePolicy::Expanding)); tempHBoxLayout->addLayout(tempVBoxLayout); tempHBoxLayout->addSpacerItem(new QSpacerItem(10, 20, QSizePolicy::Fixed)); tempVBoxLayout = new QVBoxLayout(); pushButton = new VirtualMousePushButton(tr("Up", "Mouse"), JoyButtonSlot::MouseUp, JoyButtonSlot::JoyMouseMovement, this); pushButton->setSizePolicy(sizePolicy); pushButton->setMinimumHeight(50); tempVBoxLayout->addWidget(pushButton); tempVBoxLayout->addSpacerItem(new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Fixed)); QHBoxLayout *tempInnerHBoxLayout = new QHBoxLayout(); pushButton = new VirtualMousePushButton(tr("Left Button", "Mouse"), 1, JoyButtonSlot::JoyMouseButton, this); pushButton->setSizePolicy(sizePolicy); tempInnerHBoxLayout->addWidget(pushButton); pushButton = new VirtualMousePushButton(tr("Middle Button", "Mouse"), 2, JoyButtonSlot::JoyMouseButton, this); pushButton->setSizePolicy(sizePolicy); tempInnerHBoxLayout->addWidget(pushButton); pushButton = new VirtualMousePushButton(tr("Right Button", "Mouse"), 3, JoyButtonSlot::JoyMouseButton, this); pushButton->setSizePolicy(sizePolicy); tempInnerHBoxLayout->addWidget(pushButton); tempVBoxLayout->addLayout(tempInnerHBoxLayout); tempVBoxLayout->addSpacerItem(new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Fixed)); pushButton = new VirtualMousePushButton(tr("Wheel Up", "Mouse"), 4, JoyButtonSlot::JoyMouseButton, this); pushButton->setSizePolicy(sizePolicy); pushButton->setMinimumHeight(30); tempGridLayout->addWidget(pushButton, 1, 2, 1, 1); pushButton = new VirtualMousePushButton(tr("Wheel Left", "Mouse"), 6, JoyButtonSlot::JoyMouseButton, this); pushButton->setSizePolicy(sizePolicy); pushButton->setMinimumHeight(30); tempGridLayout->addWidget(pushButton, 2, 1, 1, 1); pushButton = new VirtualMousePushButton(tr("Wheel Right", "Mouse"), 7, JoyButtonSlot::JoyMouseButton, this); pushButton->setSizePolicy(sizePolicy); pushButton->setMinimumHeight(30); tempGridLayout->addWidget(pushButton, 2, 3, 1, 1); pushButton = new VirtualMousePushButton(tr("Wheel Down", "Mouse"), 5, JoyButtonSlot::JoyMouseButton, this); pushButton->setSizePolicy(sizePolicy); pushButton->setMinimumHeight(30); tempGridLayout->addWidget(pushButton, 3, 2, 1, 1); tempVBoxLayout->addLayout(tempGridLayout); tempVBoxLayout->addSpacerItem(new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Fixed)); pushButton = new VirtualMousePushButton(tr("Down", "Mouse"), JoyButtonSlot::MouseDown, JoyButtonSlot::JoyMouseMovement, this); pushButton->setSizePolicy(sizePolicy); pushButton->setMinimumHeight(50); tempVBoxLayout->addWidget(pushButton); tempVBoxLayout->setStretch(0, 1); tempVBoxLayout->setStretch(2, 1); tempVBoxLayout->setStretch(4, 3); tempVBoxLayout->setStretch(6, 1); tempHBoxLayout->addLayout(tempVBoxLayout); tempHBoxLayout->addSpacerItem(new QSpacerItem(10, 20, QSizePolicy::Fixed)); tempVBoxLayout = new QVBoxLayout(); tempVBoxLayout->addSpacerItem(new QSpacerItem(20, 50, QSizePolicy::Minimum, QSizePolicy::Expanding)); pushButton = new VirtualMousePushButton(tr("Right", "Mouse"), JoyButtonSlot::MouseRight, JoyButtonSlot::JoyMouseMovement, this); pushButton->setSizePolicy(sizePolicy); pushButton->setMinimumHeight(50); tempVBoxLayout->addWidget(pushButton); tempVBoxLayout->addSpacerItem(new QSpacerItem(20, 50, QSizePolicy::Minimum, QSizePolicy::Expanding)); tempHBoxLayout->addLayout(tempVBoxLayout); tempHBoxLayout->addSpacerItem(new QSpacerItem(10, 20, QSizePolicy::Fixed)); tempVBoxLayout = new QVBoxLayout(); tempVBoxLayout->setSpacing(20); #ifdef Q_OS_WIN pushButton = new VirtualMousePushButton(tr("Button 4", "Mouse"), 8, JoyButtonSlot::JoyMouseButton, this); #else pushButton = new VirtualMousePushButton(tr("Mouse 8", "Mouse"), 8, JoyButtonSlot::JoyMouseButton, this); #endif pushButton->setMinimumHeight(40); tempVBoxLayout->addWidget(pushButton); #ifdef Q_OS_WIN pushButton = new VirtualMousePushButton(tr("Button 5", "Mouse"), 9, JoyButtonSlot::JoyMouseButton, this); #else pushButton = new VirtualMousePushButton(tr("Mouse 9", "Mouse"), 9, JoyButtonSlot::JoyMouseButton, this); #endif pushButton->setMinimumHeight(40); tempVBoxLayout->addWidget(pushButton); tempVBoxLayout->addSpacerItem(new QSpacerItem(20, 50, QSizePolicy::Minimum, QSizePolicy::Expanding)); tempHBoxLayout->addLayout(tempVBoxLayout); tempHBoxLayout->addSpacerItem(new QSpacerItem(10, 20, QSizePolicy::Fixed)); tempVBoxLayout = new QVBoxLayout(); tempVBoxLayout->setSpacing(20); tempVBoxLayout->addSpacerItem(new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Expanding)); mouseSettingsPushButton = new QPushButton(tr("Mouse Settings"), this); mouseSettingsPushButton->setIcon(QIcon::fromTheme(QString::fromUtf8("edit-select"))); tempVBoxLayout->addWidget(mouseSettingsPushButton); tempHBoxLayout->addLayout(tempVBoxLayout); finalVBoxLayout->addLayout(tempHBoxLayout); } VirtualKeyPushButton* VirtualKeyboardMouseWidget::createNewKey(QString xcodestring) { int width = 30; int height = 30; QFont font1; font1.setPointSize(8); font1.setBold(true); VirtualKeyPushButton *pushButton = new VirtualKeyPushButton(button, xcodestring, this); if (xcodestring == "space") { width = 100; } else if (xcodestring == "Tab") { width = 40; } else if (xcodestring == "Shift_L" || xcodestring == "Shift_R") { width = 84; } else if (xcodestring == "Control_L") { width = 70; } else if (xcodestring == "Return") { width = 60; height = 60; pushButton->setMaximumWidth(100); } else if (xcodestring == "BackSpace") { width = 72; } else if (topRowKeys.contains(xcodestring)) { width = 30; height = 36; pushButton->setMaximumSize(100, 100); } else if (xcodestring == "Print" || xcodestring == "Scroll_Lock" || xcodestring == "Pause") { width = 40; height = 36; pushButton->setMaximumSize(100, 100); font1.setPointSize(6); } else if (xcodestring == "KP_Add" || xcodestring == "KP_Enter") { width = 34; font1.setPointSize(6); } else if (xcodestring == "Num_Lock") { font1.setPointSize(6); } else if (xcodestring.startsWith("KP_")) { width = 36; height = 32; } pushButton->setObjectName(xcodestring); pushButton->setMinimumSize(width, height); QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); pushButton->setSizePolicy(sizePolicy); pushButton->setFont(font1); return pushButton; } QPushButton* VirtualKeyboardMouseWidget::createNoneKey() { QPushButton *pushButton = new QPushButton(tr("NONE"), this); pushButton->setMinimumSize(0, 25); //pushButton->setMaximumHeight(100); QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); pushButton->setSizePolicy(sizePolicy); QFont font1; font1.setBold(true); pushButton->setFont(font1); return pushButton; } void VirtualKeyboardMouseWidget::processSingleKeyboardSelection(int keycode, unsigned int alias) { QMetaObject::invokeMethod(button, "clearSlotsEventReset"); //button->clearSlotsEventReset(); QMetaObject::invokeMethod(button, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, keycode), Q_ARG(unsigned int, alias), Q_ARG(int, 0), Q_ARG(JoyButtonSlot::JoySlotInputAction, JoyButtonSlot::JoyKeyboard)); //button->setAssignedSlot(keycode, alias); emit selectionFinished(); } void VirtualKeyboardMouseWidget::processAdvancedKeyboardSelection(int keycode, unsigned int alias) { emit selectionMade(keycode, alias); } void VirtualKeyboardMouseWidget::processSingleMouseSelection(JoyButtonSlot *tempslot) { QMetaObject::invokeMethod(button, "clearSlotsEventReset"); //button->clearSlotsEventReset(); QMetaObject::invokeMethod(button, "setAssignedSlot", Qt::BlockingQueuedConnection, Q_ARG(int, tempslot->getSlotCode()), Q_ARG(JoyButtonSlot::JoySlotInputAction, tempslot->getSlotMode())); //button->setAssignedSlot(tempslot->getSlotCode(), tempslot->getSlotMode()); emit selectionFinished(); } void VirtualKeyboardMouseWidget::processAdvancedMouseSelection(JoyButtonSlot *tempslot) { emit selectionMade(tempslot); } void VirtualKeyboardMouseWidget::populateTopRowKeys() { if (topRowKeys.isEmpty()) { topRowKeys.insert("Escape", "Escape"); topRowKeys.insert("F1", "F1"); topRowKeys.insert("F2", "F2"); topRowKeys.insert("F3", "F3"); topRowKeys.insert("F4", "F4"); topRowKeys.insert("F5", "F5"); topRowKeys.insert("F6", "F6"); topRowKeys.insert("F7", "F7"); topRowKeys.insert("F8", "F8"); topRowKeys.insert("F9", "F9"); topRowKeys.insert("F10", "F10"); topRowKeys.insert("F11", "F11"); topRowKeys.insert("F12", "F12"); } } void VirtualKeyboardMouseWidget::establishVirtualKeyboardSingleSignalConnections() { QList newlist = keyboardTab->findChildren (); QListIterator iter(newlist); while (iter.hasNext()) { VirtualKeyPushButton *keybutton = iter.next(); disconnect(keybutton, SIGNAL(keycodeObtained(int, unsigned int)), 0, 0); connect(keybutton, SIGNAL(keycodeObtained(int, unsigned int)), this, SLOT(processSingleKeyboardSelection(int, unsigned int))); } QListIterator iterActions(otherKeysMenu->actions()); while (iterActions.hasNext()) { QAction *temp = iterActions.next(); disconnect(temp, SIGNAL(triggered(bool)), 0, 0); connect(temp, SIGNAL(triggered(bool)), this, SLOT(otherKeysActionSingle(bool))); } disconnect(noneButton, SIGNAL(clicked()), 0, 0); connect(noneButton, SIGNAL(clicked()), this, SLOT(clearButtonSlotsFinish())); //qDebug() << "COUNT: " << newlist.count(); } void VirtualKeyboardMouseWidget::establishVirtualKeyboardAdvancedSignalConnections() { QList newlist = keyboardTab->findChildren (); QListIterator iter(newlist); while (iter.hasNext()) { VirtualKeyPushButton *keybutton = iter.next(); disconnect(keybutton, SIGNAL(keycodeObtained(int, unsigned int)), 0, 0); connect(keybutton, SIGNAL(keycodeObtained(int, unsigned int)), this, SLOT(processAdvancedKeyboardSelection(int, unsigned int))); } QListIterator iterActions(otherKeysMenu->actions()); while (iterActions.hasNext()) { QAction *temp = iterActions.next(); disconnect(temp, SIGNAL(triggered(bool)), 0, 0); connect(temp, SIGNAL(triggered(bool)), this, SLOT(otherKeysActionAdvanced(bool))); } disconnect(noneButton, SIGNAL(clicked()), 0, 0); connect(noneButton, SIGNAL(clicked()), this, SLOT(clearButtonSlots())); } void VirtualKeyboardMouseWidget::establishVirtualMouseSignalConnections() { QList newlist = mouseTab->findChildren(); QListIterator iter(newlist); while (iter.hasNext()) { VirtualMousePushButton *mousebutton = iter.next(); disconnect(mousebutton, SIGNAL(mouseSlotCreated(JoyButtonSlot*)), 0, 0); connect(mousebutton, SIGNAL(mouseSlotCreated(JoyButtonSlot*)), this, SLOT(processSingleMouseSelection(JoyButtonSlot*))); } } void VirtualKeyboardMouseWidget::establishVirtualMouseAdvancedSignalConnections() { QList newlist = mouseTab->findChildren(); QListIterator iter(newlist); while (iter.hasNext()) { VirtualMousePushButton *mousebutton = iter.next(); disconnect(mousebutton, SIGNAL(mouseSlotCreated(JoyButtonSlot*)), 0, 0); connect(mousebutton, SIGNAL(mouseSlotCreated(JoyButtonSlot*)), this, SLOT(processAdvancedMouseSelection(JoyButtonSlot*))); } } void VirtualKeyboardMouseWidget::clearButtonSlots() { QMetaObject::invokeMethod(button, "clearSlotsEventReset", Qt::BlockingQueuedConnection); //button->clearSlotsEventReset(); emit selectionCleared(); } void VirtualKeyboardMouseWidget::clearButtonSlotsFinish() { QMetaObject::invokeMethod(button, "clearSlotsEventReset", Qt::BlockingQueuedConnection); //button->clearSlotsEventReset(); emit selectionFinished(); } bool VirtualKeyboardMouseWidget::isKeyboardTabVisible() { return this->keyboardTab->isVisible(); } void VirtualKeyboardMouseWidget::openMouseSettingsDialog() { mouseSettingsPushButton->setEnabled(false); MouseButtonSettingsDialog *dialog = new MouseButtonSettingsDialog(this->button, this); dialog->show(); QDialog *parent = static_cast(this->parentWidget()); connect(parent, SIGNAL(finished(int)), dialog, SLOT(close())); connect(dialog, SIGNAL(finished(int)), this, SLOT(enableMouseSettingButton())); } void VirtualKeyboardMouseWidget::enableMouseSettingButton() { mouseSettingsPushButton->setEnabled(true); } void VirtualKeyboardMouseWidget::resizeEvent(QResizeEvent *event) { QTabWidget::resizeEvent(event); setButtonFontSizes(); } // Dynamically change font size of list of push button according to the // size of the buttons. void VirtualKeyboardMouseWidget::setButtonFontSizes() { //int tempWidgetFontSize = 20; QList buttonList = this->findChildren(); QListIterator iter(buttonList); while (iter.hasNext()) { VirtualKeyPushButton *temp = iter.next(); //widgetSizeMan = qMin(temp->calculateFontSize(), tempWidgetFontSize); QFont tempFont(temp->font()); tempFont.setPointSize(temp->calculateFontSize()); temp->setFont(tempFont); //temp->update(); } /*iter.toFront(); while (iter.hasNext()) { VirtualKeyPushButton *temp = iter.next(); QFont tempFont(temp->font()); tempFont.setPointSize(widgetSizeMan); temp->setFont(tempFont); } */ } QPushButton* VirtualKeyboardMouseWidget::createOtherKeysMenu() { QPushButton *otherKeysPushbutton = new QPushButton("Others", this); otherKeysPushbutton->setMinimumSize(0, 25); //fuckMotherFuck->setMaximumHeight(100); QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); otherKeysPushbutton->setSizePolicy(sizePolicy); QFont font1; font1.setBold(true); otherKeysPushbutton->setFont(font1); otherKeysMenu = new QMenu(this); QAction *tempAction = 0; unsigned int temp = 0; #ifdef Q_OS_WIN tempAction = new QAction(tr("Applications"), otherKeysMenu); temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Menu); tempAction->setData(temp); otherKeysMenu->addAction(tempAction); #endif tempAction = new QAction(tr("Browser Back"), otherKeysMenu); temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Back); tempAction->setData(temp); otherKeysMenu->addAction(tempAction); tempAction = new QAction(tr("Browser Favorites"), otherKeysMenu); temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Favorites); tempAction->setData(temp); otherKeysMenu->addAction(tempAction); tempAction = new QAction(tr("Browser Forward"), otherKeysMenu); temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Forward); tempAction->setData(temp); otherKeysMenu->addAction(tempAction); tempAction = new QAction(tr("Browser Home"), otherKeysMenu); temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_HomePage); tempAction->setData(temp); otherKeysMenu->addAction(tempAction); tempAction = new QAction(tr("Browser Refresh"), otherKeysMenu); temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Refresh); tempAction->setData(temp); otherKeysMenu->addAction(tempAction); tempAction = new QAction(tr("Browser Search"), otherKeysMenu); temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Search); tempAction->setData(temp); otherKeysMenu->addAction(tempAction); tempAction = new QAction(tr("Browser Stop"), otherKeysMenu); temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Stop); tempAction->setData(temp); otherKeysMenu->addAction(tempAction); tempAction = new QAction(tr("Calc"), otherKeysMenu); temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Launch1); tempAction->setData(temp); otherKeysMenu->addAction(tempAction); tempAction = new QAction(tr("Email"), otherKeysMenu); temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_LaunchMail); tempAction->setData(temp); otherKeysMenu->addAction(tempAction); tempAction = new QAction(tr("Media"), otherKeysMenu); temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_LaunchMedia); tempAction->setData(temp); otherKeysMenu->addAction(tempAction); tempAction = new QAction(tr("Media Next"), otherKeysMenu); temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_MediaNext); tempAction->setData(temp); otherKeysMenu->addAction(tempAction); tempAction = new QAction(tr("Media Play"), otherKeysMenu); temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_MediaPlay); tempAction->setData(temp); otherKeysMenu->addAction(tempAction); tempAction = new QAction(tr("Media Previous"), otherKeysMenu); temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_MediaPrevious); tempAction->setData(temp); otherKeysMenu->addAction(tempAction); tempAction = new QAction(tr("Media Stop"), otherKeysMenu); temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_MediaStop); tempAction->setData(temp); otherKeysMenu->addAction(tempAction); tempAction = new QAction(tr("Search"), otherKeysMenu); temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_Search); tempAction->setData(temp); otherKeysMenu->addAction(tempAction); tempAction = new QAction(tr("Volume Down"), otherKeysMenu); temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_VolumeDown); tempAction->setData(temp); otherKeysMenu->addAction(tempAction); tempAction = new QAction(tr("Volume Mute"), otherKeysMenu); temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_VolumeMute); tempAction->setData(temp); otherKeysMenu->addAction(tempAction); tempAction = new QAction(tr("Volume Up"), otherKeysMenu); temp = AntKeyMapper::getInstance()->returnVirtualKey(Qt::Key_VolumeUp); tempAction->setData(temp); otherKeysMenu->addAction(tempAction); otherKeysPushbutton->setMenu(otherKeysMenu); return otherKeysPushbutton; } void VirtualKeyboardMouseWidget::otherKeysActionSingle(bool triggered) { Q_UNUSED(triggered); QAction *tempAction = static_cast(sender()); unsigned int virtualkey = tempAction->data().toInt(); processSingleKeyboardSelection(virtualkey, AntKeyMapper::getInstance()->returnQtKey(virtualkey)); } void VirtualKeyboardMouseWidget::otherKeysActionAdvanced(bool triggered) { Q_UNUSED(triggered); QAction *tempAction = static_cast(sender()); unsigned int virtualkey = tempAction->data().toInt(); processAdvancedKeyboardSelection(virtualkey, AntKeyMapper::getInstance()->returnQtKey(virtualkey)); } antimicro-2.23/src/keyboard/virtualkeyboardmousewidget.h000066400000000000000000000064601300750276700236660ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef VIRTUALKEYBOARDMOUSEWIDGET_H #define VIRTUALKEYBOARDMOUSEWIDGET_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include "virtualkeypushbutton.h" #include "virtualmousepushbutton.h" #include #include class VirtualKeyboardMouseWidget : public QTabWidget { Q_OBJECT public: explicit VirtualKeyboardMouseWidget(JoyButton *button, QWidget *parent = 0); explicit VirtualKeyboardMouseWidget(QWidget *parent = 0); bool isKeyboardTabVisible(); protected: void setupVirtualKeyboardLayout(); QVBoxLayout* setupMainKeyboardLayout(); QVBoxLayout* setupAuxKeyboardLayout(); QVBoxLayout* setupKeyboardNumPadLayout(); void setupMouseControlLayout(); VirtualKeyPushButton* createNewKey(QString xcodestring); QPushButton* createNoneKey(); void populateTopRowKeys(); QPushButton* createOtherKeysMenu(); virtual void resizeEvent(QResizeEvent *event); JoyButton *button; QWidget *keyboardTab; QWidget *mouseTab; //QLabel *mouseHorizSpeedLabel; //QLabel *mouseVertSpeedLabel; //QSpinBox *mouseHorizSpeedSpinBox; //QSpinBox *mouseVertSpeedSpinBox; QPushButton *noneButton; QPushButton *mouseSettingsPushButton; //QCheckBox *mouseChangeTogether; //QComboBox *mouseModeComboBox; QMenu *otherKeysMenu; static QHash topRowKeys; signals: void selectionFinished(); void selectionCleared(); void selectionMade(int keycode, unsigned int alias); void selectionMade(JoyButtonSlot *slot); public slots: void establishVirtualKeyboardSingleSignalConnections(); void establishVirtualMouseSignalConnections(); void establishVirtualKeyboardAdvancedSignalConnections(); void establishVirtualMouseAdvancedSignalConnections(); private slots: void processSingleKeyboardSelection(int keycode, unsigned int alias); void processAdvancedKeyboardSelection(int keycode, unsigned int alias); void processSingleMouseSelection(JoyButtonSlot *tempslot); void processAdvancedMouseSelection(JoyButtonSlot *tempslot); void clearButtonSlots(); void clearButtonSlotsFinish(); void openMouseSettingsDialog(); void enableMouseSettingButton(); void setButtonFontSizes(); void otherKeysActionSingle(bool triggered); void otherKeysActionAdvanced(bool triggered); }; #endif // VIRTUALKEYBOARDMOUSEWIDGET_H antimicro-2.23/src/keyboard/virtualkeypushbutton.cpp000066400000000000000000000160401300750276700230630ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include "virtualkeypushbutton.h" #include #include #include QHash VirtualKeyPushButton::knownAliases = QHash (); VirtualKeyPushButton::VirtualKeyPushButton(JoyButton *button, QString xcodestring, QWidget *parent) : QPushButton(parent) { populateKnownAliases(); //qDebug() << "Question: " << X11KeySymToKeycode("KP_7") << endl; //qDebug() << "Question: " << X11KeySymToKeycode(79) << endl; this->keycode = 0; this->qkeyalias = 0; this->xcodestring = ""; this->displayString = ""; this->currentlyActive = false; this->onCurrentButton = false; this->button = button; int temp = 0; if (!xcodestring.isEmpty()) { temp = X11KeySymToKeycode(xcodestring); #ifdef Q_OS_UNIX BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); if (handler->getIdentifier() == "xtest") { temp = X11KeyCodeToX11KeySym(temp); } #endif } if (temp > 0) { #ifdef Q_OS_WIN //static QtWinKeyMapper nativeWinKeyMapper; BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); #ifdef WITH_VMULTI if (handler->getIdentifier() == "vmulti") { QtKeyMapperBase *nativeWinKeyMapper = AntKeyMapper::getInstance()->getNativeKeyMapper(); this->qkeyalias = nativeWinKeyMapper->returnQtKey(temp); this->keycode = AntKeyMapper::getInstance()->returnVirtualKey(qkeyalias); } #endif BACKEND_ELSE_IF (handler->getIdentifier() == "sendinput") { this->keycode = temp; this->qkeyalias = AntKeyMapper::getInstance()->returnQtKey(this->keycode); } // Special exception for Numpad Enter on Windows. if (xcodestring == "KP_Enter") { this->qkeyalias = Qt::Key_Enter; } #else this->keycode = temp; //this->keycode = X11KeyCodeToX11KeySym(temp); this->qkeyalias = AntKeyMapper::getInstance()->returnQtKey(this->keycode); //this->keycode = temp; #endif this->xcodestring = xcodestring; this->displayString = setDisplayString(xcodestring); } this->setText(this->displayString.replace("&", "&&")); connect(this, SIGNAL(clicked()), this, SLOT(processSingleSelection())); } void VirtualKeyPushButton::processSingleSelection() { emit keycodeObtained(keycode, qkeyalias); } QString VirtualKeyPushButton::setDisplayString(QString xcodestring) { QString temp; if (knownAliases.contains(xcodestring)) { temp = knownAliases.value(xcodestring); } else { temp = keycodeToKeyString(X11KeySymToKeycode(xcodestring)); //temp = keycodeToKeyString(X11KeySymToKeycode(xcodestring)); } if (temp.isEmpty() && !xcodestring.isEmpty()) { temp = xcodestring; } return temp.toUpper(); } // Define display strings that will be used for various keys on the // virtual keyboard. void VirtualKeyPushButton::populateKnownAliases() { if (knownAliases.isEmpty()) { knownAliases.insert("space", tr("Space")); knownAliases.insert("Tab", tr("Tab")); knownAliases.insert("Shift_L", tr("Shift (L)")); knownAliases.insert("Shift_R", tr("Shift (R)")); knownAliases.insert("Control_L", tr("Ctrl (L)")); knownAliases.insert("Control_R", tr("Ctrl (R)")); knownAliases.insert("Alt_L", tr("Alt (L)")); knownAliases.insert("Alt_R", tr("Alt (R)")); knownAliases.insert("Multi_key", tr("Alt (R)")); knownAliases.insert("grave", tr("`")); knownAliases.insert("asciitilde", tr("~")); knownAliases.insert("minus", tr("-")); knownAliases.insert("equal", tr("=")); knownAliases.insert("bracketleft", tr("[")); knownAliases.insert("bracketright", tr("]")); knownAliases.insert("backslash", tr("\\")); knownAliases.insert("Caps_Lock", tr("Caps")); knownAliases.insert("semicolon", tr(";")); knownAliases.insert("apostrophe", tr("'")); knownAliases.insert("comma", tr(",")); knownAliases.insert("period", tr(".")); knownAliases.insert("slash", tr("/")); knownAliases.insert("Escape", tr("ESC")); knownAliases.insert("Print", tr("PRTSC")); knownAliases.insert("Scroll_Lock", tr("SCLK")); knownAliases.insert("Insert", tr("INS")); knownAliases.insert("Prior", tr("PGUP")); knownAliases.insert("Delete", tr("DEL")); knownAliases.insert("Next", tr("PGDN")); knownAliases.insert("KP_1", tr("1")); knownAliases.insert("KP_2", tr("2")); knownAliases.insert("KP_3", tr("3")); knownAliases.insert("KP_4", tr("4")); knownAliases.insert("KP_5", tr("5")); knownAliases.insert("KP_6", tr("6")); knownAliases.insert("KP_7", tr("7")); knownAliases.insert("KP_8", tr("8")); knownAliases.insert("KP_9", tr("9")); knownAliases.insert("KP_0", tr("0")); knownAliases.insert("Num_Lock", tr("NUM\nLK")); knownAliases.insert("KP_Divide", tr("/")); knownAliases.insert("KP_Multiply", tr("*")); knownAliases.insert("KP_Subtract", tr("-")); knownAliases.insert("KP_Add", tr("+")); knownAliases.insert("KP_Enter", tr("E\nN\nT\nE\nR")); knownAliases.insert("KP_Decimal", tr(".")); knownAliases.insert("asterisk", tr("*")); knownAliases.insert("less", tr("<")); knownAliases.insert("colon", tr(":")); knownAliases.insert("Super_L", tr("Super (L)")); knownAliases.insert("Menu", tr("Menu")); knownAliases.insert("Up", tr("Up")); knownAliases.insert("Down", tr("Down")); knownAliases.insert("Left", tr("Left")); knownAliases.insert("Right", tr("Right")); } } int VirtualKeyPushButton::calculateFontSize() { QFont tempScaledFont(this->font()); tempScaledFont.setPointSize(10); QFontMetrics fm(tempScaledFont); while (((this->width()-4) < fm.boundingRect(this->rect(), Qt::AlignCenter, this->text()).width()) && tempScaledFont.pointSize() >= 6) { tempScaledFont.setPointSize(tempScaledFont.pointSize()-1); fm = QFontMetrics(tempScaledFont); } return tempScaledFont.pointSize(); } antimicro-2.23/src/keyboard/virtualkeypushbutton.h000066400000000000000000000030661300750276700225340ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef VIRTUALKEYPUSHBUTTON_H #define VIRTUALKEYPUSHBUTTON_H #include #include #include #include class VirtualKeyPushButton : public QPushButton { Q_OBJECT public: explicit VirtualKeyPushButton(JoyButton *button, QString xcodestring, QWidget *parent = 0); int calculateFontSize(); protected: int keycode; unsigned int qkeyalias; QString xcodestring; QString displayString; bool currentlyActive; bool onCurrentButton; JoyButton *button; static QHash knownAliases; QString setDisplayString(QString xcodestring); void populateKnownAliases(); signals: void keycodeObtained(int code, unsigned int alias); public slots: private slots: void processSingleSelection(); }; #endif // VIRTUALKEYPUSHBUTTON_H antimicro-2.23/src/keyboard/virtualmousepushbutton.cpp000066400000000000000000000043341300750276700234260ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "virtualmousepushbutton.h" VirtualMousePushButton::VirtualMousePushButton(QString displayText, int code, JoyButtonSlot::JoySlotInputAction mode, QWidget *parent) : QPushButton(parent) { if (mode == JoyButtonSlot::JoyMouseButton || mode == JoyButtonSlot::JoyMouseMovement) { this->setText(displayText); if (mode == JoyButtonSlot::JoyMouseMovement) { switch (code) { case JoyButtonSlot::MouseUp: case JoyButtonSlot::MouseDown: case JoyButtonSlot::MouseLeft: case JoyButtonSlot::MouseRight: { this->code = code; break; } default: { this->code = 0; break; } } } else { this->code = code; } this->mode = mode; } else { this->setText(tr("INVALID")); this->code = 0; this->mode = JoyButtonSlot::JoyMouseButton; } connect(this, SIGNAL(clicked()), this, SLOT(createTempSlot())); } unsigned int VirtualMousePushButton::getMouseCode() { return code; } JoyButtonSlot::JoySlotInputAction VirtualMousePushButton::getMouseMode() { return mode; } void VirtualMousePushButton::createTempSlot() { JoyButtonSlot *tempslot = new JoyButtonSlot(this->code, this->mode, this); emit mouseSlotCreated(tempslot); } antimicro-2.23/src/keyboard/virtualmousepushbutton.h000066400000000000000000000026171300750276700230750ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef VIRTUALMOUSEPUSHBUTTON_H #define VIRTUALMOUSEPUSHBUTTON_H #include #include #include class VirtualMousePushButton : public QPushButton { Q_OBJECT public: explicit VirtualMousePushButton(QString displayText, int code, JoyButtonSlot::JoySlotInputAction mode, QWidget *parent = 0); unsigned int getMouseCode(); JoyButtonSlot::JoySlotInputAction getMouseMode(); protected: unsigned int code; JoyButtonSlot::JoySlotInputAction mode; signals: void mouseSlotCreated(JoyButtonSlot *tempslot); public slots: private slots: void createTempSlot(); }; #endif // VIRTUALMOUSEPUSHBUTTON_H antimicro-2.23/src/localantimicroserver.cpp000066400000000000000000000037721300750276700211670ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "localantimicroserver.h" #include "common.h" LocalAntiMicroServer::LocalAntiMicroServer(QObject *parent) : QObject(parent) { localServer = new QLocalServer(this); } void LocalAntiMicroServer::startLocalServer() { QLocalServer::removeServer(PadderCommon::localSocketKey); localServer->setMaxPendingConnections(1); if (!localServer->listen(PadderCommon::localSocketKey)) { QTextStream errorstream(stderr); QString message("Could not start signal server. Profiles cannot be reloaded\n"); message.append("from command-line"); errorstream << tr(message.toStdString().c_str()) << endl; } else { connect(localServer, SIGNAL(newConnection()), this, SLOT(handleOutsideConnection())); } } void LocalAntiMicroServer::handleOutsideConnection() { QLocalSocket *socket = localServer->nextPendingConnection(); if (socket) { connect(socket, SIGNAL(disconnected()), this, SLOT(handleSocketDisconnect())); connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater())); } } void LocalAntiMicroServer::handleSocketDisconnect() { emit clientdisconnect(); } void LocalAntiMicroServer::close() { localServer->close(); } antimicro-2.23/src/localantimicroserver.h000066400000000000000000000023261300750276700206260ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef LOCALANTIMICROSERVER_H #define LOCALANTIMICROSERVER_H #include #include class LocalAntiMicroServer : public QObject { Q_OBJECT public: explicit LocalAntiMicroServer(QObject *parent = 0); protected: QLocalServer *localServer; signals: void clientdisconnect(); public slots: void startLocalServer(); void handleOutsideConnection(); void handleSocketDisconnect(); void close(); }; #endif // LOCALANTIMICROSERVER_H antimicro-2.23/src/logger.cpp000066400000000000000000000235211300750276700162110ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "logger.h" Logger* Logger::instance = 0; /** * @brief Outputs log messages to a given text stream. Client code * should determine whether it points to a console stream or * to a file. * @param Stream used to output text * @param Messages based of a given output level or lower will be logged * @param Parent object */ Logger::Logger(QTextStream *stream, LogLevel outputLevel, QObject *parent) : QObject(parent) { instance = this; instance->outputStream = stream; instance->outputLevel = outputLevel; instance->errorStream = 0; instance->pendingTimer.setInterval(1); instance->pendingTimer.setSingleShot(true); instance->writeTime = false; connect(instance, SIGNAL(pendingMessage()), instance, SLOT(startPendingTimer())); connect(&(instance->pendingTimer), SIGNAL(timeout()), instance, SLOT(Log())); } /** * @brief Outputs log messages to a given text stream. Client code * should determine whether it points to a console stream or * to a file. * @param Stream used to output standard text * @param Stream used to output error text * @param Messages based of a given output level or lower will be logged * @param Parent object */ Logger::Logger(QTextStream *stream, QTextStream *errorStream, LogLevel outputLevel, QObject *parent) : QObject(parent) { instance = this; instance->outputStream = stream; instance->outputLevel = outputLevel; instance->errorStream = errorStream; instance->pendingTimer.setInterval(1); instance->pendingTimer.setSingleShot(true); instance->writeTime = false; connect(instance, SIGNAL(pendingMessage()), instance, SLOT(startPendingTimer())); connect(&(instance->pendingTimer), SIGNAL(timeout()), instance, SLOT(Log())); } /** * @brief Close output stream and set instance to 0. */ Logger::~Logger() { closeLogger(); closeErrorLogger(); } /** * @brief Set the highest logging level. Determines which messages * are output to the output stream. * @param Highest log level utilized. */ void Logger::setLogLevel(LogLevel level) { Q_ASSERT(instance != 0); QMutexLocker locker(&instance->logMutex); Q_UNUSED(locker); instance->outputLevel = level; } /** * @brief Get the current output level associated with the logger. * @return Current output level */ Logger::LogLevel Logger::getCurrentLogLevel() { Q_ASSERT(instance != 0); return instance->outputLevel; } void Logger::setCurrentStream(QTextStream *stream) { Q_ASSERT(instance != 0); QMutexLocker locker(&instance->logMutex); Q_UNUSED(locker); instance->outputStream->flush(); instance->outputStream = stream; } QTextStream* Logger::getCurrentStream() { Q_ASSERT(instance != 0); return instance->outputStream; } void Logger::setCurrentErrorStream(QTextStream *stream) { Q_ASSERT(instance != 0); QMutexLocker locker(&instance->logMutex); Q_UNUSED(locker); if (instance->errorStream) { instance->errorStream->flush(); } instance->errorStream = stream; } QTextStream* Logger::getCurrentErrorStream() { Q_ASSERT(instance != 0); return instance->errorStream; } /** * @brief Go through a list of pending messages and check if message should be * logged according to the set log level. Log the message to the output * stream. * @param Log level * @param String to write to output stream if appropriate to the current * log level. */ void Logger::Log() { QMutexLocker locker(&logMutex); Q_UNUSED(locker); QListIterator iter(pendingMessages); while (iter.hasNext()) { LogMessage pendingMessage = iter.next(); logMessage(pendingMessage); } pendingMessages.clear(); instance->pendingTimer.stop(); } /** * @brief Flushes output stream and closes stream if requested. * @param Whether to close the current stream. Defaults to true. */ void Logger::closeLogger(bool closeStream) { if (outputStream) { outputStream->flush(); if (closeStream && outputStream->device() != 0) { QIODevice *device = outputStream->device(); if (device->isOpen()) { device->close(); } } } } /** * @brief Flushes output stream and closes stream if requested. * @param Whether to close the current stream. Defaults to true. */ void Logger::closeErrorLogger(bool closeStream) { if (errorStream) { errorStream->flush(); if (closeStream && errorStream->device() != 0) { QIODevice *device = errorStream->device(); if (device->isOpen()) { device->close(); } } } instance->pendingTimer.stop(); instance = 0; } /** * @brief Append message to list of messages that might get placed in the * log. Messages will be written later. * @param Log level * @param String to write to output stream if appropriate to the current * log level. * @param Whether the logger should add a newline to the end of the message. */ void Logger::appendLog(LogLevel level, const QString &message, bool newline) { Q_ASSERT(instance != 0); QMutexLocker locker(&instance->logMutex); Q_UNUSED(locker); LogMessage temp; temp.level = level; temp.message = QString(message); temp.newline = newline; instance->pendingMessages.append(temp); /*if (!instance->pendingTimer.isActive()) { instance->pendingTimer.start(); } */ emit instance->pendingMessage(); } /** * @brief Immediately write a message to a text stream. * @param Log level * @param String to write to output stream if appropriate to the current * log level. * @param Whether the logger should add a newline to the end of the message. */ void Logger::directLog(LogLevel level, const QString &message, bool newline) { Q_ASSERT(instance != 0); QMutexLocker locker(&instance->logMutex); Q_UNUSED(locker); LogMessage temp; temp.level = level; temp.message = QString(message); temp.newline = newline; instance->logMessage(temp); } /** * @brief Write an individual message to the text stream. * @param LogMessage instance for a single message */ void Logger::logMessage(LogMessage msg) { LogLevel level = msg.level; QString message = msg.message; bool newline = msg.newline; if (outputLevel != LOG_NONE && level <= outputLevel) { QString displayTime = ""; QString initialPrefix = ""; QString finalMessage; if (outputLevel > LOG_INFO || writeTime) { displayTime = QString("[%1] - ").arg(QTime::currentTime().toString("hh:mm:ss.zzz")); initialPrefix = displayTime; } QTextStream *writeStream = outputStream; if (level < LOG_INFO && errorStream) { writeStream = errorStream; } finalMessage.append(initialPrefix).append(message); //*writeStream << initialPrefix << message; if (newline) { finalMessage.append("\n"); //*writeStream << endl; } *writeStream << finalMessage; writeStream->flush(); emit stringWritten(finalMessage); } } /** * @brief Get the associated timer used by the logger. * @return QTimer instance */ QTimer* Logger::getLogTimer() { return &pendingTimer; } /** * @brief Stop the logger's timer if it is currently active. */ void Logger::stopLogTimer() { if (pendingTimer.isActive()) { pendingTimer.stop(); } } /** * @brief Set whether the current time should be written with a message. * This property is only used if outputLevel is set to LOG_INFO. * @param status */ void Logger::setWriteTime(bool status) { Q_ASSERT(instance != 0); QMutexLocker locker(&instance->logMutex); Q_UNUSED(locker); writeTime = status; } /** * @brief Get whether the current time should be written with a LOG_INFO * message. * @return Whether the current time is written with a LOG_INFO message */ bool Logger::getWriteTime() { Q_ASSERT(instance != 0); return writeTime; } void Logger::startPendingTimer() { Q_ASSERT(instance != 0); if (!instance->pendingTimer.isActive()) { instance->pendingTimer.start(); } } void Logger::setCurrentLogFile(QString filename) { Q_ASSERT(instance != 0); if( instance->outputFile.isOpen() ) { instance->closeLogger(true); } instance->outputFile.setFileName( filename ); instance->outputFile.open( QIODevice::WriteOnly | QIODevice::Append ); instance->outFileStream.setDevice( &instance->outputFile ); instance->setCurrentStream( &instance->outFileStream ); instance->LogInfo(QObject::tr("Logging started"), true, true); } void Logger::setCurrentErrorLogFile(QString filename) { Q_ASSERT(instance != 0); if( instance->errorFile.isOpen() ) { instance->closeErrorLogger(true); } instance->errorFile.setFileName( filename ); instance->errorFile.open( QIODevice::WriteOnly | QIODevice::Append ); instance->outErrorFileStream.setDevice( &instance->errorFile ); instance->setCurrentErrorStream( &instance->outErrorFileStream ); } antimicro-2.23/src/logger.h000066400000000000000000000103171300750276700156550ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef LOGGER_H #define LOGGER_H #include #include #include #include #include #include #include class Logger : public QObject { Q_OBJECT public: enum LogLevel { LOG_NONE = 0, LOG_ERROR, LOG_WARNING, LOG_INFO, LOG_DEBUG, LOG_MAX = LOG_DEBUG }; typedef struct { LogLevel level; QString message; bool newline; } LogMessage; explicit Logger(QTextStream *stream, LogLevel outputLevel = LOG_INFO, QObject *parent = 0); explicit Logger(QTextStream *stream, QTextStream *errorStream, LogLevel outputLevel = LOG_INFO, QObject *parent = 0); ~Logger(); static void setLogLevel(LogLevel level); LogLevel getCurrentLogLevel(); static void setCurrentStream(QTextStream *stream); static void setCurrentLogFile(QString filename); static QTextStream* getCurrentStream(); static void setCurrentErrorStream(QTextStream *stream); static void setCurrentErrorLogFile(QString filename); static QTextStream* getCurrentErrorStream(); QTimer* getLogTimer(); void stopLogTimer(); bool getWriteTime(); void setWriteTime(bool status); static void appendLog(LogLevel level, const QString &message, bool newline=true); static void directLog(LogLevel level, const QString &message, bool newline=true); // Some convenience functions that will hopefully speed up // logging operations. inline static void LogInfo(const QString &message, bool newline=true, bool direct=false) { if (!direct) { appendLog(LOG_INFO, message, newline); } else { directLog(LOG_INFO, message, newline); } //Log(LOG_INFO, message, newline); } inline static void LogDebug(const QString &message, bool newline=true, bool direct=false) { if (!direct) { appendLog(LOG_DEBUG, message, newline); } else { directLog(LOG_DEBUG, message, newline); } //Log(LOG_DEBUG, message, newline); } inline static void LogWarning(const QString &message, bool newline=true, bool direct=false) { if (!direct) { appendLog(LOG_WARNING, message, newline); } else { directLog(LOG_WARNING, message, newline); } //Log(LOG_WARNING, message, newline); } inline static void LogError(const QString &message, bool newline=true, bool direct=false) { if (!direct) { appendLog(LOG_ERROR, message, newline); } else { directLog(LOG_ERROR, message, newline); } //Log(LOG_ERROR, message, newline); } inline static Logger* getInstance() { Q_ASSERT(instance != NULL); return instance; } protected: void closeLogger(bool closeStream=true); void closeErrorLogger(bool closeStream=true); void logMessage(LogMessage msg); QFile outputFile; QTextStream outFileStream; QTextStream *outputStream; QFile errorFile; QTextStream outErrorFileStream; QTextStream *errorStream; LogLevel outputLevel; QMutex logMutex; QTimer pendingTimer; QList pendingMessages; bool writeTime; static Logger *instance; signals: void stringWritten(QString text); void pendingMessage(); public slots: void Log(); void startPendingTimer(); }; #endif // LOGGER_H antimicro-2.23/src/main.cpp000066400000000000000000000577511300750276700156720ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #ifdef Q_OS_WIN #ifdef USE_SDL_2 #include #else #include #endif #undef main #endif #include #include #include #include #include //#include #include #include #include #include #include #include #ifdef Q_OS_WIN #include #include #include "winextras.h" #endif #include "inputdevice.h" #include "joybuttonslot.h" #include "inputdaemon.h" #include "common.h" #include "commandlineutility.h" #include "mainwindow.h" #include "autoprofileinfo.h" #include "localantimicroserver.h" #include "antimicrosettings.h" #include "applaunchhelper.h" #include "eventhandlerfactory.h" #ifndef Q_OS_WIN #include #include #include #include #ifdef WITH_X11 #include "x11extras.h" #endif #endif #include "antkeymapper.h" #include "logger.h" #ifndef Q_OS_WIN static void termSignalTermHandler(int signal) { Q_UNUSED(signal); qApp->exit(0); } static void termSignalIntHandler(int signal) { Q_UNUSED(signal); qApp->exit(0); } #endif void deleteInputDevices(QMap *joysticks) { QMapIterator iter(*joysticks); while (iter.hasNext()) { InputDevice *joystick = iter.next().value(); if (joystick) { delete joystick; joystick = 0; } } joysticks->clear(); } int main(int argc, char *argv[]) { qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType("SDL_JoystickID"); qRegisterMetaType("JoyButtonSlot::JoySlotInputAction"); #if defined(Q_OS_UNIX) && defined(WITH_X11) #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif XInitThreads(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #endif QFile logFile; QTextStream logFileStream; QTextStream outstream(stdout); QTextStream errorstream(stderr); // If running Win version, check if an explicit style // was defined on the command-line. If so, make a note // of it. #ifdef Q_OS_WIN bool styleChangeFound = false; for (int i=0; i < argc && !styleChangeFound; i++) { char *tempchrstr = argv[i]; QString temp = QString::fromUtf8(tempchrstr); if (temp == "-style") { styleChangeFound = true; } } #endif CommandLineUtility cmdutility; QStringList cmdarguments = PadderCommon::arguments(argc, argv); cmdarguments.removeFirst(); cmdutility.parseArguments(cmdarguments); Logger appLogger(&outstream, &errorstream); if (cmdutility.hasError()) { appLogger.LogError(cmdutility.getErrorText(), true, true); return 1; } else if (cmdutility.isHelpRequested()) { appLogger.LogInfo(cmdutility.generateHelpString(), false, true); return 0; } else if (cmdutility.isVersionRequested()) { appLogger.LogInfo(cmdutility.generateVersionString(), true, true); return 0; } // If a log level wasn't specified at the command-line, then use a default. if( cmdutility.getCurrentLogLevel() == Logger::LOG_NONE ) { appLogger.setLogLevel( Logger::LOG_WARNING ); } else if (cmdutility.getCurrentLogLevel() != appLogger.getCurrentLogLevel()) { appLogger.setLogLevel(cmdutility.getCurrentLogLevel()); } if( !cmdutility.getCurrentLogFile().isEmpty() ) { appLogger.setCurrentLogFile( cmdutility.getCurrentLogFile() ); appLogger.setCurrentErrorStream(NULL); } Q_INIT_RESOURCE(resources); QApplication a(argc, argv); #if defined(Q_OS_WIN) && defined(WIN_PORTABLE_PACKAGE) // If in portable mode, make sure the current directory is the same as the // config directory. This is to ensure that all relative paths resolve // correctly when loading on startup. QDir::setCurrent( PadderCommon::configPath() ); #endif QDir configDir(PadderCommon::configPath()); if (!configDir.exists()) { configDir.mkpath(PadderCommon::configPath()); } QMap *joysticks = new QMap(); QThread *inputEventThread = 0; // Cross-platform way of performing IPC. Currently, // only establish a connection and then disconnect. // In the future, there might be a reason to actually send // messages to the QLocalServer. QLocalSocket socket; socket.connectToServer(PadderCommon::localSocketKey); socket.waitForConnected(1000); if (socket.state() == QLocalSocket::ConnectedState) { // An instance of this program is already running. // Save app config and exit. AntiMicroSettings settings(PadderCommon::configFilePath(), QSettings::IniFormat); // Update log info based on config values if( cmdutility.getCurrentLogLevel() == Logger::LOG_NONE && settings.contains("LogLevel")) { appLogger.setLogLevel( (Logger::LogLevel) settings.value("LogLevel").toInt() ); } if( cmdutility.getCurrentLogFile().isEmpty() && settings.contains("LogFile")) { appLogger.setCurrentLogFile( settings.value("LogFile").toString() ); appLogger.setCurrentErrorStream(NULL); } InputDaemon *joypad_worker = new InputDaemon(joysticks, &settings, false); MainWindow w(joysticks, &cmdutility, &settings, false); w.fillButtons(); w.alterConfigFromSettings(); if (!cmdutility.hasError() && (cmdutility.hasProfile() || cmdutility.hasProfileInOptions())) { w.saveAppConfig(); } else if (!cmdutility.hasError() && cmdutility.isUnloadRequested()) { w.saveAppConfig(); } w.removeJoyTabs(); QObject::connect(&a, SIGNAL(aboutToQuit()), joypad_worker, SLOT(quit())); QTimer::singleShot(50, &a, SLOT(quit())); int result = a.exec(); settings.sync(); socket.disconnectFromServer(); deleteInputDevices(joysticks); delete joysticks; joysticks = 0; delete joypad_worker; joypad_worker = 0; return result; } LocalAntiMicroServer *localServer = 0; #ifndef Q_OS_WIN if (cmdutility.launchAsDaemon()) { pid_t pid, sid; //Fork the Parent Process pid = fork(); if (pid == 0) { appLogger.LogInfo(QObject::tr("Daemon launched"), true, true); localServer = new LocalAntiMicroServer(); localServer->startLocalServer(); } else if (pid < 0) { appLogger.LogError(QObject::tr("Failed to launch daemon"), true, true); deleteInputDevices(joysticks); delete joysticks; joysticks = 0; exit(EXIT_FAILURE); } //We got a good pid, Close the Parent Process else if (pid > 0) { appLogger.LogInfo(QObject::tr("Launching daemon"), true, true); deleteInputDevices(joysticks); delete joysticks; joysticks = 0; exit(EXIT_SUCCESS); } #ifdef WITH_X11 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif if (cmdutility.getDisplayString().isEmpty()) { X11Extras::getInstance()->syncDisplay(); } else { X11Extras::setCustomDisplay(cmdutility.getDisplayString()); X11Extras::getInstance()->syncDisplay(); if (X11Extras::getInstance()->display() == NULL) { appLogger.LogError(QObject::tr("Display string \"%1\" is not valid.") .arg(cmdutility.getDisplayString()), true, true); //errorstream << QObject::tr("Display string \"%1\" is not valid.").arg(cmdutility.getDisplayString()) << endl; deleteInputDevices(joysticks); delete joysticks; joysticks = 0; delete localServer; localServer = 0; X11Extras::getInstance()->closeDisplay(); exit(EXIT_FAILURE); } } #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #endif //Change File Mask umask(0); //Create a new Signature Id for our child sid = setsid(); if (sid < 0) { appLogger.LogError(QObject::tr("Failed to set a signature id for the daemon"), true, true); //errorstream << QObject::tr("Failed to set a signature id for the daemon") << endl; deleteInputDevices(joysticks); delete joysticks; joysticks = 0; delete localServer; localServer = 0; #ifdef WITH_X11 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif X11Extras::getInstance()->closeDisplay(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #endif exit(EXIT_FAILURE); } if ((chdir("/")) < 0) { appLogger.LogError(QObject::tr("Failed to change working directory to /"), true, true); deleteInputDevices(joysticks); delete joysticks; joysticks = 0; delete localServer; localServer = 0; #ifdef WITH_X11 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif X11Extras::getInstance()->closeDisplay(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #endif exit(EXIT_FAILURE); } //Close Standard File Descriptors close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); } else { localServer = new LocalAntiMicroServer(); localServer->startLocalServer(); #ifdef WITH_X11 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif if (!cmdutility.getDisplayString().isEmpty()) { X11Extras::getInstance()->syncDisplay(cmdutility.getDisplayString()); if (X11Extras::getInstance()->display() == NULL) { appLogger.LogError(QObject::tr("Display string \"%1\" is not valid.") .arg(cmdutility.getDisplayString()), true, true); deleteInputDevices(joysticks); delete joysticks; joysticks = 0; delete localServer; localServer = 0; X11Extras::getInstance()->closeDisplay(); exit(EXIT_FAILURE); } } #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #endif } #else localServer = new LocalAntiMicroServer(); localServer->startLocalServer(); #endif a.setQuitOnLastWindowClosed(false); //QString defaultStyleName = qApp->style()->objectName(); // If running Win version and no explicit style was // defined, use the style Fusion by default. I find the // windowsvista style a tad ugly #ifdef Q_OS_WIN if (!styleChangeFound) { qApp->setStyle(QStyleFactory::create("Fusion")); } QIcon::setThemeName("/"); #endif AntiMicroSettings *settings = new AntiMicroSettings(PadderCommon::configFilePath(), QSettings::IniFormat); settings->importFromCommandLine(cmdutility); // Update log info based on config values if( cmdutility.getCurrentLogLevel() == Logger::LOG_NONE && settings->contains("LogLevel")) { appLogger.setLogLevel( (Logger::LogLevel)settings->value("LogLevel").toInt() ); } if( cmdutility.getCurrentLogFile().isEmpty() && settings->contains("LogFile")) { appLogger.setCurrentLogFile( settings->value("LogFile").toString() ); appLogger.setCurrentErrorStream(NULL); } QString targetLang = QLocale::system().name(); if (settings->contains("Language")) { targetLang = settings->value("Language").toString(); } QTranslator qtTranslator; #if defined(Q_OS_UNIX) qtTranslator.load(QString("qt_").append(targetLang), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); #elif defined(Q_OS_WIN) #ifdef QT_DEBUG qtTranslator.load(QString("qt_").append(targetLang), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); #else qtTranslator.load(QString("qt_").append(targetLang), QApplication::applicationDirPath().append("\\share\\qt\\translations")); #endif #endif a.installTranslator(&qtTranslator); QTranslator myappTranslator; #if defined(Q_OS_UNIX) myappTranslator.load(QString("antimicro_").append(targetLang), QApplication::applicationDirPath().append("/../share/antimicro/translations")); #elif defined(Q_OS_WIN) myappTranslator.load(QString("antimicro_").append(targetLang), QApplication::applicationDirPath().append("\\share\\antimicro\\translations")); #endif a.installTranslator(&myappTranslator); #ifndef Q_OS_WIN // Have program handle SIGTERM struct sigaction termaction; termaction.sa_handler = &termSignalTermHandler; sigemptyset(&termaction.sa_mask); termaction.sa_flags = 0; sigaction(SIGTERM, &termaction, 0); // Have program handle SIGINT struct sigaction termint; termint.sa_handler = &termSignalIntHandler; sigemptyset(&termint.sa_mask); termint.sa_flags = 0; sigaction(SIGINT, &termint, 0); #endif if (cmdutility.shouldListControllers()) { InputDaemon *joypad_worker = new InputDaemon(joysticks, settings, false); AppLaunchHelper mainAppHelper(settings, false); mainAppHelper.printControllerList(joysticks); joypad_worker->quit(); joypad_worker->deleteJoysticks(); delete joysticks; joysticks = 0; delete joypad_worker; joypad_worker = 0; delete localServer; localServer = 0; #ifdef WITH_X11 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif X11Extras::getInstance()->closeDisplay(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #endif return 0; } #ifdef USE_SDL_2 else if (cmdutility.shouldMapController()) { PadderCommon::mouseHelperObj.initDeskWid(); InputDaemon *joypad_worker = new InputDaemon(joysticks, settings); inputEventThread = new QThread(); MainWindow *w = new MainWindow(joysticks, &cmdutility, settings); QObject::connect(&a, SIGNAL(aboutToQuit()), w, SLOT(removeJoyTabs())); QObject::connect(&a, SIGNAL(aboutToQuit()), joypad_worker, SLOT(quit())); QObject::connect(&a, SIGNAL(aboutToQuit()), joypad_worker, SLOT(deleteJoysticks()), Qt::BlockingQueuedConnection); QObject::connect(&a, SIGNAL(aboutToQuit()), &PadderCommon::mouseHelperObj, SLOT(deleteDeskWid()), Qt::DirectConnection); QObject::connect(&a, SIGNAL(aboutToQuit()), joypad_worker, SLOT(deleteLater()), Qt::BlockingQueuedConnection); //JoyButton::establishMouseTimerConnections(); w->makeJoystickTabs(); QTimer::singleShot(0, w, SLOT(controllerMapOpening())); joypad_worker->startWorker(); joypad_worker->moveToThread(inputEventThread); PadderCommon::mouseHelperObj.moveToThread(inputEventThread); inputEventThread->start(QThread::HighPriority); int app_result = a.exec(); // Log any remaining messages if they exist. appLogger.Log(); inputEventThread->quit(); inputEventThread->wait(); delete joysticks; joysticks = 0; //delete joypad_worker; joypad_worker = 0; delete localServer; localServer = 0; delete inputEventThread; inputEventThread = 0; #ifdef WITH_X11 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif X11Extras::getInstance()->closeDisplay(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #endif delete w; w = 0; return app_result; } #endif bool status = true; QString eventGeneratorIdentifier; AntKeyMapper *keyMapper = 0; EventHandlerFactory *factory = EventHandlerFactory::getInstance(cmdutility.getEventGenerator()); if (!factory) { status = false; } else { eventGeneratorIdentifier = factory->handler()->getIdentifier(); keyMapper = AntKeyMapper::getInstance(eventGeneratorIdentifier); status = factory->handler()->init(); factory->handler()->printPostMessages(); } #if (defined(Q_OS_UNIX) && defined(WITH_UINPUT) && defined(WITH_XTEST)) || \ defined(Q_OS_WIN) // Use fallback event handler. if (!status && cmdutility.getEventGenerator() != EventHandlerFactory::fallBackIdentifier()) { QString eventDisplayName = EventHandlerFactory::handlerDisplayName( EventHandlerFactory::fallBackIdentifier()); appLogger.LogInfo(QObject::tr("Attempting to use fallback option %1 for event generation.") .arg(eventDisplayName)); if (keyMapper) { keyMapper->deleteInstance(); keyMapper = 0; } factory->deleteInstance(); factory = EventHandlerFactory::getInstance(EventHandlerFactory::fallBackIdentifier()); if (!factory) { status = false; } else { eventGeneratorIdentifier = factory->handler()->getIdentifier(); keyMapper = AntKeyMapper::getInstance(eventGeneratorIdentifier); status = factory->handler()->init(); factory->handler()->printPostMessages(); } } #endif if (!status) { appLogger.LogError(QObject::tr("Failed to open event generator. Exiting.")); appLogger.Log(); deleteInputDevices(joysticks); delete joysticks; joysticks = 0; delete localServer; localServer = 0; if (keyMapper) { keyMapper->deleteInstance(); keyMapper = 0; } #if defined(Q_OS_UNIX) && defined(WITH_X11) #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif X11Extras::getInstance()->closeDisplay(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #endif return EXIT_FAILURE; } else { appLogger.LogInfo(QObject::tr("Using %1 as the event generator.") .arg(factory->handler()->getName())); } PadderCommon::mouseHelperObj.initDeskWid(); InputDaemon *joypad_worker = new InputDaemon(joysticks, settings); inputEventThread = new QThread(); MainWindow *w = new MainWindow(joysticks, &cmdutility, settings); w->setAppTranslator(&qtTranslator); w->setTranslator(&myappTranslator); AppLaunchHelper mainAppHelper(settings, w->getGraphicalStatus()); QObject::connect(w, SIGNAL(joystickRefreshRequested()), joypad_worker, SLOT(refresh())); QObject::connect(joypad_worker, SIGNAL(joystickRefreshed(InputDevice*)), w, SLOT(fillButtons(InputDevice*))); QObject::connect(joypad_worker, SIGNAL(joysticksRefreshed(QMap*)), w, SLOT(fillButtons(QMap*))); QObject::connect(&a, SIGNAL(aboutToQuit()), localServer, SLOT(close())); QObject::connect(&a, SIGNAL(aboutToQuit()), w, SLOT(saveAppConfig())); QObject::connect(&a, SIGNAL(aboutToQuit()), w, SLOT(removeJoyTabs())); QObject::connect(&a, SIGNAL(aboutToQuit()), &mainAppHelper, SLOT(revertMouseThread())); QObject::connect(&a, SIGNAL(aboutToQuit()), joypad_worker, SLOT(quit())); QObject::connect(&a, SIGNAL(aboutToQuit()), joypad_worker, SLOT(deleteJoysticks())); QObject::connect(&a, SIGNAL(aboutToQuit()), joypad_worker, SLOT(deleteLater())); QObject::connect(&a, SIGNAL(aboutToQuit()), &PadderCommon::mouseHelperObj, SLOT(deleteDeskWid()), Qt::DirectConnection); #ifdef Q_OS_WIN QObject::connect(&a, SIGNAL(aboutToQuit()), &mainAppHelper, SLOT(appQuitPointerPrecision())); #endif QObject::connect(localServer, SIGNAL(clientdisconnect()), w, SLOT(handleInstanceDisconnect())); #ifdef USE_SDL_2 QObject::connect(w, SIGNAL(mappingUpdated(QString,InputDevice*)), joypad_worker, SLOT(refreshMapping(QString,InputDevice*))); QObject::connect(joypad_worker, SIGNAL(deviceUpdated(int,InputDevice*)), w, SLOT(testMappingUpdateNow(int,InputDevice*))); QObject::connect(joypad_worker, SIGNAL(deviceRemoved(SDL_JoystickID)), w, SLOT(removeJoyTab(SDL_JoystickID))); QObject::connect(joypad_worker, SIGNAL(deviceAdded(InputDevice*)), w, SLOT(addJoyTab(InputDevice*))); #endif #ifdef Q_OS_WIN // Raise process priority. Helps reduce timer delays caused by // the running of other processes. bool raisedPriority = WinExtras::raiseProcessPriority(); if (!raisedPriority) { appLogger.LogInfo(QObject::tr("Could not raise process priority.")); } #endif mainAppHelper.initRunMethods(); QTimer::singleShot(0, w, SLOT(fillButtons())); QTimer::singleShot(0, w, SLOT(alterConfigFromSettings())); QTimer::singleShot(0, w, SLOT(changeWindowStatus())); mainAppHelper.changeMouseThread(inputEventThread); joypad_worker->startWorker(); joypad_worker->moveToThread(inputEventThread); PadderCommon::mouseHelperObj.moveToThread(inputEventThread); inputEventThread->start(QThread::HighPriority); int app_result = a.exec(); // Log any remaining messages if they exist. appLogger.Log(); appLogger.LogInfo(QObject::tr("Quitting Program"), true, true); joypad_worker = 0; delete localServer; localServer = 0; inputEventThread->quit(); inputEventThread->wait(); delete inputEventThread; inputEventThread = 0; delete joysticks; joysticks = 0; AntKeyMapper::getInstance()->deleteInstance(); #if defined(Q_OS_UNIX) && defined(WITH_X11) #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif X11Extras::getInstance()->closeDisplay(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #endif EventHandlerFactory::getInstance()->handler()->cleanup(); EventHandlerFactory::getInstance()->deleteInstance(); delete w; w = 0; delete settings; settings = 0; return app_result; } antimicro-2.23/src/mainsettingsdialog.cpp000066400000000000000000002107061300750276700206220ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN #include #endif #ifdef Q_OS_UNIX #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include #endif #include "eventhandlerfactory.h" #endif #include "mainsettingsdialog.h" #include "ui_mainsettingsdialog.h" #include "addeditautoprofiledialog.h" #include "editalldefaultautoprofiledialog.h" #include "common.h" #ifdef Q_OS_WIN #include "eventhandlerfactory.h" #include "winextras.h" #elif defined(Q_OS_UNIX) #include "x11extras.h" #endif static const QString RUNATSTARTUPREGKEY( "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"); static const QString RUNATSTARTUPLOCATION( QString("%0\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\antimicro.lnk") .arg(QString::fromUtf8(qgetenv("AppData")))); MainSettingsDialog::MainSettingsDialog(AntiMicroSettings *settings, QList *devices, QWidget *parent) : QDialog(parent, Qt::Dialog), ui(new Ui::MainSettingsDialog) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); ui->profileOpenDirPushButton->setIcon(QIcon::fromTheme("document-open-folder", QIcon(":/icons/16x16/actions/document-open-folder.png"))); ui->logFilePushButton->setIcon(QIcon::fromTheme("document-open-folder", QIcon(":/icons/16x16/actions/document-open-folder.png"))); this->settings = settings; this->allDefaultProfile = 0; this->connectedDevices = devices; #ifdef USE_SDL_2 fillControllerMappingsTable(); #endif settings->getLock()->lock(); QString defaultProfileDir = settings->value("DefaultProfileDir", "").toString(); int numberRecentProfiles = settings->value("NumberRecentProfiles", 5).toInt(); bool closeToTray = settings->value("CloseToTray", false).toBool(); if (!defaultProfileDir.isEmpty() && QDir(defaultProfileDir).exists()) { ui->profileDefaultDirLineEdit->setText(defaultProfileDir); } else { ui->profileDefaultDirLineEdit->setText(PadderCommon::preferredProfileDir(settings)); } ui->numberRecentProfileSpinBox->setValue(numberRecentProfiles); if (closeToTray) { ui->closeToTrayCheckBox->setChecked(true); } changePresetLanguage(); #ifdef Q_OS_WIN ui->autoProfileTableWidget->hideColumn(3); #endif ui->autoProfileTableWidget->hideColumn(7); #ifdef Q_OS_UNIX #if defined(USE_SDL_2) && defined(WITH_X11) #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif populateAutoProfiles(); fillAllAutoProfilesTable(); fillGUIDComboBox(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } else { delete ui->categoriesListWidget->item(2); ui->stackedWidget->removeWidget(ui->page_2); } #endif #elif defined(USE_SDL_2) && !defined(WITH_X11) delete ui->categoriesListWidget->item(2); ui->stackedWidget->removeWidget(ui->page_2); #elif !defined(USE_SDL_2) delete ui->categoriesListWidget->item(2); delete ui->categoriesListWidget->item(1); ui->stackedWidget->removeWidget(ui->controllerMappingsPage); ui->stackedWidget->removeWidget(ui->page_2); #endif #else populateAutoProfiles(); fillAllAutoProfilesTable(); fillGUIDComboBox(); #endif QString autoProfileActive = settings->value("AutoProfiles/AutoProfilesActive", "").toString(); if (autoProfileActive == "1") { ui->activeCheckBox->setChecked(true); ui->autoProfileTableWidget->setEnabled(true); ui->autoProfileAddPushButton->setEnabled(true); } #ifdef Q_OS_WIN BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) { // Handle Windows Vista and later QFile tempFile(RUNATSTARTUPLOCATION); if (tempFile.exists()) { ui->launchAtWinStartupCheckBox->setChecked(true); } } else { // Handle Windows XP QSettings autoRunReg(RUNATSTARTUPREGKEY, QSettings::NativeFormat); QString autoRunEntry = autoRunReg.value("antimicro", "").toString(); if (!autoRunEntry.isEmpty()) { ui->launchAtWinStartupCheckBox->setChecked(true); } } if (handler && handler->getIdentifier() == "sendinput") { bool keyRepeatEnabled = settings->value("KeyRepeat/KeyRepeatEnabled", true).toBool(); if (keyRepeatEnabled) { ui->keyRepeatEnableCheckBox->setChecked(true); ui->keyDelayHorizontalSlider->setEnabled(true); ui->keyDelaySpinBox->setEnabled(true); ui->keyRateHorizontalSlider->setEnabled(true); ui->keyRateSpinBox->setEnabled(true); } int keyRepeatDelay = settings->value("KeyRepeat/KeyRepeatDelay", InputDevice::DEFAULTKEYREPEATDELAY).toInt(); int keyRepeatRate = settings->value("KeyRepeat/KeyRepeatRate", InputDevice::DEFAULTKEYREPEATRATE).toInt(); ui->keyDelayHorizontalSlider->setValue(keyRepeatDelay); ui->keyDelaySpinBox->setValue(keyRepeatDelay); ui->keyRateHorizontalSlider->setValue(1000/keyRepeatRate); ui->keyRateSpinBox->setValue(1000/keyRepeatRate); } else { //ui->launchAtWinStartupCheckBox->setVisible(false); ui->keyRepeatGroupBox->setVisible(false); } #else ui->launchAtWinStartupCheckBox->setVisible(false); ui->keyRepeatGroupBox->setVisible(false); #endif bool useSingleProfileList = settings->value("TrayProfileList", false).toBool(); if (useSingleProfileList) { ui->traySingleProfileListCheckBox->setChecked(true); } bool minimizeToTaskBar = settings->value("MinimizeToTaskbar", false).toBool(); if (minimizeToTaskBar) { ui->minimizeTaskbarCheckBox->setChecked(true); } bool hideEmpty = settings->value("HideEmptyButtons", false).toBool(); if (hideEmpty) { ui->hideEmptyCheckBox->setChecked(true); } bool autoOpenLastProfile = settings->value("AutoOpenLastProfile", true).toBool(); if (autoOpenLastProfile) { ui->autoLoadPreviousCheckBox->setChecked(true); } else { ui->autoLoadPreviousCheckBox->setChecked(false); } bool launchInTray = settings->value("LaunchInTray", false).toBool(); if (launchInTray) { ui->launchInTrayCheckBox->setChecked(true); } #ifdef Q_OS_WIN bool associateProfiles = settings->value("AssociateProfiles", true).toBool(); if (associateProfiles) { ui->associateProfilesCheckBox->setChecked(true); } else { ui->associateProfilesCheckBox->setChecked(false); } #else ui->associateProfilesCheckBox->setVisible(false); #endif #ifdef Q_OS_WIN bool disableEnhancedMouse = settings->value("Mouse/DisableWinEnhancedPointer", false).toBool(); if (disableEnhancedMouse) { ui->disableWindowsEnhancedPointCheckBox->setChecked(true); } #else ui->disableWindowsEnhancedPointCheckBox->setVisible(false); #endif bool smoothingEnabled = settings->value("Mouse/Smoothing", false).toBool(); if (smoothingEnabled) { ui->smoothingEnableCheckBox->setChecked(true); ui->historySizeSpinBox->setEnabled(true); ui->weightModifierDoubleSpinBox->setEnabled(true); } int historySize = settings->value("Mouse/HistorySize", 0).toInt(); if (historySize > 0 && historySize <= JoyButton::MAXIMUMMOUSEHISTORYSIZE) { ui->historySizeSpinBox->setValue(historySize); } double weightModifier = settings->value("Mouse/WeightModifier", 0).toDouble(); if (weightModifier > 0.0 && weightModifier <= JoyButton::MAXIMUMWEIGHTMODIFIER) { ui->weightModifierDoubleSpinBox->setValue(weightModifier); } for (int i = 1; i <= JoyButton::MAXIMUMMOUSEREFRESHRATE; i++) { ui->mouseRefreshRateComboBox->addItem(QString("%1 ms").arg(i), i); } int refreshIndex = ui->mouseRefreshRateComboBox->findData(JoyButton::getMouseRefreshRate()); if (refreshIndex >= 0) { ui->mouseRefreshRateComboBox->setCurrentIndex(refreshIndex); } #ifdef Q_OS_WIN QString tempTooltip = ui->mouseRefreshRateComboBox->toolTip(); tempTooltip.append("\n\n"); tempTooltip.append(tr("Also, Windows users who want to use a low value should also check the\n" "\"Disable Enhance Pointer Precision\" checkbox if you haven't disabled\n" "the option in Windows.")); ui->mouseRefreshRateComboBox->setToolTip(tempTooltip); #endif fillSpringScreenPresets(); for (int i=1; i <= 16; i++) { ui->gamepadPollRateComboBox->addItem(QString("%1 ms").arg(i), QVariant(i)); } int gamepadPollIndex = ui->gamepadPollRateComboBox->findData(JoyButton::getGamepadRefreshRate()); if (gamepadPollIndex >= 0) { ui->gamepadPollRateComboBox->setCurrentIndex(gamepadPollIndex); } #ifdef Q_OS_UNIX #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif refreshExtraMouseInfo(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } else { ui->extraInfoFrame->hide(); } #endif #else ui->extraInfoFrame->hide(); #endif // Begin Advanced Tab QString curLogFile = settings->value("LogFile", "").toString(); int logLevel = settings->value("LogLevel", Logger::LOG_NONE).toInt(); if( !curLogFile.isEmpty() ) { ui->logFilePathEdit->setText(curLogFile); } ui->logLevelComboBox->setCurrentIndex( logLevel ); // End Advanced Tab settings->getLock()->unlock(); connect(ui->categoriesListWidget, SIGNAL(currentRowChanged(int)), ui->stackedWidget, SLOT(setCurrentIndex(int))); connect(ui->controllerMappingsTableWidget, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(mappingsTableItemChanged(QTableWidgetItem*))); connect(ui->mappingDeletePushButton, SIGNAL(clicked()), this, SLOT(deleteMappingRow())); connect(ui->mappngInsertPushButton, SIGNAL(clicked()), this, SLOT(insertMappingRow())); //connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(syncMappingSettings())); connect(this, SIGNAL(accepted()), this, SLOT(saveNewSettings())); connect(ui->profileOpenDirPushButton, SIGNAL(clicked()), this, SLOT(selectDefaultProfileDir())); connect(ui->activeCheckBox, SIGNAL(toggled(bool)), ui->autoProfileTableWidget, SLOT(setEnabled(bool))); connect(ui->activeCheckBox, SIGNAL(toggled(bool)), this, SLOT(autoProfileButtonsActiveState(bool))); //connect(ui->activeCheckBox, SIGNAL(toggled(bool)), ui->devicesComboBox, SLOT(setEnabled(bool))); connect(ui->devicesComboBox, SIGNAL(activated(int)), this, SLOT(changeDeviceForProfileTable(int))); connect(ui->autoProfileTableWidget, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(processAutoProfileActiveClick(QTableWidgetItem*))); connect(ui->autoProfileAddPushButton, SIGNAL(clicked()), this, SLOT(openAddAutoProfileDialog())); connect(ui->autoProfileDeletePushButton, SIGNAL(clicked()), this, SLOT(openDeleteAutoProfileConfirmDialog())); connect(ui->autoProfileEditPushButton, SIGNAL(clicked()), this, SLOT(openEditAutoProfileDialog())); connect(ui->autoProfileTableWidget, SIGNAL(itemSelectionChanged()), this, SLOT(changeAutoProfileButtonsState())); connect(ui->keyRepeatEnableCheckBox, SIGNAL(clicked(bool)), this, SLOT(changeKeyRepeatWidgetsStatus(bool))); connect(ui->keyDelayHorizontalSlider, SIGNAL(valueChanged(int)), ui->keyDelaySpinBox, SLOT(setValue(int))); connect(ui->keyDelaySpinBox, SIGNAL(valueChanged(int)), ui->keyDelayHorizontalSlider, SLOT(setValue(int))); connect(ui->keyRateHorizontalSlider, SIGNAL(valueChanged(int)), ui->keyRateSpinBox, SLOT(setValue(int))); connect(ui->keyRateSpinBox, SIGNAL(valueChanged(int)), ui->keyRateHorizontalSlider, SLOT(setValue(int))); connect(ui->smoothingEnableCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkSmoothingWidgetStatus(bool))); connect(ui->resetAccelPushButton, SIGNAL(clicked(bool)), this, SLOT(resetMouseAcceleration())); // Advanced Tab connect(ui->logFilePushButton, SIGNAL(clicked()), this, SLOT(selectLogFile())); } MainSettingsDialog::~MainSettingsDialog() { delete ui; if (connectedDevices) { delete connectedDevices; connectedDevices = 0; } } void MainSettingsDialog::fillControllerMappingsTable() { /*QList tempvariant = bindingValues(bind); QTableWidgetItem* item = new QTableWidgetItem(); ui->buttonMappingTableWidget->setItem(associatedRow, 0, item); item->setText(temptext); item->setData(Qt::UserRole, tempvariant); */ #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) ui->controllerMappingsTableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); #else ui->controllerMappingsTableWidget->horizontalHeader()->setResizeMode(QHeaderView::Stretch); #endif QHash > tempHash; settings->getLock()->lock(); settings->beginGroup("Mappings"); QStringList mappings = settings->allKeys(); QStringListIterator iter(mappings); while (iter.hasNext()) { QString tempkey = iter.next(); QString tempGUID; if (tempkey.contains("Disable")) { bool disableGameController = settings->value(tempkey, false).toBool(); tempGUID = tempkey.remove("Disable"); insertTempControllerMapping(tempHash, tempGUID); if (tempHash.contains(tempGUID)) { QList templist = tempHash.value(tempGUID); templist.replace(2, QVariant(disableGameController)); tempHash.insert(tempGUID, templist); // Overwrite original list } } else { QString mappingString = settings->value(tempkey, QString()).toString(); if (!mappingString.isEmpty()) { tempGUID = tempkey; insertTempControllerMapping(tempHash, tempGUID); if (tempHash.contains(tempGUID)) { QList templist = tempHash.value(tempGUID); templist.replace(1, mappingString); tempHash.insert(tempGUID, templist); // Overwrite original list } } } } settings->endGroup(); settings->getLock()->unlock(); QHashIterator > iter2(tempHash); int i = 0; while (iter2.hasNext()) { ui->controllerMappingsTableWidget->insertRow(i); QList templist = iter2.next().value(); QTableWidgetItem* item = new QTableWidgetItem(templist.at(0).toString()); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, iter2.key()); item->setToolTip(templist.at(0).toString()); ui->controllerMappingsTableWidget->setItem(i, 0, item); item = new QTableWidgetItem(templist.at(1).toString()); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, iter2.key()); //item->setToolTip(templist.at(1).toString()); ui->controllerMappingsTableWidget->setItem(i, 1, item); bool disableController = templist.at(2).toBool(); item = new QTableWidgetItem(); item->setCheckState(disableController ? Qt::Checked : Qt::Unchecked); item->setData(Qt::UserRole, iter2.key()); ui->controllerMappingsTableWidget->setItem(i, 2, item); i++; } } void MainSettingsDialog::insertTempControllerMapping(QHash > &hash, QString newGUID) { if (!newGUID.isEmpty() && !hash.contains(newGUID)) { QList templist; templist.append(QVariant(newGUID)); templist.append(QVariant("")); templist.append(QVariant(false)); hash.insert(newGUID, templist); } } void MainSettingsDialog::mappingsTableItemChanged(QTableWidgetItem *item) { int column = item->column(); int row = item->row(); if (column == 0 && !item->text().isEmpty()) { QTableWidgetItem *disableitem = ui->controllerMappingsTableWidget->item(row, column); if (disableitem) { disableitem->setData(Qt::UserRole, item->text()); } item->setData(Qt::UserRole, item->text()); } } void MainSettingsDialog::insertMappingRow() { int insertRowIndex = ui->controllerMappingsTableWidget->rowCount(); ui->controllerMappingsTableWidget->insertRow(insertRowIndex); QTableWidgetItem* item = new QTableWidgetItem(); //item->setFlags(item->flags() & ~Qt::ItemIsEditable); //item->setData(Qt::UserRole, iter2.key()); ui->controllerMappingsTableWidget->setItem(insertRowIndex, 0, item); item = new QTableWidgetItem(); item->setFlags(item->flags() & ~Qt::ItemIsEditable); //item->setData(Qt::UserRole, iter2.key()); ui->controllerMappingsTableWidget->setItem(insertRowIndex, 1, item); item = new QTableWidgetItem(); item->setCheckState(Qt::Unchecked); ui->controllerMappingsTableWidget->setItem(insertRowIndex, 2, item); } void MainSettingsDialog::deleteMappingRow() { int row = ui->controllerMappingsTableWidget->currentRow(); if (row >= 0) { ui->controllerMappingsTableWidget->removeRow(row); } } void MainSettingsDialog::syncMappingSettings() { settings->getLock()->lock(); settings->beginGroup("Mappings"); settings->remove(""); for (int i=0; i < ui->controllerMappingsTableWidget->rowCount(); i++) { QTableWidgetItem *itemGUID = ui->controllerMappingsTableWidget->item(i, 0); QTableWidgetItem *itemMapping = ui->controllerMappingsTableWidget->item(i, 1); QTableWidgetItem *itemDisable = ui->controllerMappingsTableWidget->item(i, 2); if (itemGUID && !itemGUID->text().isEmpty() && itemDisable) { QString disableController = itemDisable->checkState() == Qt::Checked ? "1" : "0"; if (itemMapping && !itemMapping->text().isEmpty()) { settings->setValue(itemGUID->text(), itemMapping->text()); } settings->setValue(QString("%1Disable").arg(itemGUID->text()), disableController); } } settings->endGroup(); settings->getLock()->unlock(); } void MainSettingsDialog::saveNewSettings() { #if defined(USE_SDL_2) syncMappingSettings(); #endif settings->getLock()->lock(); QString oldProfileDir = settings->value("DefaultProfileDir", "").toString(); QString possibleProfileDir = ui->profileDefaultDirLineEdit->text(); bool closeToTray = ui->closeToTrayCheckBox->isChecked(); if (oldProfileDir != possibleProfileDir) { if (QFileInfo(possibleProfileDir).exists()) { settings->setValue("DefaultProfileDir", possibleProfileDir); } else if (possibleProfileDir.isEmpty()) { settings->remove("DefaultProfileDir"); } } int numRecentProfiles = ui->numberRecentProfileSpinBox->value(); settings->setValue("NumberRecentProfiles", numRecentProfiles); if (closeToTray) { settings->setValue("CloseToTray", closeToTray ? "1" : "0"); } else { settings->remove("CloseToTray"); } settings->getLock()->unlock(); checkLocaleChange(); #ifdef Q_OS_UNIX #if defined(USE_SDL_2) && defined(WITH_X11) #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif saveAutoProfileSettings(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #endif #else saveAutoProfileSettings(); #endif settings->getLock()->lock(); #ifdef Q_OS_WIN if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) { // Handle Windows Vista and later QFile tempFile(RUNATSTARTUPLOCATION); if (ui->launchAtWinStartupCheckBox->isChecked() && !tempFile.exists()) { if (tempFile.open(QFile::WriteOnly)) { QFile currentAppLocation(qApp->applicationFilePath()); currentAppLocation.link(QFileInfo(tempFile).absoluteFilePath()); } } else if (tempFile.exists() && QFileInfo(tempFile).isWritable()) { tempFile.remove(); } } else { // Handle Windows XP QSettings autoRunReg(RUNATSTARTUPREGKEY, QSettings::NativeFormat); QString autoRunEntry = autoRunReg.value("antimicro", "").toString(); if (ui->launchAtWinStartupCheckBox->isChecked()) { QString nativeFilePath = QDir::toNativeSeparators(qApp->applicationFilePath()); autoRunReg.setValue("antimicro", nativeFilePath); } else if (!autoRunEntry.isEmpty()) { autoRunReg.remove("antimicro"); } } BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); if (handler && handler->getIdentifier() == "sendinput") { settings->setValue("KeyRepeat/KeyRepeatEnabled", ui->keyRepeatEnableCheckBox->isChecked() ? "1" : "0"); settings->setValue("KeyRepeat/KeyRepeatDelay", ui->keyDelaySpinBox->value()); settings->setValue("KeyRepeat/KeyRepeatRate", 1000/ui->keyRateSpinBox->value()); } #endif if (ui->traySingleProfileListCheckBox->isChecked()) { settings->setValue("TrayProfileList", "1"); } else { settings->setValue("TrayProfileList", "0"); } bool minimizeToTaskbar = ui->minimizeTaskbarCheckBox->isChecked(); settings->setValue("MinimizeToTaskbar", minimizeToTaskbar ? "1" : "0"); bool hideEmpty = ui->hideEmptyCheckBox->isChecked(); settings->setValue("HideEmptyButtons", hideEmpty ? "1" : "0"); bool autoOpenLastProfile = ui->autoLoadPreviousCheckBox->isChecked(); settings->setValue("AutoOpenLastProfile", autoOpenLastProfile ? "1" : "0"); bool launchInTray = ui->launchInTrayCheckBox->isChecked(); settings->setValue("LaunchInTray", launchInTray ? "1" : "0"); #ifdef Q_OS_WIN bool associateProfiles = ui->associateProfilesCheckBox->isChecked(); settings->setValue("AssociateProfiles", associateProfiles ? "1" : "0"); bool associationExists = WinExtras::containsFileAssociationinRegistry(); if (associateProfiles && !associationExists) { WinExtras::writeFileAssocationToRegistry(); } else if (!associateProfiles && associationExists) { WinExtras::removeFileAssociationFromRegistry(); } bool disableEnhancePoint = ui->disableWindowsEnhancedPointCheckBox->isChecked(); bool oldEnhancedValue = settings->value("Mouse/DisableWinEnhancedPointer", false).toBool(); bool usingEnhancedPointer = WinExtras::isUsingEnhancedPointerPrecision(); settings->setValue("Mouse/DisableWinEnhancedPointer", disableEnhancePoint ? "1" : "0"); if (disableEnhancePoint != oldEnhancedValue) { if (usingEnhancedPointer && disableEnhancePoint) { WinExtras::disablePointerPrecision(); } else if (!usingEnhancedPointer && !disableEnhancePoint) { WinExtras::enablePointerPrecision(); } } #endif PadderCommon::lockInputDevices(); if (connectedDevices->size() > 0) { InputDevice *tempDevice = connectedDevices->at(0); QMetaObject::invokeMethod(tempDevice, "haltServices", Qt::BlockingQueuedConnection); } bool smoothingEnabled = ui->smoothingEnableCheckBox->isChecked(); int historySize = ui->historySizeSpinBox->value(); double weightModifier = ui->weightModifierDoubleSpinBox->value(); settings->setValue("Mouse/Smoothing", smoothingEnabled ? "1" : "0"); if (smoothingEnabled) { if (historySize > 0) { JoyButton::setMouseHistorySize(historySize); } if (weightModifier) { JoyButton::setWeightModifier(weightModifier); } } else { JoyButton::setMouseHistorySize(1); JoyButton::setWeightModifier(0.0); } if (historySize > 0) { settings->setValue("Mouse/HistorySize", historySize); } if (weightModifier > 0.0) { settings->setValue("Mouse/WeightModifier", weightModifier); } int refreshIndex = ui->mouseRefreshRateComboBox->currentIndex(); int mouseRefreshRate = ui->mouseRefreshRateComboBox->itemData(refreshIndex).toInt(); if (mouseRefreshRate != JoyButton::getMouseRefreshRate()) { settings->setValue("Mouse/RefreshRate", mouseRefreshRate); JoyButton::setMouseRefreshRate(mouseRefreshRate); } int springIndex = ui->springScreenComboBox->currentIndex(); int springScreen = ui->springScreenComboBox->itemData(springIndex).toInt(); JoyButton::setSpringModeScreen(springScreen); settings->setValue("Mouse/SpringScreen", QString::number(springScreen)); int pollIndex = ui->gamepadPollRateComboBox->currentIndex(); unsigned int gamepadPollRate = ui->gamepadPollRateComboBox->itemData(pollIndex).toUInt(); if (gamepadPollRate != JoyButton::getGamepadRefreshRate()) { JoyButton::setGamepadRefreshRate(gamepadPollRate); settings->setValue("GamepadPollRate", QString::number(gamepadPollRate)); } // Advanced Tab settings->setValue("LogFile", ui->logFilePathEdit->text()); int logLevel = ui->logLevelComboBox->currentIndex(); if( logLevel < 0 ) { logLevel = 0; } if( Logger::LOG_MAX < logLevel ) { logLevel = Logger::LOG_MAX; } settings->setValue("LogLevel", logLevel); // End Advanced Tab PadderCommon::unlockInputDevices(); settings->sync(); settings->getLock()->unlock(); } void MainSettingsDialog::selectDefaultProfileDir() { QString lookupDir = PadderCommon::preferredProfileDir(settings); QString directory = QFileDialog::getExistingDirectory(this, tr("Select Default Profile Directory"), lookupDir); if (!directory.isEmpty() && QFileInfo(directory).exists()) { ui->profileDefaultDirLineEdit->setText(directory); } } void MainSettingsDialog::checkLocaleChange() { settings->getLock()->lock(); int row = ui->localeListWidget->currentRow(); if (row == 0) { if (settings->contains("Language")) { settings->remove("Language"); } settings->getLock()->unlock(); emit changeLanguage(QLocale::system().name()); } else { QString newLocale = "en"; if (row == 1) { newLocale = "br"; } else if (row == 2) { newLocale = "en"; } else if (row == 3) { newLocale = "fr"; } else if (row == 4) { newLocale = "de"; } else if (row == 5) { newLocale = "it"; } else if (row == 6) { newLocale = "ja"; } else if (row == 7) { newLocale = "ru"; } else if (row == 8) { newLocale = "sr"; } else if (row == 9) { newLocale = "zh_CN"; } else if (row == 10) { newLocale = "es"; } else if (row == 11) { newLocale = "uk"; } settings->setValue("Language", newLocale); settings->getLock()->unlock(); emit changeLanguage(newLocale); } } void MainSettingsDialog::populateAutoProfiles() { exeAutoProfiles.clear(); defaultAutoProfiles.clear(); settings->beginGroup("DefaultAutoProfiles"); QStringList registeredGUIDs = settings->value("GUIDs", QStringList()).toStringList(); //QStringList defaultkeys = settings->allKeys(); settings->endGroup(); QString allProfile = settings->value(QString("DefaultAutoProfileAll/Profile"), "").toString(); QString allActive = settings->value(QString("DefaultAutoProfileAll/Active"), "0").toString(); bool defaultActive = allActive == "1" ? true : false; allDefaultProfile = new AutoProfileInfo("all", allProfile, defaultActive, this); allDefaultProfile->setDefaultState(true); QStringListIterator iter(registeredGUIDs); while (iter.hasNext()) { QString tempkey = iter.next(); QString guid = tempkey; //QString guid = QString(tempkey).replace("GUID", ""); QString profile = settings->value(QString("DefaultAutoProfile-%1/Profile").arg(guid), "").toString(); QString active = settings->value(QString("DefaultAutoProfile-%1/Active").arg(guid), "0").toString(); QString deviceName = settings->value(QString("DefaultAutoProfile-%1/DeviceName").arg(guid), "").toString(); if (!guid.isEmpty() && !profile.isEmpty() && !deviceName.isEmpty()) { bool profileActive = active == "1" ? true : false; if (!defaultAutoProfiles.contains(guid) && guid != "all") { AutoProfileInfo *info = new AutoProfileInfo(guid, profile, profileActive, this); info->setDefaultState(true); info->setDeviceName(deviceName); defaultAutoProfiles.insert(guid, info); defaultList.append(info); QList templist; templist.append(info); deviceAutoProfiles.insert(guid, templist); } } } settings->beginGroup("AutoProfiles"); bool quitSearch = false; //QHash > tempAssociation; for (int i = 1; !quitSearch; i++) { QString exe = settings->value(QString("AutoProfile%1Exe").arg(i), "").toString(); QString windowName = settings->value(QString("AutoProfile%1WindowName").arg(i), "").toString(); #ifdef Q_OS_UNIX QString windowClass = settings->value(QString("AutoProfile%1WindowClass").arg(i), "").toString(); #else QString windowClass; #endif QString guid = settings->value(QString("AutoProfile%1GUID").arg(i), "").toString(); QString profile = settings->value(QString("AutoProfile%1Profile").arg(i), "").toString(); QString active = settings->value(QString("AutoProfile%1Active").arg(i), 0).toString(); QString deviceName = settings->value(QString("AutoProfile%1DeviceName").arg(i), "").toString(); // Check if all required elements exist. If not, assume that the end of the // list has been reached. if ((!exe.isEmpty() || !windowClass.isEmpty() || !windowName.isEmpty()) && !guid.isEmpty()) { bool profileActive = active == "1" ? true : false; AutoProfileInfo *info = new AutoProfileInfo(guid, profile, exe, profileActive, this); if (!deviceName.isEmpty()) { info->setDeviceName(deviceName); } info->setWindowName(windowName); #ifdef Q_OS_UNIX info->setWindowClass(windowClass); #endif profileList.append(info); QList templist; if (guid != "all") { if (deviceAutoProfiles.contains(guid)) { templist = deviceAutoProfiles.value(guid); } templist.append(info); deviceAutoProfiles.insert(guid, templist); } } /*if (!exe.isEmpty() && !guid.isEmpty()) { bool profileActive = active == "1" ? true : false; QList templist; if (exeAutoProfiles.contains(exe)) { templist = exeAutoProfiles.value(exe); } QList tempguids; if (tempAssociation.contains(exe)) { tempguids = tempAssociation.value(exe); } if (!tempguids.contains(guid)) { AutoProfileInfo *info = new AutoProfileInfo(guid, profile, exe, profileActive, this); if (!deviceName.isEmpty()) { info->setDeviceName(deviceName); } tempguids.append(guid); tempAssociation.insert(exe, tempguids); templist.append(info); exeAutoProfiles.insert(exe, templist); profileList.append(info); QList templist; if (guid != "all") { if (deviceAutoProfiles.contains(guid)) { templist = deviceAutoProfiles.value(guid); } templist.append(info); deviceAutoProfiles.insert(guid, templist); } } } */ else { quitSearch = true; } } settings->endGroup(); } void MainSettingsDialog::fillAutoProfilesTable(QString guid) { //ui->autoProfileTableWidget->clear(); for (int i = ui->autoProfileTableWidget->rowCount()-1; i >= 0; i--) { ui->autoProfileTableWidget->removeRow(i); } //QStringList tableHeader; //tableHeader << tr("Active") << tr("GUID") << tr("Profile") << tr("Application") << tr("Default?") // << tr("Instance"); //ui->autoProfileTableWidget->setHorizontalHeaderLabels(tableHeader); //ui->autoProfileTableWidget->horizontalHeader()->setVisible(true); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) ui->autoProfileTableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); #else ui->autoProfileTableWidget->horizontalHeader()->setResizeMode(QHeaderView::Stretch); #endif if (defaultAutoProfiles.contains(guid) || deviceAutoProfiles.contains(guid)) { int i = 0; AutoProfileInfo *defaultForGUID = 0; if (defaultAutoProfiles.contains(guid)) { AutoProfileInfo *info = defaultAutoProfiles.value(guid); defaultForGUID = info; ui->autoProfileTableWidget->insertRow(i); QTableWidgetItem *item = new QTableWidgetItem(); item->setCheckState(info->isActive() ? Qt::Checked : Qt::Unchecked); ui->autoProfileTableWidget->setItem(i, 0, item); QString deviceName = info->getDeviceName(); QString guidDisplay = info->getGUID(); if (!deviceName.isEmpty()) { guidDisplay = QString("%1 ").arg(info->getDeviceName()); guidDisplay.append(QString("(%1)").arg(info->getGUID())); } item = new QTableWidgetItem(guidDisplay); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getGUID()); item->setToolTip(info->getGUID()); ui->autoProfileTableWidget->setItem(i, 1, item); QFileInfo profilePath(info->getProfileLocation()); item = new QTableWidgetItem(profilePath.fileName()); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getProfileLocation()); item->setToolTip(info->getProfileLocation()); ui->autoProfileTableWidget->setItem(i, 2, item); item = new QTableWidgetItem(info->getWindowClass()); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getWindowClass()); item->setToolTip(info->getWindowClass()); ui->autoProfileTableWidget->setItem(i, 3, item); item = new QTableWidgetItem(info->getWindowName()); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getWindowName()); item->setToolTip(info->getWindowName()); ui->autoProfileTableWidget->setItem(i, 4, item); QFileInfo exeInfo(info->getExe()); item = new QTableWidgetItem(exeInfo.fileName()); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getExe()); item->setToolTip(info->getExe()); ui->autoProfileTableWidget->setItem(i, 5, item); item = new QTableWidgetItem("Default"); item->setData(Qt::UserRole, "default"); ui->autoProfileTableWidget->setItem(i, 6, item); item = new QTableWidgetItem("Instance"); item->setData(Qt::UserRole, QVariant::fromValue(info)); ui->autoProfileTableWidget->setItem(i, 7, item); i++; } QListIterator iter(deviceAutoProfiles.value(guid)); while (iter.hasNext()) { AutoProfileInfo *info = iter.next(); if (!defaultForGUID || info != defaultForGUID) { ui->autoProfileTableWidget->insertRow(i); QTableWidgetItem *item = new QTableWidgetItem(); item->setCheckState(info->isActive() ? Qt::Checked : Qt::Unchecked); ui->autoProfileTableWidget->setItem(i, 0, item); QString deviceName = info->getDeviceName(); QString guidDisplay = info->getGUID(); if (!deviceName.isEmpty()) { guidDisplay = QString("%1 ").arg(info->getDeviceName()); guidDisplay.append(QString("(%1)").arg(info->getGUID())); } item = new QTableWidgetItem(guidDisplay); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getGUID()); item->setToolTip(info->getGUID()); ui->autoProfileTableWidget->setItem(i, 1, item); QFileInfo profilePath(info->getProfileLocation()); item = new QTableWidgetItem(profilePath.fileName()); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getProfileLocation()); item->setToolTip(info->getProfileLocation()); ui->autoProfileTableWidget->setItem(i, 2, item); item = new QTableWidgetItem(info->getWindowClass()); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getWindowClass()); item->setToolTip(info->getWindowClass()); ui->autoProfileTableWidget->setItem(i, 3, item); item = new QTableWidgetItem(info->getWindowName()); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getWindowName()); item->setToolTip(info->getWindowName()); ui->autoProfileTableWidget->setItem(i, 4, item); QFileInfo exeInfo(info->getExe()); item = new QTableWidgetItem(exeInfo.fileName()); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getExe()); item->setToolTip(info->getExe()); ui->autoProfileTableWidget->setItem(i, 5, item); item = new QTableWidgetItem("Instance"); item->setData(Qt::UserRole, QVariant::fromValue(info)); ui->autoProfileTableWidget->setItem(i, 7, item); i++; } } } } void MainSettingsDialog::clearAutoProfileData() { } void MainSettingsDialog::fillGUIDComboBox() { ui->devicesComboBox->clear(); ui->devicesComboBox->addItem(tr("All"), QVariant("all")); QList guids = deviceAutoProfiles.keys(); QListIterator iter(guids); while (iter.hasNext()) { QString guid = iter.next(); QList temp = deviceAutoProfiles.value(guid); if (temp.count() > 0) { QString deviceName = temp.first()->getDeviceName(); if (!deviceName.isEmpty()) { ui->devicesComboBox->addItem(deviceName, QVariant(guid)); } else { ui->devicesComboBox->addItem(guid, QVariant(guid)); } } else { ui->devicesComboBox->addItem(guid, QVariant(guid)); } } } void MainSettingsDialog::changeDeviceForProfileTable(int index) { disconnect(ui->autoProfileTableWidget, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(processAutoProfileActiveClick(QTableWidgetItem*))); if (index == 0) { fillAllAutoProfilesTable(); } else { QString guid = ui->devicesComboBox->itemData(index).toString(); fillAutoProfilesTable(guid); } connect(ui->autoProfileTableWidget, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(processAutoProfileActiveClick(QTableWidgetItem*))); } void MainSettingsDialog::saveAutoProfileSettings() { settings->getLock()->lock(); settings->beginGroup("DefaultAutoProfiles"); QStringList defaultkeys = settings->allKeys(); settings->endGroup(); QStringListIterator iterDefaults(defaultkeys); while (iterDefaults.hasNext()) { QString tempkey = iterDefaults.next(); QString guid = QString(tempkey).replace("GUID", ""); QString testkey = QString("DefaultAutoProfile-%1").arg(guid); settings->beginGroup(testkey); settings->remove(""); settings->endGroup(); } settings->beginGroup("DefaultAutoProfiles"); settings->remove(""); settings->endGroup(); settings->beginGroup("DefaultAutoProfileAll"); settings->remove(""); settings->endGroup(); settings->beginGroup("AutoProfiles"); settings->remove(""); settings->endGroup(); if (allDefaultProfile) { QString profile = allDefaultProfile->getProfileLocation(); QString defaultActive = allDefaultProfile->isActive() ? "1" : "0"; settings->setValue(QString("DefaultAutoProfileAll/Profile"), profile); settings->setValue(QString("DefaultAutoProfileAll/Active"), defaultActive); } QMapIterator iter(defaultAutoProfiles); QStringList registeredGUIDs; while (iter.hasNext()) { iter.next(); QString guid = iter.key(); registeredGUIDs.append(guid); AutoProfileInfo *info = iter.value(); QString profileActive = info->isActive() ? "1" : "0"; QString deviceName = info->getDeviceName(); //settings->setValue(QString("DefaultAutoProfiles/GUID%1").arg(guid), guid); settings->setValue(QString("DefaultAutoProfile-%1/Profile").arg(guid), info->getProfileLocation()); settings->setValue(QString("DefaultAutoProfile-%1/Active").arg(guid), profileActive); settings->setValue(QString("DefaultAutoProfile-%1/DeviceName").arg(guid), deviceName); } if (!registeredGUIDs.isEmpty()) { settings->setValue("DefaultAutoProfiles/GUIDs", registeredGUIDs); } settings->beginGroup("AutoProfiles"); QString autoActive = ui->activeCheckBox->isChecked() ? "1" : "0"; settings->setValue("AutoProfilesActive", autoActive); QListIterator iterProfiles(profileList); int i = 1; while (iterProfiles.hasNext()) { AutoProfileInfo *info = iterProfiles.next(); QString defaultActive = info->isActive() ? "1" : "0"; if (!info->getExe().isEmpty()) { settings->setValue(QString("AutoProfile%1Exe").arg(i), info->getExe()); } if (!info->getWindowClass().isEmpty()) { settings->setValue(QString("AutoProfile%1WindowClass").arg(i), info->getWindowClass()); } if (!info->getWindowName().isEmpty()) { settings->setValue(QString("AutoProfile%1WindowName").arg(i), info->getWindowName()); } settings->setValue(QString("AutoProfile%1GUID").arg(i), info->getGUID()); settings->setValue(QString("AutoProfile%1Profile").arg(i), info->getProfileLocation()); settings->setValue(QString("AutoProfile%1Active").arg(i), defaultActive); settings->setValue(QString("AutoProfile%1DeviceName").arg(i), info->getDeviceName()); i++; } settings->endGroup(); settings->getLock()->unlock(); } void MainSettingsDialog::fillAllAutoProfilesTable() { for (int i = ui->autoProfileTableWidget->rowCount()-1; i >= 0; i--) { ui->autoProfileTableWidget->removeRow(i); } //QStringList tableHeader; //tableHeader << tr("Active") << tr("GUID") << tr("Profile") << tr("Application") << tr("Default?") // << tr("Instance"); //ui->autoProfileTableWidget->setHorizontalHeaderLabels(tableHeader); ui->autoProfileTableWidget->horizontalHeader()->setVisible(true); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) ui->autoProfileTableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); #else ui->autoProfileTableWidget->horizontalHeader()->setResizeMode(QHeaderView::Stretch); #endif ui->autoProfileTableWidget->hideColumn(7); int i = 0; AutoProfileInfo *info = allDefaultProfile; ui->autoProfileTableWidget->insertRow(i); QTableWidgetItem *item = new QTableWidgetItem(); item->setCheckState(info->isActive() ? Qt::Checked : Qt::Unchecked); ui->autoProfileTableWidget->setItem(i, 0, item); QString deviceName = info->getDeviceName(); QString guidDisplay = info->getGUID(); if (!deviceName.isEmpty()) { guidDisplay = QString("%1 ").arg(info->getDeviceName()); guidDisplay.append(QString("(%1)").arg(info->getGUID())); } item = new QTableWidgetItem(guidDisplay); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getGUID()); item->setToolTip(info->getGUID()); ui->autoProfileTableWidget->setItem(i, 1, item); QFileInfo profilePath(info->getProfileLocation()); item = new QTableWidgetItem(profilePath.fileName()); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getProfileLocation()); item->setToolTip(info->getProfileLocation()); ui->autoProfileTableWidget->setItem(i, 2, item); QFileInfo exeInfo(info->getExe()); item = new QTableWidgetItem(exeInfo.fileName()); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getExe()); item->setToolTip(info->getExe()); ui->autoProfileTableWidget->setItem(i, 5, item); item = new QTableWidgetItem("Default"); item->setData(Qt::UserRole, "default"); ui->autoProfileTableWidget->setItem(i, 6, item); item = new QTableWidgetItem("Instance"); item->setData(Qt::UserRole, QVariant::fromValue(info)); ui->autoProfileTableWidget->setItem(i, 7, item); i++; QListIterator iterDefaults(defaultList); while (iterDefaults.hasNext()) { AutoProfileInfo *info = iterDefaults.next(); ui->autoProfileTableWidget->insertRow(i); QTableWidgetItem *item = new QTableWidgetItem(); item->setCheckState(info->isActive() ? Qt::Checked : Qt::Unchecked); ui->autoProfileTableWidget->setItem(i, 0, item); QString deviceName = info->getDeviceName(); QString guidDisplay = info->getGUID(); if (!deviceName.isEmpty()) { guidDisplay = QString("%1 ").arg(info->getDeviceName()); guidDisplay.append(QString("(%1)").arg(info->getGUID())); } item = new QTableWidgetItem(guidDisplay); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getGUID()); item->setToolTip(info->getGUID()); ui->autoProfileTableWidget->setItem(i, 1, item); QFileInfo profilePath(info->getProfileLocation()); item = new QTableWidgetItem(profilePath.fileName()); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getProfileLocation()); item->setToolTip(info->getProfileLocation()); ui->autoProfileTableWidget->setItem(i, 2, item); /* QFileInfo exeInfo(info->getExe()); item = new QTableWidgetItem(exeInfo.fileName()); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getExe()); item->setToolTip(info->getExe()); ui->autoProfileTableWidget->setItem(i, 3, item); */ item = new QTableWidgetItem("Default"); item->setData(Qt::UserRole, "default"); ui->autoProfileTableWidget->setItem(i, 6, item); item = new QTableWidgetItem("Instance"); item->setData(Qt::UserRole, QVariant::fromValue(info)); ui->autoProfileTableWidget->setItem(i, 7, item); i++; } QListIterator iter(profileList); while (iter.hasNext()) { AutoProfileInfo *info = iter.next(); ui->autoProfileTableWidget->insertRow(i); QTableWidgetItem *item = new QTableWidgetItem(); item->setCheckState(info->isActive() ? Qt::Checked : Qt::Unchecked); ui->autoProfileTableWidget->setItem(i, 0, item); QString deviceName = info->getDeviceName(); QString guidDisplay = info->getGUID(); if (!deviceName.isEmpty()) { guidDisplay = QString("%1 ").arg(info->getDeviceName()); guidDisplay.append(QString("(%1)").arg(info->getGUID())); } item = new QTableWidgetItem(guidDisplay); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getGUID()); item->setToolTip(info->getGUID()); ui->autoProfileTableWidget->setItem(i, 1, item); QFileInfo profilePath(info->getProfileLocation()); item = new QTableWidgetItem(profilePath.fileName()); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getProfileLocation()); item->setToolTip(info->getProfileLocation()); ui->autoProfileTableWidget->setItem(i, 2, item); item = new QTableWidgetItem(info->getWindowClass()); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getWindowClass()); item->setToolTip(info->getWindowClass()); ui->autoProfileTableWidget->setItem(i, 3, item); item = new QTableWidgetItem(info->getWindowName()); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getWindowName()); item->setToolTip(info->getWindowName()); ui->autoProfileTableWidget->setItem(i, 4, item); QFileInfo exeInfo(info->getExe()); item = new QTableWidgetItem(exeInfo.fileName()); item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setData(Qt::UserRole, info->getExe()); item->setToolTip(info->getExe()); ui->autoProfileTableWidget->setItem(i, 5, item); item = new QTableWidgetItem(); item->setData(Qt::UserRole, ""); ui->autoProfileTableWidget->setItem(i, 6, item); item = new QTableWidgetItem("Instance"); item->setData(Qt::UserRole, QVariant::fromValue(info)); ui->autoProfileTableWidget->setItem(i, 7, item); i++; } } void MainSettingsDialog::processAutoProfileActiveClick(QTableWidgetItem *item) { if (item && item->column() == 0) { QTableWidgetItem *infoitem = ui->autoProfileTableWidget->item(item->row(), 7); AutoProfileInfo *info = infoitem->data(Qt::UserRole).value(); Qt::CheckState active = item->checkState(); if (active == Qt::Unchecked) { info->setActive(false); } else if (active == Qt::Checked) { info->setActive(true); } } } void MainSettingsDialog::openAddAutoProfileDialog() { QList reservedGUIDs = defaultAutoProfiles.keys(); AutoProfileInfo *info = new AutoProfileInfo(this); AddEditAutoProfileDialog *dialog = new AddEditAutoProfileDialog(info, settings, connectedDevices, reservedGUIDs, false, this); connect(dialog, SIGNAL(accepted()), this, SLOT(addNewAutoProfile())); connect(dialog, SIGNAL(rejected()), info, SLOT(deleteLater())); dialog->show(); } void MainSettingsDialog::openEditAutoProfileDialog() { int selectedRow = ui->autoProfileTableWidget->currentRow(); if (selectedRow >= 0) { QTableWidgetItem *item = ui->autoProfileTableWidget->item(selectedRow, 7); //QTableWidgetItem *itemDefault = ui->autoProfileTableWidget->item(selectedRow, 4); AutoProfileInfo *info = item->data(Qt::UserRole).value(); if (info != allDefaultProfile) { QList reservedGUIDs = defaultAutoProfiles.keys(); if (info->getGUID() != "all") { AutoProfileInfo *temp = defaultAutoProfiles.value(info->getGUID()); if (info == temp) { reservedGUIDs.removeAll(info->getGUID()); } } AddEditAutoProfileDialog *dialog = new AddEditAutoProfileDialog(info, settings, connectedDevices, reservedGUIDs, true, this); connect(dialog, SIGNAL(accepted()), this, SLOT(transferEditsToCurrentTableRow())); dialog->show(); } else { EditAllDefaultAutoProfileDialog *dialog = new EditAllDefaultAutoProfileDialog(info, settings, this); dialog->show(); connect(dialog, SIGNAL(accepted()), this, SLOT(transferAllProfileEditToCurrentTableRow())); } } } void MainSettingsDialog::openDeleteAutoProfileConfirmDialog() { QMessageBox msgBox; msgBox.setText(tr("Are you sure you want to delete the profile?")); msgBox.setStandardButtons(QMessageBox::Discard | QMessageBox::Cancel); msgBox.setDefaultButton(QMessageBox::Cancel); int ret = msgBox.exec(); if (ret == QMessageBox::Discard) { int selectedRow = ui->autoProfileTableWidget->currentRow(); if (selectedRow >= 0) { QTableWidgetItem *item = ui->autoProfileTableWidget->item(selectedRow, 7); //QTableWidgetItem *itemDefault = ui->autoProfileTableWidget->item(selectedRow, 4); AutoProfileInfo *info = item->data(Qt::UserRole).value(); if (info->isCurrentDefault()) { if (info->getGUID() == "all") { delete allDefaultProfile; allDefaultProfile = 0; } else if (defaultAutoProfiles.contains(info->getGUID())) { defaultAutoProfiles.remove(info->getGUID()); defaultList.removeAll(info); delete info; info = 0; } } else { if (deviceAutoProfiles.contains(info->getGUID())) { QList temp = deviceAutoProfiles.value(info->getGUID()); temp.removeAll(info); deviceAutoProfiles.insert(info->getGUID(), temp); } /*if (exeAutoProfiles.contains(info->getExe())) { QList temp = exeAutoProfiles.value(info->getExe()); temp.removeAll(info); exeAutoProfiles.insert(info->getExe(), temp); } */ profileList.removeAll(info); delete info; info = 0; } } ui->autoProfileTableWidget->removeRow(selectedRow); } } void MainSettingsDialog::changeAutoProfileButtonsState() { int selectedRow = ui->autoProfileTableWidget->currentRow(); if (selectedRow >= 0) { QTableWidgetItem *item = ui->autoProfileTableWidget->item(selectedRow, 7); //QTableWidgetItem *itemDefault = ui->autoProfileTableWidget->item(selectedRow, 4); AutoProfileInfo *info = item->data(Qt::UserRole).value(); if (info == allDefaultProfile) { ui->autoProfileAddPushButton->setEnabled(true); ui->autoProfileEditPushButton->setEnabled(true); ui->autoProfileDeletePushButton->setEnabled(false); } else { ui->autoProfileAddPushButton->setEnabled(true); ui->autoProfileEditPushButton->setEnabled(true); ui->autoProfileDeletePushButton->setEnabled(true); } } else { ui->autoProfileAddPushButton->setEnabled(true); ui->autoProfileDeletePushButton->setEnabled(false); ui->autoProfileEditPushButton->setEnabled(false); } } void MainSettingsDialog::transferAllProfileEditToCurrentTableRow() { EditAllDefaultAutoProfileDialog *dialog = static_cast(sender()); AutoProfileInfo *info = dialog->getAutoProfile(); allDefaultProfile = info; changeDeviceForProfileTable(0); } void MainSettingsDialog::transferEditsToCurrentTableRow() { AddEditAutoProfileDialog *dialog = static_cast(sender()); AutoProfileInfo *info = dialog->getAutoProfile(); // Delete pointers to object that might be misplaced // due to an association change. QString oldGUID = dialog->getOriginalGUID(); //QString originalExe = dialog->getOriginalExe(); if (oldGUID != info->getGUID()) { if (defaultAutoProfiles.value(oldGUID) == info) { defaultAutoProfiles.remove(oldGUID); } if (info->isCurrentDefault()) { defaultAutoProfiles.insert(info->getGUID(), info); } } if (oldGUID != info->getGUID() && deviceAutoProfiles.contains(oldGUID)) { QList temp = deviceAutoProfiles.value(oldGUID); temp.removeAll(info); if (temp.count() > 0) { deviceAutoProfiles.insert(oldGUID, temp); } else { deviceAutoProfiles.remove(oldGUID); } if (deviceAutoProfiles.contains(info->getGUID())) { QList temp2 = deviceAutoProfiles.value(oldGUID); if (!temp2.contains(info)) { temp2.append(info); deviceAutoProfiles.insert(info->getGUID(), temp2); } } else if (info->getGUID().toLower() != "all") { QList temp2; temp2.append(info); deviceAutoProfiles.insert(info->getGUID(), temp2); } } else if (oldGUID != info->getGUID() && info->getGUID().toLower() != "all") { QList temp; temp.append(info); deviceAutoProfiles.insert(info->getGUID(), temp); } if (!info->isCurrentDefault()) { defaultList.removeAll(info); if (!profileList.contains(info)) { profileList.append(info); } } else { profileList.removeAll(info); if (!defaultList.contains(info)) { defaultList.append(info); } } if (deviceAutoProfiles.contains(info->getGUID())) { QList temp2 = deviceAutoProfiles.value(info->getGUID()); if (!temp2.contains(info)) { temp2.append(info); deviceAutoProfiles.insert(info->getGUID(), temp2); } } else { QList temp2; temp2.append(info); deviceAutoProfiles.insert(info->getGUID(), temp2); } /*if (originalExe != info->getExe() && exeAutoProfiles.contains(originalExe)) { QList temp = exeAutoProfiles.value(originalExe); temp.removeAll(info); exeAutoProfiles.insert(originalExe, temp); if (exeAutoProfiles.contains(info->getExe())) { QList temp2 = exeAutoProfiles.value(info->getExe()); if (!temp2.contains(info)) { temp2.append(info); exeAutoProfiles.insert(info->getExe(), temp2); } } else { QList temp2; temp2.append(info); exeAutoProfiles.insert(info->getExe(), temp2); } if (deviceAutoProfiles.contains(info->getGUID())) { QList temp2 = deviceAutoProfiles.value(info->getGUID()); if (!temp2.contains(info)) { temp2.append(info); deviceAutoProfiles.insert(info->getGUID(), temp2); } } else { QList temp2; temp2.append(info); deviceAutoProfiles.insert(info->getGUID(), temp2); } } */ fillGUIDComboBox(); int currentIndex = ui->devicesComboBox->currentIndex(); changeDeviceForProfileTable(currentIndex); } void MainSettingsDialog::addNewAutoProfile() { AddEditAutoProfileDialog *dialog = static_cast(sender()); AutoProfileInfo *info = dialog->getAutoProfile(); bool found = false; if (info->isCurrentDefault()) { if (defaultAutoProfiles.contains(info->getGUID())) { found = true; } } /*else { QList templist; if (exeAutoProfiles.contains(info->getExe())) { templist = exeAutoProfiles.value(info->getExe()); } QListIterator iterProfiles(templist); while (iterProfiles.hasNext()) { AutoProfileInfo *oldinfo = iterProfiles.next(); if (info->getExe() == oldinfo->getExe() && info->getGUID() == oldinfo->getGUID()) { found = true; iterProfiles.toBack(); } } } */ if (!found) { if (info->isCurrentDefault()) { if (!info->getGUID().isEmpty() && !info->getExe().isEmpty()) { defaultAutoProfiles.insert(info->getGUID(), info); defaultList.append(info); } } else { if (!info->getGUID().isEmpty() && !info->getExe().isEmpty()) { //QList templist; //templist.append(info); //exeAutoProfiles.insert(info->getExe(), templist); profileList.append(info); if (info->getGUID() != "all") { QList tempDevProfileList; if (deviceAutoProfiles.contains(info->getGUID())) { tempDevProfileList = deviceAutoProfiles.value(info->getGUID()); } tempDevProfileList.append(info); deviceAutoProfiles.insert(info->getGUID(), tempDevProfileList); } } } fillGUIDComboBox(); changeDeviceForProfileTable(ui->devicesComboBox->currentIndex()); } } void MainSettingsDialog::autoProfileButtonsActiveState(bool enabled) { if (enabled) { changeAutoProfileButtonsState(); } else { ui->autoProfileAddPushButton->setEnabled(false); ui->autoProfileEditPushButton->setEnabled(false); ui->autoProfileDeletePushButton->setEnabled(false); } } void MainSettingsDialog::changeKeyRepeatWidgetsStatus(bool enabled) { ui->keyDelayHorizontalSlider->setEnabled(enabled); ui->keyDelaySpinBox->setEnabled(enabled); ui->keyRateHorizontalSlider->setEnabled(enabled); ui->keyRateSpinBox->setEnabled(enabled); } void MainSettingsDialog::checkSmoothingWidgetStatus(bool enabled) { if (enabled) { ui->historySizeSpinBox->setEnabled(true); ui->weightModifierDoubleSpinBox->setEnabled(true); } else { ui->historySizeSpinBox->setEnabled(false); ui->weightModifierDoubleSpinBox->setEnabled(false); } } void MainSettingsDialog::changePresetLanguage() { if (settings->contains("Language")) { QString targetLang = settings->value("Language").toString(); if (targetLang == "br") { ui->localeListWidget->setCurrentRow(1); } else if (targetLang == "en") { ui->localeListWidget->setCurrentRow(2); } else if (targetLang == "fr") { ui->localeListWidget->setCurrentRow(3); } else if (targetLang == "de") { ui->localeListWidget->setCurrentRow(4); } else if (targetLang == "it") { ui->localeListWidget->setCurrentRow(5); } else if (targetLang == "ja") { ui->localeListWidget->setCurrentRow(6); } else if (targetLang == "ru") { ui->localeListWidget->setCurrentRow(7); } else if (targetLang == "sr") { ui->localeListWidget->setCurrentRow(8); } else if (targetLang == "zh_CN") { ui->localeListWidget->setCurrentRow(9); } else if (targetLang == "es") { ui->localeListWidget->setCurrentRow(10); } else if (targetLang == "uk") { ui->localeListWidget->setCurrentRow(11); } else { ui->localeListWidget->setCurrentRow(0); } } else { ui->localeListWidget->setCurrentRow(0); } } void MainSettingsDialog::fillSpringScreenPresets() { ui->springScreenComboBox->clear(); ui->springScreenComboBox->addItem(tr("Default"), QVariant(AntiMicroSettings::defaultSpringScreen)); QDesktopWidget deskWid; for (int i=0; i < deskWid.screenCount(); i++) { ui->springScreenComboBox->addItem(QString(":%1").arg(i), QVariant(i)); } int screenIndex = ui->springScreenComboBox->findData(JoyButton::getSpringModeScreen()); if (screenIndex > -1) { ui->springScreenComboBox->setCurrentIndex(screenIndex); } } void MainSettingsDialog::refreshExtraMouseInfo() { #if defined(Q_OS_UNIX) && defined(WITH_X11) QString handler = EventHandlerFactory::getInstance()->handler()->getIdentifier(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif struct X11Extras::ptrInformation temp; if (handler == "uinput") { temp = X11Extras::getInstance()->getPointInformation(); } else if (handler == "xtest") { temp = X11Extras::getInstance()->getPointInformation(X11Extras::xtestMouseDeviceName); } if (temp.id >= 0) { ui->accelNumLabel->setText(QString::number(temp.accelNum)); ui->accelDenomLabel->setText(QString::number(temp.accelDenom)); ui->accelThresLabel->setText(QString::number(temp.threshold)); } #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #endif } void MainSettingsDialog::resetMouseAcceleration() { #if defined(Q_OS_UNIX) && defined(WITH_X11) #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif X11Extras::getInstance()->x11ResetMouseAccelerationChange(); refreshExtraMouseInfo(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #endif } void MainSettingsDialog::selectLogFile() { QString oldLogFile = settings->value("LogFile", "").toString(); QString newLogFile = QFileDialog::getSaveFileName(this, tr("Save Log File As"), oldLogFile, tr("Log Files (*.log)")); if( !newLogFile.isEmpty() ) { ui->logFilePathEdit->setText(newLogFile); } } antimicro-2.23/src/mainsettingsdialog.h000066400000000000000000000064761300750276700202760ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MAINSETTINGSDIALOG_H #define MAINSETTINGSDIALOG_H #include #include #include #include #include #include #include "autoprofileinfo.h" #include "inputdevice.h" #include "antimicrosettings.h" namespace Ui { class MainSettingsDialog; } class MainSettingsDialog : public QDialog { Q_OBJECT public: explicit MainSettingsDialog(AntiMicroSettings *settings, QList *devices, QWidget *parent = 0); ~MainSettingsDialog(); protected: void fillControllerMappingsTable(); void insertTempControllerMapping(QHash > &hash, QString newGUID); void checkLocaleChange(); void populateAutoProfiles(); void fillAutoProfilesTable(QString guid); void fillAllAutoProfilesTable(); void clearAutoProfileData(); void changePresetLanguage(); void fillSpringScreenPresets(); void refreshExtraMouseInfo(); AntiMicroSettings *settings; // GUID, AutoProfileInfo* // Default profiles assigned to a specific device QMap defaultAutoProfiles; // GUID, QList // Profiles assigned with an association with an application QMap > deviceAutoProfiles; // Path, QList // TODO: CHECK IF NEEDED ANYMORE QMap > exeAutoProfiles; QList defaultList; QList profileList; AutoProfileInfo* allDefaultProfile; QList *connectedDevices; private: Ui::MainSettingsDialog *ui; signals: void changeLanguage(QString language); protected slots: void mappingsTableItemChanged(QTableWidgetItem *item); void insertMappingRow(); void deleteMappingRow(); void syncMappingSettings(); void saveNewSettings(); void selectDefaultProfileDir(); void fillGUIDComboBox(); void changeDeviceForProfileTable(int index); void saveAutoProfileSettings(); void processAutoProfileActiveClick(QTableWidgetItem *item); void openAddAutoProfileDialog(); void openEditAutoProfileDialog(); void openDeleteAutoProfileConfirmDialog(); void changeAutoProfileButtonsState(); void transferEditsToCurrentTableRow(); void transferAllProfileEditToCurrentTableRow(); void addNewAutoProfile(); void autoProfileButtonsActiveState(bool enabled); void changeKeyRepeatWidgetsStatus(bool enabled); void checkSmoothingWidgetStatus(bool enabled); void resetMouseAcceleration(); void selectLogFile(); }; #endif // MAINSETTINGSDIALOG_H antimicro-2.23/src/mainsettingsdialog.ui000066400000000000000000001270471300750276700204620ustar00rootroot00000000000000 MainSettingsDialog Qt::WindowModal 0 0 706 578 0 0 Edit Settings true 0 0 180 16777215 QListView::TopToBottom false QListView::Fixed false 0 General Controller Mappings Language Auto Profile Mouse Advanced 0 4 9 20 Profi&le Directory: profileDefaultDirLineEdit <html><head/><body><p>Specify the default directory that the program should use in file dialogs when loading a profile or saving a new profile.</p></body></html> 512 true false Recent Profile Count: <html><head/><body><p>Number of profiles that can be placed in recent profile list. 0 will result in the program not enforcing a limit on the number of profiles displayed.</p></body></html> 100 5 Qt::Vertical QSizePolicy::Fixed 20 8 8 Gamepad Poll Rate: Change the poll rate that the program uses to discover new events from gamepads. Defaults to 10 ms. Reducing the poll rate value could cause the application to use more CPU power so please test the setting that you use before using antimicro unattended. Hide main window when the main window close button is clicked instead of quitting the program. Close To Tray Have Windows start antimicro at system startup. Launch At Windows Startup Display recent profiles for all controllers as a single list in the tray menu. Defaults to using sub-menus. Single Profile List in Tray Have the program minimize to the taskbar. By default, the program minimizes to the system tray if available. Minimize to Taskbar This option will cause the program to hide all buttons that have no slots assigned to them. The Quick Set dialog window will have to be used to bring up the edit dialog for gamepad buttons. Hide Empty Buttons When the program is launched, open the last known profile that was opened during the previous session. Auto Load Last Opened Profile true Only show the system tray icon when the program first launches. Launch in Tray Associate .amgp files with antimicro in Windows Explorer. Associate Profiles true Qt::Vertical QSizePolicy::Fixed 20 8 Key Repeat Active keys will be repeatedly pressed when this option is enabled. Enable Delay: false Specifies how much time should elapse before key repeating begins. 250 1000 10 100 660 Qt::Horizontal QSlider::NoTicks false ms 250 1000 100 660 Rate: false Specifies how many times key presses will be performed per seconds. 5 50 25 Qt::Horizontal QSlider::NoTicks false times/s 5 50 25 Qt::Vertical QSizePolicy::MinimumExpanding 20 10 4 9 Below is a list of the custom mappings that have been saved. You can use the following table to delete mappings or have mappings temporarily disabled. You can also disable mappings that are included with SDL; just insert a new row with the appropriate joystick GUID and check disable. Settings will not take affect until you either refresh all joysticks or unplug that particular joystick. false true QAbstractItemView::SingleSelection true false GUID Mapping String Disable? Delete .. Insert .. 4 <html><head/><body><p>antimicro has been translated into many different languages by contributors. By default, the program will choose an appropriate translation based on your system's locale setting. However, you can make antimicro load a different translation depending on the language that you choose from the list below.</p></body></html> true Qt::Vertical QSizePolicy::Minimum 10 10 -1 Default Português do Brasil English Français Deutsch Italiano 日本語 РуÑÑкий ÑрпÑки / srpski 简化字 Español українÑька 4 Active 20 Qt::Horizontal 40 20 Devices: All Qt::Vertical QSizePolicy::Fixed 20 10 false QAbstractItemView::SingleSelection QAbstractItemView::SelectRows 8 false true 100 false true false Active Device Profile Class Title Program Default? Qt::Vertical QSizePolicy::Fixed 20 10 false Add .. false Edit .. false Delete .. 10 4 Disable the "Enhanced Pointer Precision" Windows setting while antimicro is running. Disabling "Enhanced Pointer Precision" will allow mouse movement within antimicro to be more precise. Disable Enhance Pointer Precision true Smoothing 10 20 Enable Histor&y Size: historySizeSpinBox false 1 100 10 Weight &Modifier: weightModifierDoubleSpinBox false 1.000000000000000 0.100000000000000 0.200000000000000 Refresh Rate: The refresh rate is the amount of time that will elapse in between mouse events. Please be cautious when editing this setting as it will cause the program to use more CPU power. Setting this value too low can cause system instability. Please test the setting before using it unattended. Spring 10 20 Screen: springScreenComboBox Utilize the specified screen for spring mode. On Linux, the default is to use the primary screen. On Windows, the default is to use all available screens. QFrame::StyledPanel QFrame::Raised 6 0 0 Accel Numerator: 0 0 0 Qt::Horizontal 40 20 Accel Denominator: 0 Qt::Horizontal 40 20 Accel Threshold: 0 Qt::Horizontal 40 20 Qt::Horizontal 40 20 If the acceleration values for the virtual mouse have been changed by a different process, particularly when quitting an older game, then you might want to reset the acceleration values used by the virtual mouse. Reset Acceleration Qt::Vertical 20 20 10 9 481 31 Log File: 9 69 481 31 Qt::LeftToRight Log Level: None Error Warning Info Debug Qt::Horizontal 40 20 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() MainSettingsDialog accept() 248 254 157 274 buttonBox rejected() MainSettingsDialog reject() 316 260 286 274 antimicro-2.23/src/mainwindow.cpp000066400000000000000000001543021300750276700171100ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN #include #endif #include "mainwindow.h" #include "ui_mainwindow.h" #include "joyaxiswidget.h" #include "joybuttonwidget.h" #include "joycontrolstickpushbutton.h" #include "joytabwidget.h" #include "joydpadbuttonwidget.h" #include "joycontrolstickbuttonpushbutton.h" #include "dpadpushbutton.h" #include "joystickstatuswindow.h" #include "qkeydisplaydialog.h" #include "mainsettingsdialog.h" #include "advancestickassignmentdialog.h" #include "common.h" #ifdef USE_SDL_2 #include "gamecontrollermappingdialog.h" #if defined(WITH_X11) || defined(Q_OS_WIN) #include "autoprofileinfo.h" #endif #endif #ifdef Q_OS_WIN #include "winextras.h" #endif #ifdef Q_OS_UNIX #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include #endif #endif MainWindow::MainWindow(QMap *joysticks, CommandLineUtility *cmdutility, AntiMicroSettings *settings, bool graphical, QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); ui->stackedWidget->setCurrentIndex(0); this->translator = 0; this->appTranslator = 0; this->cmdutility = cmdutility; this->graphical = graphical; this->settings = settings; ui->actionStick_Pad_Assign->setVisible(false); #ifndef USE_SDL_2 ui->actionGameController_Mapping->setVisible(false); #endif #ifdef Q_OS_UNIX #if defined(USE_SDL_2) && defined(WITH_X11) #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif this->appWatcher = new AutoProfileWatcher(settings, this); checkAutoProfileWatcherTimer(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } else { this->appWatcher = 0; } #endif #endif #elif defined(Q_OS_WIN) this->appWatcher = new AutoProfileWatcher(settings, this); checkAutoProfileWatcherTimer(); #else this->appWatcher = 0; #endif signalDisconnect = false; showTrayIcon = !cmdutility->isTrayHidden() && graphical && !cmdutility->shouldListControllers() && !cmdutility->shouldMapController(); this->joysticks = joysticks; if (showTrayIcon) { trayIconMenu = new QMenu(this); trayIcon = new QSystemTrayIcon(this); trayIcon->setContextMenu(trayIconMenu); connect(trayIconMenu, SIGNAL(aboutToShow()), this, SLOT(refreshTrayIconMenu())); connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayIconClickAction(QSystemTrayIcon::ActivationReason))); } // Look at flags and call setEnabled as desired; defaults to true. // Enabled status is used to specify whether errors in profile loading and // saving should be display in a window or written to stderr. if (graphical) { if (cmdutility->isHiddenRequested() && cmdutility->isTrayHidden()) { setEnabled(false); } } else { setEnabled(false); } resize(settings->value("WindowSize", size()).toSize()); move(settings->value("WindowPosition", pos()).toPoint()); if (graphical) { aboutDialog = new AboutDialog(this); } else { aboutDialog = 0; } connect(ui->menuQuit, SIGNAL(aboutToShow()), this, SLOT(mainMenuChange())); connect(ui->menuOptions, SIGNAL(aboutToShow()), this, SLOT(mainMenuChange())); connect(ui->actionKeyValue, SIGNAL(triggered()), this, SLOT(openKeyCheckerDialog())); connect(ui->actionAbout_Qt, SIGNAL(triggered()), qApp, SLOT(aboutQt())); connect(ui->actionProperties, SIGNAL(triggered()), this, SLOT(openJoystickStatusWindow())); connect(ui->actionGitHubPage, SIGNAL(triggered()), this, SLOT(openGitHubPage())); connect(ui->actionOptions, SIGNAL(triggered()), this, SLOT(openMainSettingsDialog())); connect(ui->actionWiki, SIGNAL(triggered()), this, SLOT(openWikiPage())); #ifdef USE_SDL_2 connect(ui->actionGameController_Mapping, SIGNAL(triggered()), this, SLOT(openGameControllerMappingWindow())); #if defined(Q_OS_UNIX) && defined(WITH_X11) #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif connect(appWatcher, SIGNAL(foundApplicableProfile(AutoProfileInfo*)), this, SLOT(autoprofileLoad(AutoProfileInfo*))); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #elif defined(Q_OS_WIN) connect(appWatcher, SIGNAL(foundApplicableProfile(AutoProfileInfo*)), this, SLOT(autoprofileLoad(AutoProfileInfo*))); #endif #endif #ifdef Q_OS_WIN if (graphical) { if (!WinExtras::IsRunningAsAdmin()) { if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) { QIcon uacIcon = QApplication::style()->standardIcon(QStyle::SP_VistaShield); ui->uacPushButton->setIcon(uacIcon); } connect(ui->uacPushButton, SIGNAL(clicked()), this, SLOT(restartAsElevated())); } else { ui->uacPushButton->setVisible(false); } } #else ui->uacPushButton->setVisible(false); #endif } MainWindow::~MainWindow() { delete ui; } void MainWindow::alterConfigFromSettings() { if (cmdutility->shouldListControllers()) { this->graphical = graphical = false; } else if (cmdutility->hasProfile()) { if (cmdutility->hasControllerNumber()) { loadConfigFile(cmdutility->getProfileLocation(), cmdutility->getControllerNumber()); } else if (cmdutility->hasControllerID()) { loadConfigFile(cmdutility->getProfileLocation(), cmdutility->hasControllerID()); } else { loadConfigFile(cmdutility->getProfileLocation()); } } QList *tempList = cmdutility->getControllerOptionsList(); //unsigned int optionListSize = tempList->size(); QListIterator optionIter(*tempList); while (optionIter.hasNext()) { ControllerOptionsInfo temp = optionIter.next(); if (temp.hasProfile()) { if (temp.hasControllerNumber()) { loadConfigFile(temp.getProfileLocation(), temp.getControllerNumber()); } else if (temp.hasControllerID()) { loadConfigFile(temp.getProfileLocation(), temp.hasControllerID()); } else { loadConfigFile(temp.getProfileLocation()); } } else if (temp.isUnloadRequested()) { if (temp.hasControllerNumber()) { unloadCurrentConfig(temp.getControllerNumber()); } else if (temp.hasControllerID()) { unloadCurrentConfig(temp.hasControllerID()); } else { unloadCurrentConfig(0); } } if (temp.getStartSetNumber() > 0) { if (temp.hasControllerNumber()) { changeStartSetNumber(temp.getJoyStartSetNumber(), temp.getControllerNumber()); } else if (temp.hasControllerID()) { changeStartSetNumber(temp.getJoyStartSetNumber(), temp.getControllerID()); } else { changeStartSetNumber(temp.getJoyStartSetNumber()); } } } } #ifdef USE_SDL_2 void MainWindow::controllerMapOpening() { if (cmdutility->shouldMapController()) { this->graphical = graphical = false; QList *tempList = cmdutility->getControllerOptionsList(); ControllerOptionsInfo temp = tempList->at(0); if (temp.hasControllerNumber()) { unsigned int joypadIndex = cmdutility->getControllerNumber(); selectControllerJoyTab(joypadIndex); openGameControllerMappingWindow(true); } else if (temp.hasControllerID()) { QString joypadGUID = cmdutility->getControllerID(); selectControllerJoyTab(joypadGUID); openGameControllerMappingWindow(true); } else { Logger::LogInfo(tr("Could not find a proper controller identifier. " "Exiting.")); qApp->quit(); } } } #endif void MainWindow::fillButtons() { fillButtons(joysticks); } void MainWindow::makeJoystickTabs() { ui->stackedWidget->setCurrentIndex(0); removeJoyTabs(); #ifdef USE_SDL_2 // Make temporary QMap with devices inserted using the device index as the // key rather than joystick ID. QMap temp; QMapIterator iterTemp(*joysticks); while (iterTemp.hasNext()) { iterTemp.next(); InputDevice *joystick = iterTemp.value(); temp.insert(joystick->getJoyNumber(), joystick); } QMapIterator iter(temp); #else QMapIterator iter(*joysticks); #endif while (iter.hasNext()) { iter.next(); InputDevice *joystick = iter.value(); JoyTabWidget *tabwidget = new JoyTabWidget(joystick, settings, this); QString joytabName = joystick->getSDLName(); joytabName.append(" ").append(tr("(%1)").arg(joystick->getName())); ui->tabWidget->addTab(tabwidget, joytabName); } if (joysticks > 0) { ui->tabWidget->setCurrentIndex(0); ui->stackedWidget->setCurrentIndex(1); } } void MainWindow::fillButtons(InputDevice *joystick) { int joyindex = joystick->getJoyNumber(); JoyTabWidget *tabwidget = static_cast(ui->tabWidget->widget(joyindex)); tabwidget->refreshButtons(); } void MainWindow::fillButtons(QMap *joysticks) { ui->stackedWidget->setCurrentIndex(0); removeJoyTabs(); #ifdef USE_SDL_2 // Make temporary QMap with devices inserted using the device index as the // key rather than joystick ID. QMap temp; QMapIterator iterTemp(*joysticks); while (iterTemp.hasNext()) { iterTemp.next(); InputDevice *joystick = iterTemp.value(); temp.insert(joystick->getJoyNumber(), joystick); } QMapIterator iter(temp); #else QMapIterator iter(*joysticks); #endif while (iter.hasNext()) { iter.next(); InputDevice *joystick = iter.value(); JoyTabWidget *tabwidget = new JoyTabWidget(joystick, settings, this); QString joytabName = joystick->getSDLName(); joytabName.append(" ").append(tr("(%1)").arg(joystick->getName())); ui->tabWidget->addTab(tabwidget, joytabName); tabwidget->refreshButtons(); connect(tabwidget, SIGNAL(namesDisplayChanged(bool)), this, SLOT(propogateNameDisplayStatus(bool))); #ifdef USE_SDL_2 connect(tabwidget, SIGNAL(mappingUpdated(QString,InputDevice*)), this, SLOT(propogateMappingUpdate(QString,InputDevice*))); #endif if (showTrayIcon) { connect(tabwidget, SIGNAL(joystickConfigChanged(int)), this, SLOT(populateTrayIcon())); } } if (joysticks->size() > 0) { loadAppConfig(); ui->tabWidget->setCurrentIndex(0); ui->stackedWidget->setCurrentIndex(1); } if (showTrayIcon) { trayIcon->hide(); populateTrayIcon(); trayIcon->show(); } ui->actionUpdate_Joysticks->setEnabled(true); ui->actionHide->setEnabled(true); ui->actionQuit->setEnabled(true); } // Intermediate slot to be used in Form Designer void MainWindow::startJoystickRefresh() { ui->stackedWidget->setCurrentIndex(0); ui->actionUpdate_Joysticks->setEnabled(false); ui->actionHide->setEnabled(false); ui->actionQuit->setEnabled(false); removeJoyTabs(); emit joystickRefreshRequested(); } void MainWindow::populateTrayIcon() { disconnect(trayIconMenu, SIGNAL(aboutToShow()), this, SLOT(singleTrayProfileMenuShow())); trayIconMenu->clear(); profileActions.clear(); unsigned int joystickCount = joysticks->size(); if (joystickCount > 0) { QMapIterator iter(*joysticks); bool useSingleList = settings->value("TrayProfileList", false).toBool(); if (!useSingleList && joystickCount == 1) { useSingleList = true; } int i = 0; while (iter.hasNext()) { iter.next(); InputDevice *current = iter.value(); QString joytabName = current->getSDLName(); joytabName.append(" ").append(tr("(%1)").arg(current->getName())); QMenu *joysticksubMenu = 0; if (!useSingleList) { joysticksubMenu = trayIconMenu->addMenu(joytabName); } JoyTabWidget *widget = static_cast(ui->tabWidget->widget(i)); if (widget) { QHash *configs = widget->recentConfigs(); QHashIterator configIter(*configs); QList tempProfileList; while (configIter.hasNext()) { configIter.next(); QAction *newaction = 0; if (joysticksubMenu) { newaction = new QAction(configIter.value(), joysticksubMenu); } else { newaction = new QAction(configIter.value(), trayIconMenu); } newaction->setCheckable(true); newaction->setChecked(false); if (configIter.key() == widget->getCurrentConfigIndex()) { newaction->setChecked(true); } QHash tempmap; tempmap.insert(QString::number(i), QVariant (configIter.key())); QVariant tempvar (tempmap); newaction->setData(tempvar); connect(newaction, SIGNAL(triggered(bool)), this, SLOT(profileTrayActionTriggered(bool))); if (useSingleList) { tempProfileList.append(newaction); } else { joysticksubMenu->addAction(newaction); } } delete configs; configs = 0; QAction *newaction = 0; if (joysticksubMenu) { newaction = new QAction(tr("Open File"), joysticksubMenu); } else { newaction = new QAction(tr("Open File"), trayIconMenu); } newaction->setIcon(QIcon::fromTheme("document-open")); connect(newaction, SIGNAL(triggered()), widget, SLOT(openConfigFileDialog())); if (useSingleList) { QAction *titleAction = new QAction(joytabName, trayIconMenu); titleAction->setCheckable(false); QFont actionFont = titleAction->font(); actionFont.setBold(true); titleAction->setFont(actionFont); trayIconMenu->addAction(titleAction); trayIconMenu->addActions(tempProfileList); trayIconMenu->addAction(newaction); profileActions.insert(i, tempProfileList); if (iter.hasNext()) { trayIconMenu->addSeparator(); } } else { joysticksubMenu->addAction(newaction); connect(joysticksubMenu, SIGNAL(aboutToShow()), this, SLOT(joystickTrayShow())); } i++; } } if (useSingleList) { connect(trayIconMenu, SIGNAL(aboutToShow()), this, SLOT(singleTrayProfileMenuShow())); } trayIconMenu->addSeparator(); } hideAction = new QAction(tr("&Hide"), trayIconMenu); hideAction->setIcon(QIcon::fromTheme("view-restore")); connect(hideAction, SIGNAL(triggered()), this, SLOT(hideWindow())); restoreAction = new QAction(tr("&Restore"), trayIconMenu); restoreAction->setIcon(QIcon::fromTheme("view-fullscreen")); connect(restoreAction, SIGNAL(triggered()), this, SLOT(show())); closeAction = new QAction(tr("&Quit"), trayIconMenu); closeAction->setIcon(QIcon::fromTheme("application-exit")); connect(closeAction, SIGNAL(triggered()), this, SLOT(quitProgram())); updateJoy = new QAction(tr("&Update Joysticks"), trayIconMenu); updateJoy->setIcon(QIcon::fromTheme("view-refresh")); connect(updateJoy, SIGNAL(triggered()), this, SLOT(startJoystickRefresh())); trayIconMenu->addAction(hideAction); trayIconMenu->addAction(restoreAction); trayIconMenu->addAction(updateJoy); trayIconMenu->addAction(closeAction); QIcon icon = QIcon::fromTheme("antimicro", QIcon(":/images/antimicro_trayicon.png")); trayIcon->setIcon(icon); trayIcon->setContextMenu(trayIconMenu); } void MainWindow::quitProgram() { bool discard = true; for (int i=0; i < ui->tabWidget->count() && discard; i++) { JoyTabWidget *tab = static_cast(ui->tabWidget->widget(i)); discard = tab->discardUnsavedProfileChanges(); } if (discard) { qApp->quit(); } } void MainWindow::refreshTrayIconMenu() { if (this->isHidden()) { hideAction->setEnabled(false); restoreAction->setEnabled(true); } else { hideAction->setEnabled(true); restoreAction->setEnabled(false); } } void MainWindow::trayIconClickAction(QSystemTrayIcon::ActivationReason reason) { if (reason == QSystemTrayIcon::Trigger) { if (this->isHidden()) { this->show(); } else { this->hideWindow(); } } } void MainWindow::mainMenuChange() { QMenu *tempMenu = static_cast(sender()); if (tempMenu == ui->menuQuit) { if (showTrayIcon) { ui->actionHide->setEnabled(true); } else { ui->actionHide->setEnabled(false); } } #ifndef USE_SDL_2 if (tempMenu == ui->menuOptions) { ui->actionGameController_Mapping->setVisible(false); } #endif } void MainWindow::saveAppConfig() { if (joysticks->size() > 0) { JoyTabWidget *temptabwidget = static_cast(ui->tabWidget->widget(0)); settings->setValue("DisplayNames", temptabwidget->isDisplayingNames() ? "1" : "0"); settings->beginGroup("Controllers"); QStringList tempIdentifierHolder; for (int i=0; i < ui->tabWidget->count(); i++) { bool prepareSave = true; JoyTabWidget *tabwidget = static_cast(ui->tabWidget->widget(i)); InputDevice *device = tabwidget->getJoystick(); // Do not allow multi-controller adapters to overwrite each // others recent config file list. Use first controller // detected to save recent config list. Flag controller string // afterwards. if (!device->getStringIdentifier().isEmpty()) { if (tempIdentifierHolder.contains(device->getStringIdentifier())) { prepareSave = false; } else { tempIdentifierHolder.append(device->getStringIdentifier()); } } if (prepareSave) { tabwidget->saveSettings(); } } settings->endGroup(); } settings->setValue("WindowSize", size()); settings->setValue("WindowPosition", pos()); } void MainWindow::loadAppConfig(bool forceRefresh) { for (int i=0; i < ui->tabWidget->count(); i++) { JoyTabWidget *tabwidget = static_cast(ui->tabWidget->widget(i)); tabwidget->loadSettings(forceRefresh); } } void MainWindow::disableFlashActions() { for (int i=0; i < ui->tabWidget->count(); i++) { QList list = ui->tabWidget->widget(i)->findChildren(); QListIterator iter(list); while (iter.hasNext()) { JoyButtonWidget *buttonWidget = iter.next(); buttonWidget->disableFlashes(); } QList list2 = ui->tabWidget->widget(i)->findChildren(); QListIterator iter2(list2); while (iter2.hasNext()) { JoyAxisWidget *axisWidget = iter2.next(); axisWidget->disableFlashes(); } QList list3 = ui->tabWidget->widget(i)->findChildren(); QListIterator iter3(list3); while (iter3.hasNext()) { JoyControlStickPushButton *stickWidget = iter3.next(); stickWidget->disableFlashes(); } QList list4 = ui->tabWidget->widget(i)->findChildren(); QListIterator iter4(list4); while (iter4.hasNext()) { JoyDPadButtonWidget *dpadWidget = iter4.next(); dpadWidget->disableFlashes(); } QList list6 = ui->tabWidget->widget(i)->findChildren(); QListIterator iter6(list6); while (iter6.hasNext()) { JoyControlStickButtonPushButton *stickButtonWidget = iter6.next(); stickButtonWidget->disableFlashes(); } QList list7 = ui->tabWidget->widget(i)->findChildren(); QListIterator iter7(list7); while (iter7.hasNext()) { DPadPushButton *dpadWidget = iter7.next(); dpadWidget->disableFlashes(); } JoyTabWidget *tabWidget = static_cast(ui->tabWidget->widget(i)); ui->tabWidget->disableFlashes(tabWidget->getJoystick()); } } void MainWindow::enableFlashActions() { for (int i=0; i < ui->tabWidget->count(); i++) { QList list = ui->tabWidget->widget(i)->findChildren(); QListIterator iter(list); while (iter.hasNext()) { JoyButtonWidget *buttonWidget = iter.next(); buttonWidget->enableFlashes(); buttonWidget->tryFlash(); } QList list2 = ui->tabWidget->widget(i)->findChildren(); QListIterator iter2(list2); while (iter2.hasNext()) { JoyAxisWidget *axisWidget = iter2.next(); axisWidget->enableFlashes(); axisWidget->tryFlash(); } QList list3 = ui->tabWidget->widget(i)->findChildren(); QListIterator iter3(list3); while (iter3.hasNext()) { JoyControlStickPushButton *stickWidget = iter3.next(); stickWidget->enableFlashes(); stickWidget->tryFlash(); } QList list4 = ui->tabWidget->widget(i)->findChildren(); QListIterator iter4(list4); while (iter4.hasNext()) { JoyDPadButtonWidget *dpadWidget = iter4.next(); dpadWidget->enableFlashes(); dpadWidget->tryFlash(); } QList list6 = ui->tabWidget->widget(i)->findChildren(); QListIterator iter6(list6); while (iter6.hasNext()) { JoyControlStickButtonPushButton *stickButtonWidget = iter6.next(); stickButtonWidget->enableFlashes(); stickButtonWidget->tryFlash(); } QList list7 = ui->tabWidget->widget(i)->findChildren(); QListIterator iter7(list7); while (iter7.hasNext()) { DPadPushButton *dpadWidget = iter7.next(); dpadWidget->enableFlashes(); dpadWidget->tryFlash(); } JoyTabWidget *tabWidget = static_cast(ui->tabWidget->widget(i)); ui->tabWidget->enableFlashes(tabWidget->getJoystick()); } } // Intermediate slot used in Design mode void MainWindow::hideWindow() { disableFlashActions(); signalDisconnect = true; hide(); } void MainWindow::joystickTrayShow() { QMenu *tempmenu = static_cast(sender()); QList menuactions = tempmenu->actions(); QListIterator listiter (menuactions); while (listiter.hasNext()) { QAction *action = listiter.next(); action->setChecked(false); QHash tempmap = action->data().toHash(); QHashIterator iter(tempmap); while (iter.hasNext()) { iter.next(); int joyindex = iter.key().toInt(); int configindex = iter.value().toInt(); JoyTabWidget *widget = static_cast(ui->tabWidget->widget(joyindex)); if (configindex == widget->getCurrentConfigIndex()) { action->setChecked(true); if (widget->getJoystick()->isDeviceEdited()) { action->setIcon(QIcon::fromTheme("document-save-as")); } else if (!action->icon().isNull()) { action->setIcon(QIcon()); } } else if (!action->icon().isNull()) { action->setIcon(QIcon()); } if (action->text() != widget->getConfigName(configindex)) { action->setText(widget->getConfigName(configindex)); } } } } void MainWindow::showEvent(QShowEvent *event) { bool propogate = true; // Check if hideEvent has been processed if (signalDisconnect && isVisible()) { // Restore flashing buttons enableFlashActions(); signalDisconnect = false; // Only needed if hidden with the system tray enabled if (showTrayIcon) { if (isMinimized()) { if (isMaximized()) { showMaximized(); } else { showNormal(); } activateWindow(); raise(); } } } if (propogate) { QMainWindow::showEvent(event); } } void MainWindow::changeEvent(QEvent *event) { if (event->type() == QEvent::WindowStateChange) { QWindowStateChangeEvent *e = static_cast(event); if (e->oldState() != Qt::WindowMinimized && isMinimized()) { bool minimizeToTaskbar = settings->value("MinimizeToTaskbar", false).toBool(); if (QSystemTrayIcon::isSystemTrayAvailable() && showTrayIcon && !minimizeToTaskbar) { this->hideWindow(); } else { disableFlashActions(); signalDisconnect = true; } } } else if (event->type() == QEvent::LanguageChange) { retranslateUi(); } QMainWindow::changeEvent(event); } void MainWindow::openAboutDialog() { aboutDialog->show(); } void MainWindow::loadConfigFile(QString fileLocation, int joystickIndex) { if (joystickIndex > 0 && joysticks->contains(joystickIndex-1)) { JoyTabWidget *widget = static_cast(ui->tabWidget->widget(joystickIndex-1)); if (widget) { widget->loadConfigFile(fileLocation); } } else if (joystickIndex <= 0) { for (int i=0; i < ui->tabWidget->count(); i++) { JoyTabWidget *widget = static_cast(ui->tabWidget->widget(i)); if (widget) { widget->loadConfigFile(fileLocation); } } } } void MainWindow::loadConfigFile(QString fileLocation, QString controllerID) { if (!controllerID.isEmpty()) { QListIterator iter(ui->tabWidget->findChildren()); while (iter.hasNext()) { JoyTabWidget *tab = iter.next(); if (tab) { InputDevice *tempdevice = tab->getJoystick(); if (controllerID == tempdevice->getStringIdentifier()) { tab->loadConfigFile(fileLocation); } } } } } void MainWindow::removeJoyTabs() { int oldtabcount = ui->tabWidget->count(); for (int i = oldtabcount-1; i >= 0; i--) { QWidget *tab = ui->tabWidget->widget(i); delete tab; tab = 0; } ui->tabWidget->clear(); } void MainWindow::handleInstanceDisconnect() { settings->sync(); loadAppConfig(true); } void MainWindow::openJoystickStatusWindow() { int index = ui->tabWidget->currentIndex(); if (index >= 0) { JoyTabWidget *joyTab = static_cast(ui->tabWidget->widget(index)); InputDevice *joystick = joyTab->getJoystick(); if (joystick) { JoystickStatusWindow *dialog = new JoystickStatusWindow(joystick, this); dialog->show(); } } } void MainWindow::openKeyCheckerDialog() { QKeyDisplayDialog *dialog = new QKeyDisplayDialog(this); dialog->show(); } void MainWindow::openGitHubPage() { QDesktopServices::openUrl(QUrl(PadderCommon::githubProjectPage)); } void MainWindow::openWikiPage() { QDesktopServices::openUrl(QUrl(PadderCommon::wikiPage)); } void MainWindow::unloadCurrentConfig(int joystickIndex) { if (joystickIndex > 0 && joysticks->contains(joystickIndex-1)) { JoyTabWidget *widget = static_cast (ui->tabWidget->widget(joystickIndex-1)); if (widget) { widget->unloadConfig(); } } else if (joystickIndex <= 0) { for (int i=0; i < ui->tabWidget->count(); i++) { JoyTabWidget *widget = static_cast (ui->tabWidget->widget(i)); if (widget) { widget->unloadConfig(); } } } } void MainWindow::unloadCurrentConfig(QString controllerID) { if (!controllerID.isEmpty()) { QListIterator iter(ui->tabWidget->findChildren()); while (iter.hasNext()) { JoyTabWidget *tab = iter.next(); if (tab) { InputDevice *tempdevice = tab->getJoystick(); if (controllerID == tempdevice->getStringIdentifier()) { tab->unloadConfig(); } } } } } void MainWindow::propogateNameDisplayStatus(bool displayNames) { JoyTabWidget *tabwidget = static_cast(sender()); for (int i=0; i < ui->tabWidget->count(); i++) { JoyTabWidget *tab = static_cast(ui->tabWidget->widget(i)); if (tab && tab != tabwidget) { if (tab->isDisplayingNames() != displayNames) { tab->changeNameDisplay(displayNames); } } } } void MainWindow::changeStartSetNumber(unsigned int startSetNumber, QString controllerID) { if (!controllerID.isEmpty()) { QListIterator iter(ui->tabWidget->findChildren()); while (iter.hasNext()) { JoyTabWidget *tab = iter.next(); if (tab) { InputDevice *tempdevice = tab->getJoystick(); if (controllerID == tempdevice->getStringIdentifier()) { tab->changeCurrentSet(startSetNumber); } } } } } void MainWindow::changeStartSetNumber(unsigned int startSetNumber, unsigned int joystickIndex) { if (joystickIndex > 0 && joysticks->contains(joystickIndex-1)) { JoyTabWidget *widget = static_cast(ui->tabWidget->widget(joystickIndex-1)); if (widget) { widget->changeCurrentSet(startSetNumber); } } else if (joystickIndex <= 0) { for (int i=0; i < ui->tabWidget->count(); i++) { JoyTabWidget *widget = static_cast(ui->tabWidget->widget(i)); if (widget) { widget->changeCurrentSet(startSetNumber); } } } } /** * @brief Build list of current input devices and pass it to settings dialog * instance. Open Settings dialog. */ void MainWindow::openMainSettingsDialog() { QList *devices = new QList(joysticks->values()); MainSettingsDialog *dialog = new MainSettingsDialog(settings, devices, this); connect(dialog, SIGNAL(changeLanguage(QString)), this, SLOT(changeLanguage(QString))); if (appWatcher) { #if defined(USE_SDL_2) && defined(Q_OS_UNIX) && defined(WITH_X11) #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif connect(dialog, SIGNAL(accepted()), appWatcher, SLOT(syncProfileAssignment())); connect(dialog, SIGNAL(accepted()), this, SLOT(checkAutoProfileWatcherTimer())); connect(dialog, SIGNAL(rejected()), this, SLOT(checkAutoProfileWatcherTimer())); appWatcher->stopTimer(); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #elif defined(USE_SDL_2) && defined(Q_OS_WIN) connect(dialog, SIGNAL(accepted()), appWatcher, SLOT(syncProfileAssignment())); connect(dialog, SIGNAL(accepted()), this, SLOT(checkAutoProfileWatcherTimer())); connect(dialog, SIGNAL(rejected()), this, SLOT(checkAutoProfileWatcherTimer())); appWatcher->stopTimer(); #endif } connect(dialog, SIGNAL(accepted()), this, SLOT(populateTrayIcon())); connect(dialog, SIGNAL(accepted()), this, SLOT(checkHideEmptyOption())); #ifdef Q_OS_WIN connect(dialog, SIGNAL(accepted()), this, SLOT(checkKeyRepeatOptions())); #endif dialog->show(); } /** * @brief Change language used by the application. * @param Language code */ void MainWindow::changeLanguage(QString language) { if (translator && appTranslator) { PadderCommon::reloadTranslations(translator, appTranslator, language); } } /** * @brief Check if the program should really quit or if it should * be minimized. * @param QCloseEvent */ void MainWindow::closeEvent(QCloseEvent *event) { bool closeToTray = settings->value("CloseToTray", false).toBool(); if (closeToTray && QSystemTrayIcon::isSystemTrayAvailable() && showTrayIcon) { this->hideWindow(); } else { qApp->quit(); } QMainWindow::closeEvent(event); } /** * @brief Show abstracted controller dialog for use in SDL 1.2. No longer * used for versions of the program running SDL 2. In SDL 2, * the Game Controller API is being used instead. */ void MainWindow::showStickAssignmentDialog() { int index = ui->tabWidget->currentIndex(); if (index >= 0) { JoyTabWidget *joyTab = static_cast(ui->tabWidget->widget(index)); Joystick *joystick = static_cast(joyTab->getJoystick()); AdvanceStickAssignmentDialog *dialog = new AdvanceStickAssignmentDialog(joystick, this); connect(dialog, SIGNAL(finished(int)), joyTab, SLOT(fillButtons())); dialog->show(); } } /** * @brief Display a version of the tray menu that shows all recent profiles for * all controllers in one list. */ void MainWindow::singleTrayProfileMenuShow() { if (!profileActions.isEmpty()) { QMapIterator > mapIter(profileActions); while (mapIter.hasNext()) { mapIter.next(); QList menuactions = mapIter.value(); QListIterator listiter (menuactions); while (listiter.hasNext()) { QAction *action = listiter.next(); action->setChecked(false); QHash tempmap = action->data().toHash(); QHashIterator iter(tempmap); while (iter.hasNext()) { iter.next(); int joyindex = iter.key().toInt(); int configindex = iter.value().toInt(); JoyTabWidget *widget = static_cast(ui->tabWidget->widget(joyindex)); if (configindex == widget->getCurrentConfigIndex()) { action->setChecked(true); if (widget->getJoystick()->isDeviceEdited()) { action->setIcon(QIcon::fromTheme("document-save-as")); } else if (!action->icon().isNull()) { action->setIcon(QIcon()); } } else if (!action->icon().isNull()) { action->setIcon(QIcon()); } if (action->text() != widget->getConfigName(configindex)) { action->setText(widget->getConfigName(configindex)); } } } } } } void MainWindow::profileTrayActionTriggered(bool checked) { // Obtaining the selected config QAction *action = static_cast(sender()); QHash tempmap = action->data().toHash(); QHashIterator iter(tempmap); while (iter.hasNext()) { iter.next(); // Fetching indicies and tab associated with the current joypad int joyindex = iter.key().toInt(); int configindex = iter.value().toInt(); JoyTabWidget *widget = static_cast(ui->tabWidget->widget(joyindex)); // Checking if the selected config has been disabled by the change (action->isChecked() represents the state of the checkbox AFTER the click) if (!checked) { // It has - disabling - the 0th config is the new/'null' config widget->setCurrentConfig(0); } else { // It hasn't - enabling - note that setting this causes the menu to be updated widget->setCurrentConfig(configindex); } } } void MainWindow::checkHideEmptyOption() { for (int i=0; i < ui->tabWidget->count(); i++) { JoyTabWidget *tab = static_cast(ui->tabWidget->widget(i)); if (tab) { tab->checkHideEmptyOption(); } } } #ifdef Q_OS_WIN void MainWindow::checkKeyRepeatOptions() { for (int i=0; i < ui->tabWidget->count(); i++) { JoyTabWidget *tab = static_cast(ui->tabWidget->widget(i)); tab->deviceKeyRepeatSettings(); } } /** * @brief Check if user really wants to restart the program with elevated * privileges. If yes, attempt to restart the program. */ void MainWindow::restartAsElevated() { QMessageBox msg; msg.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msg.setWindowTitle(tr("Run as Administrator?")); msg.setText(tr("Are you sure that you want to run this program as Adminstrator?" "\n\n" "Some games run as Administrator which will cause events generated by antimicro " "to not be used by those games unless antimicro is also run " "as the Adminstrator. " "This is due to permission problems caused by User Account " "Control (UAC) options in Windows Vista and later.")); if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA) { QIcon uacIcon = QApplication::style()->standardIcon(QStyle::SP_VistaShield); msg.button(QMessageBox::Yes)->setIcon(uacIcon); } int result = msg.exec(); if (result == QMessageBox::Yes) { bool result = WinExtras::elevateAntiMicro(); if (result) { qApp->quit(); } else { msg.setStandardButtons(QMessageBox::Close); msg.setWindowTitle(tr("Failed to elevate program")); msg.setText(tr("Failed to restart this program as the Administrator")); msg.exec(); } } } #endif #ifdef USE_SDL_2 void MainWindow::openGameControllerMappingWindow(bool openAsMain) { int index = ui->tabWidget->currentIndex(); if (index >= 0) { JoyTabWidget *joyTab = static_cast(ui->tabWidget->widget(index)); InputDevice *joystick = joyTab->getJoystick(); if (joystick) { GameControllerMappingDialog *dialog = new GameControllerMappingDialog(joystick, settings, this); if (openAsMain) { dialog->setParent(0); dialog->setWindowFlags(Qt::Window); connect(dialog, SIGNAL(finished(int)), qApp, SLOT(quit())); } else { connect(dialog, SIGNAL(mappingUpdate(QString,InputDevice*)), this, SLOT(propogateMappingUpdate(QString, InputDevice*))); } dialog->show(); } } else if (openAsMain) { Logger::LogInfo(tr("Could not find controller. Exiting.")); qApp->quit(); } } void MainWindow::propogateMappingUpdate(QString mapping, InputDevice *device) { emit mappingUpdated(mapping, device); } void MainWindow::testMappingUpdateNow(int index, InputDevice *device) { QWidget *tab = ui->tabWidget->widget(index); if (tab) { ui->tabWidget->removeTab(index); delete tab; tab = 0; } JoyTabWidget *tabwidget = new JoyTabWidget(device, settings, this); QString joytabName = device->getSDLName(); joytabName.append(" ").append(tr("(%1)").arg(device->getName())); ui->tabWidget->insertTab(index, tabwidget, joytabName); tabwidget->refreshButtons(); ui->tabWidget->setCurrentIndex(index); connect(tabwidget, SIGNAL(namesDisplayChanged(bool)), this, SLOT(propogateNameDisplayStatus(bool))); connect(tabwidget, SIGNAL(mappingUpdated(QString,InputDevice*)), this, SLOT(propogateMappingUpdate(QString,InputDevice*))); if (showTrayIcon) { connect(tabwidget, SIGNAL(joystickConfigChanged(int)), this, SLOT(populateTrayIcon())); trayIcon->hide(); populateTrayIcon(); trayIcon->show(); } } void MainWindow::removeJoyTab(SDL_JoystickID deviceID) { bool found = false; for (int i=0; i < ui->tabWidget->count() && !found; i++) { JoyTabWidget *tab = static_cast(ui->tabWidget->widget(i)); if (tab && deviceID == tab->getJoystick()->getSDLJoystickID()) { // Save most recent profile list to settings before removing tab. tab->saveDeviceSettings(); // Remove flash event connections between buttons and // the tab before deleting tab. ui->tabWidget->disableFlashes(tab->getJoystick()); ui->tabWidget->removeTab(i); QMetaObject::invokeMethod(tab->getJoystick(), "finalRemoval"); delete tab; tab = 0; found = true; } } // Refresh tab text to reflect new index values. for (int i=0; i < ui->tabWidget->count(); i++) { JoyTabWidget *tab = static_cast(ui->tabWidget->widget(i)); if (tab) { InputDevice *device = tab->getJoystick(); QString joytabName = device->getSDLName(); joytabName.append(" ").append(tr("(%1)").arg(device->getName())); ui->tabWidget->setTabText(i, joytabName); } } if (showTrayIcon) { trayIcon->hide(); populateTrayIcon(); trayIcon->show(); } if (ui->tabWidget->count() == 0) { ui->stackedWidget->setCurrentIndex(0); } } void MainWindow::addJoyTab(InputDevice *device) { JoyTabWidget *tabwidget = new JoyTabWidget(device, settings, this); QString joytabName = device->getSDLName(); joytabName.append(" ").append(tr("(%1)").arg(device->getName())); ui->tabWidget->addTab(tabwidget, joytabName); tabwidget->loadDeviceSettings(); tabwidget->refreshButtons(); // Refresh tab text to reflect new index values. for (int i=0; i < ui->tabWidget->count(); i++) { JoyTabWidget *tab = static_cast(ui->tabWidget->widget(i)); if (tab) { InputDevice *device = tab->getJoystick(); QString joytabName = device->getSDLName(); joytabName.append(" ").append(tr("(%1)").arg(device->getName())); ui->tabWidget->setTabText(i, joytabName); } } connect(tabwidget, SIGNAL(namesDisplayChanged(bool)), this, SLOT(propogateNameDisplayStatus(bool))); connect(tabwidget, SIGNAL(mappingUpdated(QString,InputDevice*)), this, SLOT(propogateMappingUpdate(QString,InputDevice*))); if (showTrayIcon) { connect(tabwidget, SIGNAL(joystickConfigChanged(int)), this, SLOT(populateTrayIcon())); trayIcon->hide(); populateTrayIcon(); trayIcon->show(); } ui->stackedWidget->setCurrentIndex(1); } void MainWindow::autoprofileLoad(AutoProfileInfo *info) { if( info != NULL ) { Logger::LogDebug(QObject::tr("Auto-switching to profile \"%1\"."). arg(info->getProfileLocation())); } else { Logger::LogError(QObject::tr("Auto-switching to NULL profile!")); } #if defined(USE_SDL_2) && (defined(WITH_X11) || defined(Q_OS_WIN)) #if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif for (int i = 0; i < ui->tabWidget->count(); i++) { JoyTabWidget *widget = static_cast(ui->tabWidget->widget(i)); if (widget) { if (info->getGUID() == "all") { // If the all option for a Default profile was found, // first check for controller specific associations. If one exists, // skip changing the profile on the controller. A later call will // be used to switch the profile for that controller. QList *customs = appWatcher->getCustomDefaults(); bool found = false; QListIterator iter(*customs); while (iter.hasNext()) { AutoProfileInfo *tempinfo = iter.next(); if (tempinfo->getGUID() == widget->getJoystick()->getGUIDString() && info->isCurrentDefault()) { found = true; iter.toBack(); } } delete customs; customs = 0; // Check if profile has already been switched for a particular // controller. if (!found) { QString tempguid = widget->getJoystick()->getGUIDString(); if (appWatcher->isGUIDLocked(tempguid)) { found = true; } } if (!found) { // If the profile location is empty, assume // that an empty profile should get loaded. if (info->getProfileLocation().isEmpty()) { widget->setCurrentConfig(0); } else { widget->loadConfigFile(info->getProfileLocation()); } } } else if (info->getGUID() == widget->getJoystick()->getStringIdentifier()) { if (info->getProfileLocation().isEmpty()) { widget->setCurrentConfig(0); } else { widget->loadConfigFile(info->getProfileLocation()); } } } } #if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #endif } void MainWindow::checkAutoProfileWatcherTimer() { #if defined(USE_SDL_2) && (defined(WITH_X11) || defined(Q_OS_WIN)) #if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif QString autoProfileActive = settings->value("AutoProfiles/AutoProfilesActive", "0").toString(); if (autoProfileActive == "1") { appWatcher->startTimer(); } else { appWatcher->stopTimer(); } #if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #endif } /** * @brief TODO: Check if method is save to remove. */ void MainWindow::updateMenuOptions() { int index = ui->tabWidget->currentIndex(); if (index >= 0) { JoyTabWidget *joyTab = static_cast(ui->tabWidget->widget(index)); InputDevice *joystick = joyTab->getJoystick(); if (qobject_cast(joystick) != 0) { ui->actionStick_Pad_Assign->setEnabled(false); } else { ui->actionStick_Pad_Assign->setEnabled(true); } } } /** * @brief Select appropriate tab with the specified index. * @param Index of appropriate tab. */ void MainWindow::selectControllerJoyTab(unsigned int index) { if (index > 0 && joysticks->contains(index-1)) { JoyTabWidget *widget = static_cast (ui->tabWidget->widget(index-1)); if (widget) { ui->tabWidget->setCurrentIndex(index-1); } } } /** * @brief Select appropriate tab that has a device with the specified GUID. * @param GUID of joystick device. */ void MainWindow::selectControllerJoyTab(QString GUID) { if (!GUID.isEmpty()) { InputDevice *device = 0; QMapIterator deviceIter(*joysticks); while (deviceIter.hasNext()) { deviceIter.next(); InputDevice *tempDevice = deviceIter.value(); if (tempDevice && GUID == tempDevice->getStringIdentifier()) { device = tempDevice; deviceIter.toBack(); } } if (device) { ui->tabWidget->setCurrentIndex(device->getJoyNumber()); } } } #endif void MainWindow::changeWindowStatus() { // Check flags to see if user requested for the main window and the tray icon // to not be displayed. if (graphical) { bool launchInTraySetting = settings->runtimeValue("LaunchInTray", false).toBool(); if (!cmdutility->isHiddenRequested() && (!launchInTraySetting || !QSystemTrayIcon::isSystemTrayAvailable())) { show(); } else if (cmdutility->isHiddenRequested() && cmdutility->isTrayHidden()) { // Window should already be hidden but make sure // to disable flashing buttons. hideWindow(); setEnabled(false); // Should already be disabled. Do it again just to be sure. } else if (cmdutility->isHiddenRequested() || launchInTraySetting) { // Window should already be hidden but make sure // to disable flashing buttons. hideWindow(); } } } bool MainWindow::getGraphicalStatus() { return graphical; } void MainWindow::setTranslator(QTranslator *translator) { this->translator = translator; } QTranslator* MainWindow::getTranslator() { return translator; } void MainWindow::setAppTranslator(QTranslator *translator) { this->appTranslator = translator; } QTranslator* MainWindow::getAppTranslator() { return appTranslator; } void MainWindow::retranslateUi() { ui->retranslateUi(this); } void MainWindow::refreshTabHelperThreads() { for (int i=0; i < ui->tabWidget->count(); i++) { JoyTabWidget *widget = static_cast(ui->tabWidget->widget(i)); if (widget) { widget->refreshHelperThread(); } } } antimicro-2.23/src/mainwindow.h000066400000000000000000000116031300750276700165510ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include #include #include #include #include #include #include #include #include "inputdevice.h" #include "aboutdialog.h" #include "commandlineutility.h" #include "antimicrosettings.h" #include "autoprofilewatcher.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QMap *joysticks, CommandLineUtility *cmdutility, AntiMicroSettings *settings, bool graphical=true, QWidget *parent = 0); ~MainWindow(); bool getGraphicalStatus(); void setTranslator(QTranslator *translator); QTranslator* getTranslator(); void setAppTranslator(QTranslator *translator); QTranslator* getAppTranslator(); protected: virtual void showEvent(QShowEvent *event); virtual void changeEvent(QEvent *event); virtual void closeEvent(QCloseEvent *event); void retranslateUi(); void loadConfigFile(QString fileLocation, int joystickIndex=0); void loadConfigFile(QString fileLocation, QString controllerID); void unloadCurrentConfig(int joystickIndex=0); void unloadCurrentConfig(QString controllerID); void changeStartSetNumber(unsigned int startSetNumber, QString controllerID); void changeStartSetNumber(unsigned int startSetNumber, unsigned int joystickIndex=0); QMap *joysticks; QSystemTrayIcon *trayIcon; QAction *hideAction; QAction *restoreAction; QAction *closeAction; QAction *updateJoy; QMenu *trayIconMenu; QMap > profileActions; AboutDialog *aboutDialog; bool signalDisconnect; bool showTrayIcon; bool graphical; QLocalServer *localServer; CommandLineUtility *cmdutility; AntiMicroSettings *settings; QTranslator *translator; QTranslator *appTranslator; AutoProfileWatcher *appWatcher; private: Ui::MainWindow *ui; signals: void joystickRefreshRequested(); void readConfig(int index); #ifdef USE_SDL_2 void mappingUpdated(QString mapping, InputDevice *device); #endif public slots: void fillButtons(); void makeJoystickTabs(); void alterConfigFromSettings(); void fillButtons(InputDevice *joystick); void fillButtons(QMap *joysticks); void startJoystickRefresh(); void hideWindow(); void saveAppConfig(); void loadAppConfig(bool forceRefresh=false); void removeJoyTabs(); void quitProgram(); void changeWindowStatus(); void refreshTabHelperThreads(); #ifdef USE_SDL_2 void controllerMapOpening(); void testMappingUpdateNow(int index, InputDevice *device); void removeJoyTab(SDL_JoystickID deviceID); void addJoyTab(InputDevice *device); void selectControllerJoyTab(QString GUID); void selectControllerJoyTab(unsigned int index); #endif private slots: void refreshTrayIconMenu(); void trayIconClickAction(QSystemTrayIcon::ActivationReason reason); void mainMenuChange(); void disableFlashActions(); void enableFlashActions(); void joystickTrayShow(); void singleTrayProfileMenuShow(); void profileTrayActionTriggered(bool checked); void populateTrayIcon(); void openAboutDialog(); void handleInstanceDisconnect(); void openJoystickStatusWindow(); void openKeyCheckerDialog(); void openGitHubPage(); void openWikiPage(); void propogateNameDisplayStatus(bool displayNames); void changeLanguage(QString language); void openMainSettingsDialog(); void showStickAssignmentDialog(); void checkHideEmptyOption(); #ifdef Q_OS_WIN void checkKeyRepeatOptions(); void restartAsElevated(); #endif #ifdef USE_SDL_2 void openGameControllerMappingWindow(bool openAsMain=false); void propogateMappingUpdate(QString mapping, InputDevice *device); void autoprofileLoad(AutoProfileInfo *info); void checkAutoProfileWatcherTimer(); void updateMenuOptions(); #endif }; #endif // MAINWINDOW_H antimicro-2.23/src/mainwindow.ui000066400000000000000000000263301300750276700167420ustar00rootroot00000000000000 MainWindow Qt::WindowModal 0 0 650 580 650 0 antimicro :/images/antimicro.png:/images/antimicro.png JoyButtonWidget[isflashing="true"], JoyAxisWidget[isflashing="true"], JoyControlStickPushButton[isflashing="true"], JoyControlStickButtonPushButton[isflashing="true"], DPadPushButton[isflashing="true"] { background-color: rgb(0, 0, 255); color: rgb(205, 197, 191); } QPushButton#setPushButton1[setActive="false"], QPushButton#setPushButton2[setActive="false"], QPushButton#setPushButton3[setActive="false"], QPushButton#setPushButton4[setActive="false"], QPushButton#setPushButton5[setActive="false"], QPushButton#setPushButton6[setActive="false"], QPushButton#setPushButton7[setActive="false"], QPushButton#setPushButton8[setActive="false"] { background-color: rgb(190, 190, 190); } QStackedWidget#stackedWidget{ padding-top: 10px; } QPushButton#namesPushButton[isDisplayingNames="true"] { background-color: rgb(192, 255, 192); } 4 0 0 0 0 QFrame::NoFrame QFrame::Plain 1 0 No Joysticks have been found. Please plug in a joystick and then choose the "Update Joysticks" option in the main menu true Qt::AlignCenter true 0 0 0 true 0 0 Qt::LeftToRight QTabWidget::North QTabWidget::Rounded -1 true false false false If events are not seen by a game, please click here to run this application as Administrator. false false false 0 0 650 21 &App &Options &Help &Quit Ctrl+Q true &Update Joysticks Ctrl+U &Hide Ctrl+H &About Ctrl+A About Qt Properties Key Checker Home Page GitHub Page Game Controller Mapping Settings Stick/Pad Assign Wiki JoyTabWidgetContainer QTabWidget
joytabwidgetcontainer.h
1
actionQuit triggered() MainWindow quitProgram() -1 -1 199 149 actionUpdate_Joysticks triggered() MainWindow startJoystickRefresh() -1 -1 349 262 actionHide triggered() MainWindow hideWindow() -1 -1 349 262 actionAbout triggered() MainWindow openAboutDialog() -1 -1 349 262 actionStick_Pad_Assign triggered() MainWindow showStickAssignmentDialog() -1 -1 324 289 startJoystickRefresh() hideWindow() openAboutDialog() quitProgram() showStickAssignmentDialog()
antimicro-2.23/src/mousedialog/000077500000000000000000000000001300750276700165335ustar00rootroot00000000000000antimicro-2.23/src/mousedialog/mouseaxissettingsdialog.cpp000066400000000000000000000317061300750276700242240ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "mouseaxissettingsdialog.h" #include "ui_mousesettingsdialog.h" #include #include #include #include MouseAxisSettingsDialog::MouseAxisSettingsDialog(JoyAxis *axis, QWidget *parent) : MouseSettingsDialog(parent), helper(axis) { setAttribute(Qt::WA_DeleteOnClose); this->axis = axis; helper.moveToThread(axis->thread()); calculateMouseSpeedPreset(); selectCurrentMouseModePreset(); calculateSpringPreset(); if (axis->getButtonsPresetSensitivity() > 0.0) { ui->sensitivityDoubleSpinBox->setValue(axis->getButtonsPresetSensitivity()); } updateAccelerationCurvePresetComboBox(); updateWindowTitleAxisName(); if (ui->mouseModeComboBox->currentIndex() == 2) { springPreviewWidget = new SpringModeRegionPreview(ui->springWidthSpinBox->value(), ui->springHeightSpinBox->value()); } else { springPreviewWidget = new SpringModeRegionPreview(0, 0); } calculateWheelSpeedPreset(); if (axis->isRelativeSpring()) { ui->relativeSpringCheckBox->setChecked(true); } double easingDuration = axis->getButtonsEasingDuration(); ui->easingDoubleSpinBox->setValue(easingDuration); calculateExtraAccelrationStatus(); calculateExtraAccelerationMultiplier(); calculateStartAccelerationMultiplier(); calculateMinAccelerationThreshold(); calculateMaxAccelerationThreshold(); calculateAccelExtraDuration(); calculateReleaseSpringRadius(); calculateExtraAccelerationCurve(); changeSpringSectionStatus(ui->mouseModeComboBox->currentIndex()); changeSettingsWidgetStatus(ui->accelerationComboBox->currentIndex()); connect(this, SIGNAL(finished(int)), springPreviewWidget, SLOT(deleteLater())); connect(ui->mouseModeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeMouseMode(int))); connect(ui->accelerationComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeMouseCurve(int))); connect(ui->horizontalSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateConfigHorizontalSpeed(int))); connect(ui->verticalSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateConfigVerticalSpeed(int))); connect(ui->springWidthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateSpringWidth(int))); connect(ui->springWidthSpinBox, SIGNAL(valueChanged(int)), springPreviewWidget, SLOT(setSpringWidth(int))); connect(ui->springHeightSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateSpringHeight(int))); connect(ui->springHeightSpinBox, SIGNAL(valueChanged(int)), springPreviewWidget, SLOT(setSpringHeight(int))); connect(ui->relativeSpringCheckBox, SIGNAL(clicked(bool)), this, SLOT(updateSpringRelativeStatus(bool))); connect(ui->sensitivityDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(updateSensitivity(double))); connect(ui->wheelHoriSpeedSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateWheelSpeedHorizontalSpeed(int))); connect(ui->wheelVertSpeedSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateWheelSpeedVerticalSpeed(int))); connect(ui->easingDoubleSpinBox, SIGNAL(valueChanged(double)), axis, SLOT(setButtonsEasingDuration(double))); connect(ui->extraAccelerationGroupBox, SIGNAL(clicked(bool)), &helper, SLOT(updateExtraAccelerationStatus(bool))); connect(ui->extraAccelDoubleSpinBox, SIGNAL(valueChanged(double)), &helper, SLOT(updateExtraAccelerationMultiplier(double))); connect(ui->minMultiDoubleSpinBox, SIGNAL(valueChanged(double)), &helper, SLOT(updateStartMultiPercentage(double))); connect(ui->minThresholdDoubleSpinBox, SIGNAL(valueChanged(double)), &helper, SLOT(updateMinAccelThreshold(double))); connect(ui->maxThresholdDoubleSpinBox, SIGNAL(valueChanged(double)), &helper, SLOT(updateMaxAccelThreshold(double))); connect(ui->accelExtraDurationDoubleSpinBox, SIGNAL(valueChanged(double)), &helper, SLOT(updateAccelExtraDuration(double))); connect(ui->releaseSpringRadiusspinBox, SIGNAL(valueChanged(int)), &helper, SLOT(updateReleaseSpringRadius(int))); connect(ui->extraAccelCurveComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateExtraAccelerationCurve(int))); } void MouseAxisSettingsDialog::changeMouseMode(int index) { if (index == 1) { axis->setButtonsMouseMode(JoyButton::MouseCursor); if (springPreviewWidget->isVisible()) { springPreviewWidget->hide(); } } else if (index == 2) { axis->setButtonsMouseMode(JoyButton::MouseSpring); if (!springPreviewWidget->isVisible()) { springPreviewWidget->setSpringWidth(ui->springWidthSpinBox->value()); springPreviewWidget->setSpringHeight(ui->springHeightSpinBox->value()); } axis->getPAxisButton()->setExtraAccelerationStatus(false); axis->getNAxisButton()->setExtraAccelerationStatus(false); } } void MouseAxisSettingsDialog::changeMouseCurve(int index) { JoyButton::JoyMouseCurve temp = MouseSettingsDialog::getMouseCurveForIndex(index); axis->setButtonsMouseCurve(temp); } void MouseAxisSettingsDialog::updateConfigHorizontalSpeed(int value) { axis->getPAxisButton()->setMouseSpeedX(value); axis->getNAxisButton()->setMouseSpeedX(value); } void MouseAxisSettingsDialog::updateConfigVerticalSpeed(int value) { axis->getPAxisButton()->setMouseSpeedY(value); axis->getNAxisButton()->setMouseSpeedY(value); } void MouseAxisSettingsDialog::updateSpringWidth(int value) { axis->setButtonsSpringWidth(value); } void MouseAxisSettingsDialog::updateSpringHeight(int value) { axis->setButtonsSpringHeight(value); } void MouseAxisSettingsDialog::selectCurrentMouseModePreset() { bool presetDefined = axis->hasSameButtonsMouseMode(); if (presetDefined) { JoyButton::JoyMouseMovementMode mode = axis->getButtonsPresetMouseMode(); if (mode == JoyButton::MouseCursor) { ui->mouseModeComboBox->setCurrentIndex(1); } else if (mode == JoyButton::MouseSpring) { ui->mouseModeComboBox->setCurrentIndex(2); } } else { ui->mouseModeComboBox->setCurrentIndex(0); } } void MouseAxisSettingsDialog::calculateSpringPreset() { int tempWidth = axis->getButtonsPresetSpringWidth(); int tempHeight = axis->getButtonsPresetSpringHeight(); if (tempWidth > 0) { ui->springWidthSpinBox->setValue(tempWidth); } if (tempHeight > 0) { ui->springHeightSpinBox->setValue(tempHeight); } } void MouseAxisSettingsDialog::calculateMouseSpeedPreset() { int tempMouseSpeedX = 0; tempMouseSpeedX = qMax(axis->getPAxisButton()->getMouseSpeedX(), axis->getNAxisButton()->getMouseSpeedX()); int tempMouseSpeedY = 0; tempMouseSpeedY = qMax(axis->getPAxisButton()->getMouseSpeedY(), axis->getNAxisButton()->getMouseSpeedY()); ui->horizontalSpinBox->setValue(tempMouseSpeedX); ui->verticalSpinBox->setValue(tempMouseSpeedY); } void MouseAxisSettingsDialog::updateSensitivity(double value) { axis->setButtonsSensitivity(value); } void MouseAxisSettingsDialog::updateAccelerationCurvePresetComboBox() { JoyButton::JoyMouseCurve temp = axis->getButtonsPresetMouseCurve(); MouseSettingsDialog::updateAccelerationCurvePresetComboBox(temp); } void MouseAxisSettingsDialog::calculateWheelSpeedPreset() { JoyAxisButton *paxisbutton = axis->getPAxisButton(); JoyAxisButton *naxisbutton = axis->getNAxisButton(); int tempWheelSpeedX = qMax(paxisbutton->getWheelSpeedX(), naxisbutton->getWheelSpeedX()); int tempWheelSpeedY = qMax(paxisbutton->getWheelSpeedY(), naxisbutton->getWheelSpeedY()); ui->wheelHoriSpeedSpinBox->setValue(tempWheelSpeedX); ui->wheelVertSpeedSpinBox->setValue(tempWheelSpeedY); } void MouseAxisSettingsDialog::updateWheelSpeedHorizontalSpeed(int value) { axis->setButtonsWheelSpeedX(value); } void MouseAxisSettingsDialog::updateWheelSpeedVerticalSpeed(int value) { axis->setButtonsWheelSpeedY(value); } void MouseAxisSettingsDialog::updateSpringRelativeStatus(bool value) { axis->setButtonsSpringRelativeStatus(value); } void MouseAxisSettingsDialog::updateWindowTitleAxisName() { QString temp; temp.append(tr("Mouse Settings - ")); if (!axis->getAxisName().isEmpty()) { temp.append(axis->getPartialName(false, true)); } else { temp.append(axis->getPartialName()); } if (axis->getParentSet()->getIndex() != 0) { unsigned int setIndex = axis->getParentSet()->getRealIndex(); temp.append(" [").append(tr("Set %1").arg(setIndex)); QString setName = axis->getParentSet()->getName(); if (!setName.isEmpty()) { temp.append(": ").append(setName); } temp.append("]"); } setWindowTitle(temp); } void MouseAxisSettingsDialog::calculateExtraAccelrationStatus() { if (axis->getPAxisButton()->isExtraAccelerationEnabled() && axis->getNAxisButton()->isExtraAccelerationEnabled()) { ui->extraAccelerationGroupBox->setChecked(true); //ui->extraAccelCheckBox->setChecked(true); //ui->extraAccelDoubleSpinBox->setEnabled(true); } else { ui->extraAccelerationGroupBox->setChecked(false); } } void MouseAxisSettingsDialog::calculateExtraAccelerationMultiplier() { if (axis->getPAxisButton()->getExtraAccelerationMultiplier() == axis->getNAxisButton()->getExtraAccelerationMultiplier()) { double temp = axis->getPAxisButton()->getExtraAccelerationMultiplier(); ui->extraAccelDoubleSpinBox->setValue(temp); } } void MouseAxisSettingsDialog::calculateStartAccelerationMultiplier() { if (axis->getPAxisButton()->getStartAccelMultiplier() == axis->getNAxisButton()->getStartAccelMultiplier()) { double temp = axis->getPAxisButton()->getStartAccelMultiplier(); ui->minMultiDoubleSpinBox->setValue(temp); } } void MouseAxisSettingsDialog::calculateMinAccelerationThreshold() { if (axis->getPAxisButton()->getMinAccelThreshold() == axis->getNAxisButton()->getMinAccelThreshold()) { double temp = axis->getPAxisButton()->getMinAccelThreshold(); ui->minThresholdDoubleSpinBox->setValue(temp); } } void MouseAxisSettingsDialog::calculateMaxAccelerationThreshold() { if (axis->getPAxisButton()->getMaxAccelThreshold() == axis->getNAxisButton()->getMaxAccelThreshold()) { double temp = axis->getPAxisButton()->getMaxAccelThreshold(); ui->maxThresholdDoubleSpinBox->setValue(temp); } } void MouseAxisSettingsDialog::calculateAccelExtraDuration() { if (axis->getPAxisButton()->getAccelExtraDuration() == axis->getNAxisButton()->getAccelExtraDuration()) { double temp = axis->getPAxisButton()->getAccelExtraDuration(); ui->accelExtraDurationDoubleSpinBox->setValue(temp); } } void MouseAxisSettingsDialog::calculateReleaseSpringRadius() { int result = 0; if (axis->getPAxisButton()->getSpringDeadCircleMultiplier() == axis->getNAxisButton()->getSpringDeadCircleMultiplier()) { result = axis->getPAxisButton()->getSpringDeadCircleMultiplier(); } ui->releaseSpringRadiusspinBox->setValue(result); } void MouseAxisSettingsDialog::updateExtraAccelerationCurve(int index) { JoyButton::JoyExtraAccelerationCurve temp = getExtraAccelCurveForIndex(index); if (index > 0) { InputDevice *device = axis->getParentSet()->getInputDevice(); //PadderCommon::lockInputDevices(); //QMetaObject::invokeMethod(device, "haltServices", Qt::BlockingQueuedConnection); PadderCommon::inputDaemonMutex.lock(); axis->getPAxisButton()->setExtraAccelerationCurve(temp); axis->getNAxisButton()->setExtraAccelerationCurve(temp); PadderCommon::inputDaemonMutex.unlock(); //PadderCommon::unlockInputDevices(); } } void MouseAxisSettingsDialog::calculateExtraAccelerationCurve() { if (axis->getPAxisButton()->getExtraAccelerationCurve() == axis->getNAxisButton()->getExtraAccelerationCurve()) { JoyButton::JoyExtraAccelerationCurve temp = axis->getPAxisButton()->getExtraAccelerationCurve(); updateExtraAccelerationCurvePresetComboBox(temp); } } antimicro-2.23/src/mousedialog/mouseaxissettingsdialog.h000066400000000000000000000047241300750276700236710ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MOUSEAXISSETTINGSDIALOG_H #define MOUSEAXISSETTINGSDIALOG_H #include "mousesettingsdialog.h" #include "springmoderegionpreview.h" #include #include "uihelpers/mouseaxissettingsdialoghelper.h" class MouseAxisSettingsDialog : public MouseSettingsDialog { Q_OBJECT public: explicit MouseAxisSettingsDialog(JoyAxis *axis, QWidget *parent = 0); protected: void selectCurrentMouseModePreset(); void calculateSpringPreset(); void calculateMouseSpeedPreset(); //void selectSmoothingPreset(); void calculateWheelSpeedPreset(); void updateWindowTitleAxisName(); void calculateExtraAccelrationStatus(); void calculateExtraAccelerationMultiplier(); void calculateStartAccelerationMultiplier(); void calculateMinAccelerationThreshold(); void calculateMaxAccelerationThreshold(); void calculateAccelExtraDuration(); void calculateReleaseSpringRadius(); void calculateExtraAccelerationCurve(); JoyAxis *axis; SpringModeRegionPreview *springPreviewWidget; MouseAxisSettingsDialogHelper helper; signals: public slots: void changeMouseMode(int index); void changeMouseCurve(int index); void updateConfigHorizontalSpeed(int value); void updateConfigVerticalSpeed(int value); void updateSpringWidth(int value); void updateSpringHeight(int value); void updateSensitivity(double value); void updateAccelerationCurvePresetComboBox(); //void updateSmoothingSetting(bool clicked); void updateWheelSpeedHorizontalSpeed(int value); void updateWheelSpeedVerticalSpeed(int value); void updateSpringRelativeStatus(bool value); private slots: void updateExtraAccelerationCurve(int index); }; #endif // MOUSEAXISSETTINGSDIALOG_H antimicro-2.23/src/mousedialog/mousebuttonsettingsdialog.cpp000066400000000000000000000227731300750276700245770ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "mousebuttonsettingsdialog.h" #include "ui_mousesettingsdialog.h" #include #include #include #include #include MouseButtonSettingsDialog::MouseButtonSettingsDialog(JoyButton *button, QWidget *parent) : MouseSettingsDialog(parent), helper(button) { setAttribute(Qt::WA_DeleteOnClose); resize(size().width(), 450); //setGeometry(geometry().x(), geometry().y(), size().width(), 450); this->button = button; helper.moveToThread(button->thread()); calculateMouseSpeedPreset(); selectCurrentMouseModePreset(); calculateSpringPreset(); if (button->getSensitivity() > 0.0) { ui->sensitivityDoubleSpinBox->setValue(button->getSensitivity()); } updateAccelerationCurvePresetComboBox(); updateWindowTitleButtonName(); if (ui->mouseModeComboBox->currentIndex() == 2) { springPreviewWidget = new SpringModeRegionPreview(ui->springWidthSpinBox->value(), ui->springHeightSpinBox->value()); } else { springPreviewWidget = new SpringModeRegionPreview(0, 0); } ui->wheelHoriSpeedSpinBox->setValue(button->getWheelSpeedX()); ui->wheelVertSpeedSpinBox->setValue(button->getWheelSpeedY()); if (button->isRelativeSpring()) { ui->relativeSpringCheckBox->setChecked(true); } double easingDuration = button->getEasingDuration(); ui->easingDoubleSpinBox->setValue(easingDuration); if (button->isPartRealAxis()) { ui->extraAccelerationGroupBox->setChecked(button->isExtraAccelerationEnabled()); ui->extraAccelDoubleSpinBox->setValue(button->getExtraAccelerationMultiplier()); ui->minMultiDoubleSpinBox->setValue(button->getStartAccelMultiplier()); ui->minThresholdDoubleSpinBox->setValue(button->getMinAccelThreshold()); ui->maxThresholdDoubleSpinBox->setValue(button->getMaxAccelThreshold()); ui->accelExtraDurationDoubleSpinBox->setValue(button->getAccelExtraDuration()); } else { ui->extraAccelerationGroupBox->setVisible(false); } ui->releaseSpringRadiusspinBox->setValue(button->getSpringDeadCircleMultiplier()); calculateExtraAccelerationCurve(); changeSpringSectionStatus(ui->mouseModeComboBox->currentIndex()); changeSettingsWidgetStatus(ui->accelerationComboBox->currentIndex()); connect(this, SIGNAL(finished(int)), springPreviewWidget, SLOT(deleteLater())); connect(ui->mouseModeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeMouseMode(int))); connect(ui->accelerationComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeMouseCurve(int))); connect(ui->horizontalSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateConfigHorizontalSpeed(int))); connect(ui->verticalSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateConfigVerticalSpeed(int))); connect(ui->springWidthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateSpringWidth(int))); connect(ui->springWidthSpinBox, SIGNAL(valueChanged(int)), springPreviewWidget, SLOT(setSpringWidth(int))); connect(ui->springHeightSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateSpringHeight(int))); connect(ui->springHeightSpinBox, SIGNAL(valueChanged(int)), springPreviewWidget, SLOT(setSpringHeight(int))); connect(ui->relativeSpringCheckBox, SIGNAL(clicked(bool)), &helper, SLOT(updateSpringRelativeStatus(bool))); connect(ui->sensitivityDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(updateSensitivity(double))); connect(ui->wheelHoriSpeedSpinBox, SIGNAL(valueChanged(int)), button, SLOT(setWheelSpeedX(int))); connect(ui->wheelVertSpeedSpinBox, SIGNAL(valueChanged(int)), button, SLOT(setWheelSpeedY(int))); connect(ui->easingDoubleSpinBox, SIGNAL(valueChanged(double)), button, SLOT(setEasingDuration(double))); connect(ui->extraAccelerationGroupBox, SIGNAL(clicked(bool)), &helper, SLOT(updateExtraAccelerationStatus(bool))); connect(ui->extraAccelDoubleSpinBox, SIGNAL(valueChanged(double)), &helper, SLOT(updateExtraAccelerationMultiplier(double))); connect(ui->minMultiDoubleSpinBox, SIGNAL(valueChanged(double)), &helper, SLOT(updateStartMultiPercentage(double))); connect(ui->minThresholdDoubleSpinBox, SIGNAL(valueChanged(double)), &helper, SLOT(updateMinAccelThreshold(double))); connect(ui->maxThresholdDoubleSpinBox, SIGNAL(valueChanged(double)), &helper, SLOT(updateMaxAccelThreshold(double))); connect(ui->accelExtraDurationDoubleSpinBox, SIGNAL(valueChanged(double)), &helper, SLOT(updateAccelExtraDuration(double))); connect(ui->releaseSpringRadiusspinBox, SIGNAL(valueChanged(int)), &helper, SLOT(updateReleaseSpringRadius(int))); connect(ui->extraAccelCurveComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateExtraAccelerationCurve(int))); } void MouseButtonSettingsDialog::changeMouseMode(int index) { if (index == 1) { button->setMouseMode(JoyButton::MouseCursor); if (springPreviewWidget->isVisible()) { springPreviewWidget->hide(); } } else if (index == 2) { button->setMouseMode(JoyButton::MouseSpring); if (!springPreviewWidget->isVisible()) { springPreviewWidget->setSpringWidth(ui->springWidthSpinBox->value()); springPreviewWidget->setSpringHeight(ui->springHeightSpinBox->value()); } if (button->isPartRealAxis()) { button->setExtraAccelerationStatus(false); } } } void MouseButtonSettingsDialog::changeMouseCurve(int index) { JoyButton::JoyMouseCurve temp = MouseSettingsDialog::getMouseCurveForIndex(index); button->setMouseCurve(temp); } void MouseButtonSettingsDialog::updateConfigHorizontalSpeed(int value) { QMetaObject::invokeMethod(button, "setMouseSpeedX", Q_ARG(int, value)); } void MouseButtonSettingsDialog::updateConfigVerticalSpeed(int value) { QMetaObject::invokeMethod(button, "setMouseSpeedY", Q_ARG(int, value)); } void MouseButtonSettingsDialog::updateSpringWidth(int value) { QMetaObject::invokeMethod(button, "setSpringWidth", Q_ARG(int, value)); } void MouseButtonSettingsDialog::updateSpringHeight(int value) { QMetaObject::invokeMethod(button, "setSpringHeight", Q_ARG(int, value)); } void MouseButtonSettingsDialog::selectCurrentMouseModePreset() { JoyButton::JoyMouseMovementMode mode = button->getMouseMode(); if (mode == JoyButton::MouseCursor) { ui->mouseModeComboBox->setCurrentIndex(1); } else if (mode == JoyButton::MouseSpring) { ui->mouseModeComboBox->setCurrentIndex(2); } } void MouseButtonSettingsDialog::calculateSpringPreset() { int tempWidth = button->getSpringWidth(); int tempHeight = button->getSpringHeight(); if (tempWidth > 0) { ui->springWidthSpinBox->setValue(tempWidth); } if (tempHeight > 0) { ui->springHeightSpinBox->setValue(tempHeight); } } void MouseButtonSettingsDialog::calculateMouseSpeedPreset() { int tempMouseSpeedX = button->getMouseSpeedX(); int tempMouseSpeedY = button->getMouseSpeedY(); ui->horizontalSpinBox->setValue(tempMouseSpeedX); ui->verticalSpinBox->setValue(tempMouseSpeedY); } void MouseButtonSettingsDialog::updateSensitivity(double value) { button->setSensitivity(value); } void MouseButtonSettingsDialog::updateAccelerationCurvePresetComboBox() { JoyButton::JoyMouseCurve temp = button->getMouseCurve(); MouseSettingsDialog::updateAccelerationCurvePresetComboBox(temp); } /*void MouseButtonSettingsDialog::updateSpringRelativeStatus(bool value) { button->setSpringRelativeStatus(value); } */ void MouseButtonSettingsDialog::updateWindowTitleButtonName() { QString temp; temp.append(tr("Mouse Settings - ")).append(button->getPartialName(false, true)); if (button->getParentSet()->getIndex() != 0) { unsigned int setIndex = button->getParentSet()->getRealIndex(); temp.append(" [").append(tr("Set %1").arg(setIndex)); QString setName = button->getParentSet()->getName(); if (!setName.isEmpty()) { temp.append(": ").append(setName); } temp.append("]"); } setWindowTitle(temp); } void MouseButtonSettingsDialog::calculateExtraAccelerationCurve() { JoyButton::JoyExtraAccelerationCurve temp = button->getExtraAccelerationCurve(); updateExtraAccelerationCurvePresetComboBox(temp); } void MouseButtonSettingsDialog::updateExtraAccelerationCurve(int index) { JoyButton::JoyExtraAccelerationCurve temp = getExtraAccelCurveForIndex(index); if (index > 0) { PadderCommon::inputDaemonMutex.lock(); button->setExtraAccelerationCurve(temp); button->setExtraAccelerationCurve(temp); PadderCommon::inputDaemonMutex.unlock(); } } antimicro-2.23/src/mousedialog/mousebuttonsettingsdialog.h000066400000000000000000000037241300750276700242370ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MOUSEBUTTONSETTINGSDIALOG_H #define MOUSEBUTTONSETTINGSDIALOG_H #include "mousesettingsdialog.h" #include "springmoderegionpreview.h" #include #include "uihelpers/mousebuttonsettingsdialoghelper.h" class MouseButtonSettingsDialog : public MouseSettingsDialog { Q_OBJECT public: explicit MouseButtonSettingsDialog(JoyButton *button, QWidget *parent = 0); protected: void selectCurrentMouseModePreset(); void calculateSpringPreset(); void calculateMouseSpeedPreset(); void updateWindowTitleButtonName(); void calculateExtraAccelerationCurve(); JoyButton *button; SpringModeRegionPreview *springPreviewWidget; MouseButtonSettingsDialogHelper helper; signals: public slots: void changeMouseMode(int index); void changeMouseCurve(int index); void updateConfigHorizontalSpeed(int value); void updateConfigVerticalSpeed(int value); void updateSpringWidth(int value); void updateSpringHeight(int value); void updateSensitivity(double value); void updateAccelerationCurvePresetComboBox(); //void updateSpringRelativeStatus(bool value); private slots: void updateExtraAccelerationCurve(int index); }; #endif // MOUSEBUTTONSETTINGSDIALOG_H antimicro-2.23/src/mousedialog/mousecontrolsticksettingsdialog.cpp000066400000000000000000000304561300750276700257770ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "mousecontrolsticksettingsdialog.h" #include "ui_mousesettingsdialog.h" #include #include #include #include MouseControlStickSettingsDialog::MouseControlStickSettingsDialog(JoyControlStick *stick, QWidget *parent) : MouseSettingsDialog(parent), helper(stick) { setAttribute(Qt::WA_DeleteOnClose); this->stick = stick; helper.moveToThread(stick->thread()); calculateMouseSpeedPreset(); selectCurrentMouseModePreset(); calculateSpringPreset(); if (stick->getButtonsPresetSensitivity() > 0.0) { ui->sensitivityDoubleSpinBox->setValue(stick->getButtonsPresetSensitivity()); } updateAccelerationCurvePresetComboBox(); updateWindowTitleStickName(); if (ui->mouseModeComboBox->currentIndex() == 2) { springPreviewWidget = new SpringModeRegionPreview(ui->springWidthSpinBox->value(), ui->springHeightSpinBox->value()); } else { springPreviewWidget = new SpringModeRegionPreview(0, 0); } calculateWheelSpeedPreset(); if (stick->isRelativeSpring()) { ui->relativeSpringCheckBox->setChecked(true); } double easingDuration = stick->getButtonsEasingDuration(); ui->easingDoubleSpinBox->setValue(easingDuration); calculateExtraAccelrationStatus(); calculateExtraAccelerationMultiplier(); calculateStartAccelerationMultiplier(); calculateMinAccelerationThreshold(); calculateMaxAccelerationThreshold(); calculateAccelExtraDuration(); calculateReleaseSpringRadius(); calculateExtraAccelerationCurve(); changeSpringSectionStatus(ui->mouseModeComboBox->currentIndex()); changeSettingsWidgetStatus(ui->accelerationComboBox->currentIndex()); connect(this, SIGNAL(finished(int)), springPreviewWidget, SLOT(deleteLater())); connect(ui->mouseModeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeMouseMode(int))); connect(ui->accelerationComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeMouseCurve(int))); connect(ui->horizontalSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateConfigHorizontalSpeed(int))); connect(ui->verticalSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateConfigVerticalSpeed(int))); connect(ui->springWidthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateSpringWidth(int))); connect(ui->springWidthSpinBox, SIGNAL(valueChanged(int)), springPreviewWidget, SLOT(setSpringWidth(int))); connect(ui->springHeightSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateSpringHeight(int))); connect(ui->springHeightSpinBox, SIGNAL(valueChanged(int)), springPreviewWidget, SLOT(setSpringHeight(int))); connect(ui->relativeSpringCheckBox, SIGNAL(clicked(bool)), this, SLOT(updateSpringRelativeStatus(bool))); connect(ui->sensitivityDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(updateSensitivity(double))); connect(ui->wheelHoriSpeedSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateWheelSpeedHorizontalSpeed(int))); connect(ui->wheelVertSpeedSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateWheelSpeedVerticalSpeed(int))); connect(ui->easingDoubleSpinBox, SIGNAL(valueChanged(double)), stick, SLOT(setButtonsEasingDuration(double))); connect(ui->extraAccelerationGroupBox, SIGNAL(clicked(bool)), &helper, SLOT(updateExtraAccelerationStatus(bool))); connect(ui->extraAccelDoubleSpinBox, SIGNAL(valueChanged(double)), &helper, SLOT(updateExtraAccelerationMultiplier(double))); connect(ui->minMultiDoubleSpinBox, SIGNAL(valueChanged(double)), &helper, SLOT(updateStartMultiPercentage(double))); connect(ui->minThresholdDoubleSpinBox, SIGNAL(valueChanged(double)), &helper, SLOT(updateMinAccelThreshold(double))); connect(ui->maxThresholdDoubleSpinBox, SIGNAL(valueChanged(double)), &helper, SLOT(updateMaxAccelThreshold(double))); connect(ui->accelExtraDurationDoubleSpinBox, SIGNAL(valueChanged(double)), &helper, SLOT(updateAccelExtraDuration(double))); connect(ui->releaseSpringRadiusspinBox, SIGNAL(valueChanged(int)), &helper, SLOT(updateReleaseSpringRadius(int))); connect(ui->extraAccelCurveComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateExtraAccelerationCurve(int))); } void MouseControlStickSettingsDialog::changeMouseMode(int index) { if (index == 1) { stick->setButtonsMouseMode(JoyButton::MouseCursor); if (springPreviewWidget->isVisible()) { springPreviewWidget->hide(); } } else if (index == 2) { stick->setButtonsMouseMode(JoyButton::MouseSpring); if (!springPreviewWidget->isVisible()) { springPreviewWidget->setSpringWidth(ui->springWidthSpinBox->value()); springPreviewWidget->setSpringHeight(ui->springHeightSpinBox->value()); } stick->setButtonsExtraAccelerationStatus(false); } } void MouseControlStickSettingsDialog::changeMouseCurve(int index) { JoyButton::JoyMouseCurve temp = MouseSettingsDialog::getMouseCurveForIndex(index); stick->setButtonsMouseCurve(temp); } void MouseControlStickSettingsDialog::updateConfigHorizontalSpeed(int value) { QHashIterator iter(*stick->getButtons()); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); button->setMouseSpeedX(value); } } void MouseControlStickSettingsDialog::updateConfigVerticalSpeed(int value) { QHashIterator iter(*stick->getButtons()); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); button->setMouseSpeedY(value); } } void MouseControlStickSettingsDialog::updateSpringWidth(int value) { stick->setButtonsSpringWidth(value); } void MouseControlStickSettingsDialog::updateSpringHeight(int value) { stick->setButtonsSpringHeight(value); } void MouseControlStickSettingsDialog::selectCurrentMouseModePreset() { bool presetDefined = stick->hasSameButtonsMouseMode(); if (presetDefined) { JoyButton::JoyMouseMovementMode mode = stick->getButtonsPresetMouseMode(); if (mode == JoyButton::MouseCursor) { ui->mouseModeComboBox->setCurrentIndex(1); } else if (mode == JoyButton::MouseSpring) { ui->mouseModeComboBox->setCurrentIndex(2); } } else { ui->mouseModeComboBox->setCurrentIndex(0); } } void MouseControlStickSettingsDialog::calculateSpringPreset() { int tempWidth = stick->getButtonsPresetSpringWidth(); int tempHeight = stick->getButtonsPresetSpringHeight(); if (tempWidth > 0) { ui->springWidthSpinBox->setValue(tempWidth); } if (tempHeight > 0) { ui->springHeightSpinBox->setValue(tempHeight); } } void MouseControlStickSettingsDialog::calculateMouseSpeedPreset() { QHashIterator iter(*stick->getButtons()); int tempMouseSpeedX = 0; while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); tempMouseSpeedX = qMax(tempMouseSpeedX, button->getMouseSpeedX()); } iter.toFront(); int tempMouseSpeedY = 0; while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); tempMouseSpeedY = qMax(tempMouseSpeedY, button->getMouseSpeedY()); } ui->horizontalSpinBox->setValue(tempMouseSpeedX); ui->verticalSpinBox->setValue(tempMouseSpeedY); } void MouseControlStickSettingsDialog::updateSensitivity(double value) { stick->setButtonsSensitivity(value); } void MouseControlStickSettingsDialog::updateAccelerationCurvePresetComboBox() { JoyButton::JoyMouseCurve temp = stick->getButtonsPresetMouseCurve(); MouseSettingsDialog::updateAccelerationCurvePresetComboBox(temp); } void MouseControlStickSettingsDialog::calculateWheelSpeedPreset() { QHashIterator iter(*stick->getButtons()); int tempWheelSpeedX = 0; int tempWheelSpeedY = 0; while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); tempWheelSpeedX = qMax(tempWheelSpeedX, button->getWheelSpeedX()); tempWheelSpeedY = qMax(tempWheelSpeedY, button->getWheelSpeedY()); } ui->wheelHoriSpeedSpinBox->setValue(tempWheelSpeedX); ui->wheelVertSpeedSpinBox->setValue(tempWheelSpeedY); } void MouseControlStickSettingsDialog::updateWheelSpeedHorizontalSpeed(int value) { stick->setButtonsWheelSpeedX(value); } void MouseControlStickSettingsDialog::updateWheelSpeedVerticalSpeed(int value) { stick->setButtonsWheelSpeedY(value); } void MouseControlStickSettingsDialog::updateSpringRelativeStatus(bool value) { stick->setButtonsSpringRelativeStatus(value); } void MouseControlStickSettingsDialog::updateWindowTitleStickName() { QString temp = QString(tr("Mouse Settings")).append(" - "); if (!stick->getStickName().isEmpty()) { temp.append(stick->getPartialName(false, true)); } else { temp.append(stick->getPartialName()); } if (stick->getParentSet()->getIndex() != 0) { unsigned int setIndex = stick->getParentSet()->getRealIndex(); temp.append(" [").append(tr("Set %1").arg(setIndex)); QString setName = stick->getParentSet()->getName(); if (!setName.isEmpty()) { temp.append(": ").append(setName); } temp.append("]"); } setWindowTitle(temp); } void MouseControlStickSettingsDialog::calculateExtraAccelrationStatus() { if (stick->getButtonsExtraAccelerationStatus()) { ui->extraAccelerationGroupBox->setChecked(true); } } void MouseControlStickSettingsDialog::calculateExtraAccelerationMultiplier() { ui->extraAccelDoubleSpinBox->setValue(stick->getButtonsExtraAccelerationMultiplier()); } void MouseControlStickSettingsDialog::calculateStartAccelerationMultiplier() { ui->minMultiDoubleSpinBox->setValue(stick->getButtonsStartAccelerationMultiplier()); } void MouseControlStickSettingsDialog::calculateMinAccelerationThreshold() { ui->minThresholdDoubleSpinBox->setValue(stick->getButtonsMinAccelerationThreshold()); } void MouseControlStickSettingsDialog::calculateMaxAccelerationThreshold() { ui->maxThresholdDoubleSpinBox->setValue(stick->getButtonsMaxAccelerationThreshold()); } void MouseControlStickSettingsDialog::calculateAccelExtraDuration() { ui->accelExtraDurationDoubleSpinBox->setValue(stick->getButtonsAccelerationEasingDuration()); } void MouseControlStickSettingsDialog::calculateReleaseSpringRadius() { ui->releaseSpringRadiusspinBox->setValue(stick->getButtonsSpringDeadCircleMultiplier()); } void MouseControlStickSettingsDialog::calculateExtraAccelerationCurve() { JoyButton::JoyExtraAccelerationCurve curve = stick->getButtonsExtraAccelerationCurve(); updateExtraAccelerationCurvePresetComboBox(curve); } void MouseControlStickSettingsDialog::updateExtraAccelerationCurve(int index) { JoyButton::JoyExtraAccelerationCurve temp = getExtraAccelCurveForIndex(index); if (index > 0) { //PadderCommon::lockInputDevices(); //InputDevice *device = stick->getParentSet()->getInputDevice(); //QMetaObject::invokeMethod(device, "haltServices", Qt::BlockingQueuedConnection); PadderCommon::inputDaemonMutex.lock(); stick->setButtonsExtraAccelCurve(temp); PadderCommon::inputDaemonMutex.unlock(); //PadderCommon::unlockInputDevices(); } } antimicro-2.23/src/mousedialog/mousecontrolsticksettingsdialog.h000066400000000000000000000047251300750276700254440ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MOUSECONTROLSTICKSETTINGSDIALOG_H #define MOUSECONTROLSTICKSETTINGSDIALOG_H #include "mousesettingsdialog.h" #include "springmoderegionpreview.h" #include #include "uihelpers/mousecontrolsticksettingsdialoghelper.h" class MouseControlStickSettingsDialog : public MouseSettingsDialog { Q_OBJECT public: explicit MouseControlStickSettingsDialog(JoyControlStick *stick, QWidget *parent=0); protected: void selectCurrentMouseModePreset(); void calculateSpringPreset(); void calculateMouseSpeedPreset(); void calculateWheelSpeedPreset(); void updateWindowTitleStickName(); void calculateExtraAccelrationStatus(); void calculateExtraAccelerationMultiplier(); void calculateStartAccelerationMultiplier(); void calculateMinAccelerationThreshold(); void calculateMaxAccelerationThreshold(); void calculateAccelExtraDuration(); void calculateReleaseSpringRadius(); void calculateExtraAccelerationCurve(); JoyControlStick *stick; SpringModeRegionPreview *springPreviewWidget; MouseControlStickSettingsDialogHelper helper; signals: public slots: void changeMouseMode(int index); void changeMouseCurve(int index); void updateConfigHorizontalSpeed(int value); void updateConfigVerticalSpeed(int value); void updateSpringWidth(int value); void updateSpringHeight(int value); void updateSensitivity(double value); void updateAccelerationCurvePresetComboBox(); void updateWheelSpeedHorizontalSpeed(int value); void updateWheelSpeedVerticalSpeed(int value); void updateSpringRelativeStatus(bool value); private slots: void updateExtraAccelerationCurve(int index); }; #endif // MOUSECONTROLSTICKSETTINGSDIALOG_H antimicro-2.23/src/mousedialog/mousedpadsettingsdialog.cpp000066400000000000000000000245451300750276700241730ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "mousedpadsettingsdialog.h" #include "ui_mousesettingsdialog.h" #include #include #include #include MouseDPadSettingsDialog::MouseDPadSettingsDialog(JoyDPad *dpad, QWidget *parent) : MouseSettingsDialog(parent), helper(dpad) { setAttribute(Qt::WA_DeleteOnClose); resize(size().width(), 450); //setGeometry(geometry().x(), geometry().y(), size().width(), 450); this->dpad = dpad; helper.moveToThread(dpad->thread()); calculateMouseSpeedPreset(); selectCurrentMouseModePreset(); calculateSpringPreset(); if (dpad->getButtonsPresetSensitivity() > 0.0) { ui->sensitivityDoubleSpinBox->setValue(dpad->getButtonsPresetSensitivity()); } updateAccelerationCurvePresetComboBox(); updateWindowTitleDPadName(); if (ui->mouseModeComboBox->currentIndex() == 2) { springPreviewWidget = new SpringModeRegionPreview(ui->springWidthSpinBox->value(), ui->springHeightSpinBox->value()); } else { springPreviewWidget = new SpringModeRegionPreview(0, 0); } calculateWheelSpeedPreset(); if (dpad->isRelativeSpring()) { ui->relativeSpringCheckBox->setChecked(true); } double easingDuration = dpad->getButtonsEasingDuration(); ui->easingDoubleSpinBox->setValue(easingDuration); ui->extraAccelerationGroupBox->setVisible(false); calculateReleaseSpringRadius(); calculateExtraAccelerationCurve(); changeSpringSectionStatus(ui->mouseModeComboBox->currentIndex()); changeSettingsWidgetStatus(ui->accelerationComboBox->currentIndex()); connect(this, SIGNAL(finished(int)), springPreviewWidget, SLOT(deleteLater())); connect(ui->mouseModeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeMouseMode(int))); connect(ui->accelerationComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeMouseCurve(int))); connect(ui->horizontalSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateConfigHorizontalSpeed(int))); connect(ui->verticalSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateConfigVerticalSpeed(int))); connect(ui->springWidthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateSpringWidth(int))); connect(ui->springWidthSpinBox, SIGNAL(valueChanged(int)), springPreviewWidget, SLOT(setSpringWidth(int))); connect(ui->springHeightSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateSpringHeight(int))); connect(ui->springHeightSpinBox, SIGNAL(valueChanged(int)), springPreviewWidget, SLOT(setSpringHeight(int))); connect(ui->relativeSpringCheckBox, SIGNAL(clicked(bool)), this, SLOT(updateSpringRelativeStatus(bool))); connect(ui->sensitivityDoubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(updateSensitivity(double))); connect(ui->wheelHoriSpeedSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateWheelSpeedHorizontalSpeed(int))); connect(ui->wheelVertSpeedSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateWheelSpeedVerticalSpeed(int))); connect(ui->easingDoubleSpinBox, SIGNAL(valueChanged(double)), dpad, SLOT(setButtonsEasingDuration(double))); connect(ui->releaseSpringRadiusspinBox, SIGNAL(valueChanged(int)), this, SLOT(updateReleaseSpringRadius(int))); connect(ui->extraAccelCurveComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateExtraAccelerationCurve(int))); JoyButtonMouseHelper *mouseHelper = JoyButton::getMouseHelper(); connect(mouseHelper, SIGNAL(mouseCursorMoved(int,int,int)), this, SLOT(updateMouseCursorStatusLabels(int,int,int))); connect(mouseHelper, SIGNAL(mouseSpringMoved(int,int)), this, SLOT(updateMouseSpringStatusLabels(int,int))); lastMouseStatUpdate.start(); } void MouseDPadSettingsDialog::changeMouseMode(int index) { if (index == 1) { dpad->setButtonsMouseMode(JoyButton::MouseCursor); if (springPreviewWidget->isVisible()) { springPreviewWidget->hide(); } } else if (index == 2) { dpad->setButtonsMouseMode(JoyButton::MouseSpring); if (!springPreviewWidget->isVisible()) { springPreviewWidget->setSpringWidth(ui->springWidthSpinBox->value()); springPreviewWidget->setSpringHeight(ui->springHeightSpinBox->value()); } } } void MouseDPadSettingsDialog::changeMouseCurve(int index) { JoyButton::JoyMouseCurve temp = MouseSettingsDialog::getMouseCurveForIndex(index); dpad->setButtonsMouseCurve(temp); } void MouseDPadSettingsDialog::updateConfigHorizontalSpeed(int value) { QHashIterator iter(*dpad->getButtons()); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); button->setMouseSpeedX(value); } } void MouseDPadSettingsDialog::updateConfigVerticalSpeed(int value) { QHashIterator iter(*dpad->getButtons()); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); button->setMouseSpeedY(value); } } void MouseDPadSettingsDialog::updateSpringWidth(int value) { dpad->setButtonsSpringWidth(value); } void MouseDPadSettingsDialog::updateSpringHeight(int value) { dpad->setButtonsSpringHeight(value); } void MouseDPadSettingsDialog::selectCurrentMouseModePreset() { bool presetDefined = dpad->hasSameButtonsMouseMode(); if (presetDefined) { JoyButton::JoyMouseMovementMode mode = dpad->getButtonsPresetMouseMode(); if (mode == JoyButton::MouseCursor) { ui->mouseModeComboBox->setCurrentIndex(1); } else if (mode == JoyButton::MouseSpring) { ui->mouseModeComboBox->setCurrentIndex(2); } } else { ui->mouseModeComboBox->setCurrentIndex(0); } } void MouseDPadSettingsDialog::calculateSpringPreset() { int tempWidth = dpad->getButtonsPresetSpringWidth(); int tempHeight = dpad->getButtonsPresetSpringHeight(); if (tempWidth > 0) { ui->springWidthSpinBox->setValue(tempWidth); } if (tempHeight > 0) { ui->springHeightSpinBox->setValue(tempHeight); } } void MouseDPadSettingsDialog::calculateMouseSpeedPreset() { QHashIterator iter(*dpad->getButtons()); int tempMouseSpeedX = 0; while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); tempMouseSpeedX = qMax(tempMouseSpeedX, button->getMouseSpeedX()); } iter.toFront(); int tempMouseSpeedY = 0; while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); tempMouseSpeedY = qMax(tempMouseSpeedY, button->getMouseSpeedY()); } ui->horizontalSpinBox->setValue(tempMouseSpeedX); ui->verticalSpinBox->setValue(tempMouseSpeedY); } void MouseDPadSettingsDialog::updateSensitivity(double value) { dpad->setButtonsSensitivity(value); } void MouseDPadSettingsDialog::updateAccelerationCurvePresetComboBox() { JoyButton::JoyMouseCurve temp = dpad->getButtonsPresetMouseCurve(); MouseSettingsDialog::updateAccelerationCurvePresetComboBox(temp); } void MouseDPadSettingsDialog::calculateWheelSpeedPreset() { QHashIterator iter(*dpad->getButtons()); int tempWheelSpeedX = 0; int tempWheelSpeedY = 0; while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); tempWheelSpeedX = qMax(tempWheelSpeedX, button->getWheelSpeedX()); tempWheelSpeedY = qMax(tempWheelSpeedY, button->getWheelSpeedY()); } ui->wheelHoriSpeedSpinBox->setValue(tempWheelSpeedX); ui->wheelVertSpeedSpinBox->setValue(tempWheelSpeedY); } void MouseDPadSettingsDialog::updateWheelSpeedHorizontalSpeed(int value) { dpad->setButtonsWheelSpeedX(value); } void MouseDPadSettingsDialog::updateWheelSpeedVerticalSpeed(int value) { dpad->setButtonsWheelSpeedY(value); } void MouseDPadSettingsDialog::updateSpringRelativeStatus(bool value) { dpad->setButtonsSpringRelativeStatus(value); } void MouseDPadSettingsDialog::updateWindowTitleDPadName() { QString temp = QString(tr("Mouse Settings")).append(" - "); if (!dpad->getDpadName().isEmpty()) { temp.append(dpad->getName(false, true)); } else { temp.append(dpad->getName()); } if (dpad->getParentSet()->getIndex() != 0) { unsigned int setIndex = dpad->getParentSet()->getRealIndex(); temp.append(" [").append(tr("Set %1").arg(setIndex)); QString setName = dpad->getParentSet()->getName(); if (!setName.isEmpty()) { temp.append(": ").append(setName); } temp.append("]"); } setWindowTitle(temp); } void MouseDPadSettingsDialog::updateReleaseSpringRadius(int value) { dpad->setButtonsSpringDeadCircleMultiplier(value); } void MouseDPadSettingsDialog::calculateReleaseSpringRadius() { ui->releaseSpringRadiusspinBox->setValue(dpad->getButtonsSpringDeadCircleMultiplier()); } void MouseDPadSettingsDialog::calculateExtraAccelerationCurve() { JoyButton::JoyExtraAccelerationCurve curve = dpad->getButtonsExtraAccelerationCurve(); updateExtraAccelerationCurvePresetComboBox(curve); } void MouseDPadSettingsDialog::updateExtraAccelerationCurve(int index) { JoyButton::JoyExtraAccelerationCurve temp = JoyButton::LinearAccelCurve; if (index > 0) { InputDevice *device = dpad->getParentSet()->getInputDevice(); PadderCommon::lockInputDevices(); QMetaObject::invokeMethod(device, "haltServices", Qt::BlockingQueuedConnection); temp = getExtraAccelCurveForIndex(index); dpad->setButtonsExtraAccelerationCurve(temp); PadderCommon::unlockInputDevices(); } } antimicro-2.23/src/mousedialog/mousedpadsettingsdialog.h000066400000000000000000000042321300750276700236270ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MOUSEDPADSETTINGSDIALOG_H #define MOUSEDPADSETTINGSDIALOG_H #include "mousesettingsdialog.h" #include "springmoderegionpreview.h" #include #include "uihelpers/mousedpadsettingsdialoghelper.h" class MouseDPadSettingsDialog : public MouseSettingsDialog { Q_OBJECT public: explicit MouseDPadSettingsDialog(JoyDPad *dpad, QWidget *parent = 0); protected: void selectCurrentMouseModePreset(); void calculateSpringPreset(); void calculateMouseSpeedPreset(); void calculateWheelSpeedPreset(); void updateWindowTitleDPadName(); void calculateReleaseSpringRadius(); void calculateExtraAccelerationCurve(); JoyDPad *dpad; SpringModeRegionPreview *springPreviewWidget; MouseDpadSettingsDialogHelper helper; signals: public slots: void changeMouseMode(int index); void changeMouseCurve(int index); void updateConfigHorizontalSpeed(int value); void updateConfigVerticalSpeed(int value); void updateSpringWidth(int value); void updateSpringHeight(int value); void updateSensitivity(double value); void updateAccelerationCurvePresetComboBox(); void updateWheelSpeedHorizontalSpeed(int value); void updateWheelSpeedVerticalSpeed(int value); void updateSpringRelativeStatus(bool value); private slots: void updateReleaseSpringRadius(int value); void updateExtraAccelerationCurve(int index); }; #endif // MOUSEDPADSETTINGSDIALOG_H antimicro-2.23/src/mousedialog/springmoderegionpreview.cpp000066400000000000000000000101001300750276700242040ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include #include #include "springmoderegionpreview.h" SpringModeRegionPreview::SpringModeRegionPreview(int width, int height, QWidget *parent) : #if defined(Q_OS_WIN) QWidget(parent, Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint) #else QWidget(parent, Qt::FramelessWindowHint) #endif { int tempwidth = adjustSpringSizeWidth(width); int tempheight = adjustSpringSizeHeight(height); setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_TranslucentBackground); #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) setAttribute(Qt::WA_PaintOnScreen); #endif setAttribute(Qt::WA_ShowWithoutActivating); setWindowTitle(tr("Spring Mode Preview")); if (tempwidth >= 2 && tempheight >= 2) { int cw = (qApp->desktop()->width() / 2) - (tempwidth / 2); int ch = (qApp->desktop()->height() / 2) - (tempheight / 2); setGeometry(cw, ch, tempwidth, tempheight); show(); } else { resize(0, 0); move(0, 0); } } void SpringModeRegionPreview::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter p(this); QPen border; border.setWidth(3); border.setColor(Qt::black); p.setPen(border); p.drawRect(1, 1, width()-3, height()-3); } int SpringModeRegionPreview::adjustSpringSizeWidth(int width) { int tempwidth = size().width(); if (width >= 2) { tempwidth = width; } else { tempwidth = 0; } return tempwidth; } int SpringModeRegionPreview::adjustSpringSizeHeight(int height) { int tempheight = size().height(); if (height >= 2) { tempheight = height; } else { tempheight = 0; } return tempheight; } void SpringModeRegionPreview::setSpringWidth(int width) { int tempwidth = adjustSpringSizeWidth(width); int height = size().height(); #ifdef Q_OS_UNIX hide(); #endif if (tempwidth >= 2 && height >= 2) { int cw = (qApp->desktop()->width() / 2) - (tempwidth / 2); int ch = (qApp->desktop()->height() / 2) - (height / 2); setGeometry(cw, ch, tempwidth, height); if (!isVisible()) { show(); } } else { #ifndef Q_OS_UNIX hide(); #endif resize(tempwidth, height); move(0, 0); } } void SpringModeRegionPreview::setSpringHeight(int height) { int tempheight = adjustSpringSizeHeight(height); int width = size().width(); #ifdef Q_OS_UNIX hide(); #endif if (width >= 2 && tempheight >= 2) { int cw = (qApp->desktop()->width() / 2) - (width / 2); int ch = (qApp->desktop()->height() / 2) - (tempheight / 2); setGeometry(cw, ch, width, tempheight); if (!isVisible()) { show(); } } else { #ifndef Q_OS_UNIX hide(); #endif resize(width, tempheight); move(0, 0); } } void SpringModeRegionPreview::setSpringSize(int width, int height) { int tempwidth = adjustSpringSizeWidth(width); int tempheight = adjustSpringSizeHeight(height); int cw = (qApp->desktop()->width() / 2) - (tempwidth / 2); int ch = (qApp->desktop()->height() / 2) - (height / 2); resize(tempwidth, tempheight); move(cw, ch); } antimicro-2.23/src/mousedialog/springmoderegionpreview.h000066400000000000000000000024631300750276700236660ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SPRINGMODEREGIONPREVIEW_H #define SPRINGMODEREGIONPREVIEW_H #include class SpringModeRegionPreview : public QWidget { Q_OBJECT public: explicit SpringModeRegionPreview(int width = 0, int height = 0, QWidget *parent = 0); protected: void paintEvent(QPaintEvent *event); int adjustSpringSizeWidth(int width); int adjustSpringSizeHeight(int height); signals: public slots: void setSpringWidth(int width); void setSpringHeight(int height); void setSpringSize(int width, int height); }; #endif // SPRINGMODEREGIONPREVIEW_H antimicro-2.23/src/mousedialog/uihelpers/000077500000000000000000000000001300750276700205335ustar00rootroot00000000000000antimicro-2.23/src/mousedialog/uihelpers/mouseaxissettingsdialoghelper.cpp000066400000000000000000000045341300750276700274230ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "mouseaxissettingsdialoghelper.h" MouseAxisSettingsDialogHelper::MouseAxisSettingsDialogHelper(JoyAxis *axis, QObject *parent) : QObject(parent) { Q_ASSERT(axis); this->axis = axis; } void MouseAxisSettingsDialogHelper::updateExtraAccelerationStatus(bool checked) { axis->getPAxisButton()->setExtraAccelerationStatus(checked); axis->getNAxisButton()->setExtraAccelerationStatus(checked); } void MouseAxisSettingsDialogHelper::updateExtraAccelerationMultiplier(double value) { axis->getPAxisButton()->setExtraAccelerationMultiplier(value); axis->getNAxisButton()->setExtraAccelerationMultiplier(value); } void MouseAxisSettingsDialogHelper::updateStartMultiPercentage(double value) { axis->getPAxisButton()->setStartAccelMultiplier(value); axis->getNAxisButton()->setStartAccelMultiplier(value); } void MouseAxisSettingsDialogHelper::updateMinAccelThreshold(double value) { axis->getPAxisButton()->setMinAccelThreshold(value); axis->getNAxisButton()->setMinAccelThreshold(value); } void MouseAxisSettingsDialogHelper::updateMaxAccelThreshold(double value) { axis->getPAxisButton()->setMaxAccelThreshold(value); axis->getNAxisButton()->setMaxAccelThreshold(value); } void MouseAxisSettingsDialogHelper::updateAccelExtraDuration(double value) { axis->getPAxisButton()->setAccelExtraDuration(value); axis->getNAxisButton()->setAccelExtraDuration(value); } void MouseAxisSettingsDialogHelper::updateReleaseSpringRadius(int value) { axis->getPAxisButton()->setSpringDeadCircleMultiplier(value); axis->getNAxisButton()->setSpringDeadCircleMultiplier(value); } antimicro-2.23/src/mousedialog/uihelpers/mouseaxissettingsdialoghelper.h000066400000000000000000000027251300750276700270700ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MOUSEAXISSETTINGSDIALOGHELPER_H #define MOUSEAXISSETTINGSDIALOGHELPER_H #include #include "joyaxis.h" class MouseAxisSettingsDialogHelper : public QObject { Q_OBJECT public: explicit MouseAxisSettingsDialogHelper(JoyAxis *axis, QObject *parent = 0); protected: JoyAxis *axis; signals: public slots: void updateExtraAccelerationStatus(bool checked); void updateExtraAccelerationMultiplier(double value); void updateStartMultiPercentage(double value); void updateMinAccelThreshold(double value); void updateMaxAccelThreshold(double value); void updateAccelExtraDuration(double value); void updateReleaseSpringRadius(int value); }; #endif // MOUSEAXISSETTINGSDIALOGHELPER_H antimicro-2.23/src/mousedialog/uihelpers/mousebuttonsettingsdialoghelper.cpp000066400000000000000000000037311300750276700277700ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "mousebuttonsettingsdialoghelper.h" MouseButtonSettingsDialogHelper::MouseButtonSettingsDialogHelper(JoyButton *button, QObject *parent) : QObject(parent) { Q_ASSERT(button); this->button = button; } void MouseButtonSettingsDialogHelper::updateExtraAccelerationStatus(bool checked) { button->setExtraAccelerationStatus(checked); } void MouseButtonSettingsDialogHelper::updateExtraAccelerationMultiplier(double value) { button->setExtraAccelerationMultiplier(value); } void MouseButtonSettingsDialogHelper::updateStartMultiPercentage(double value) { button->setStartAccelMultiplier(value); } void MouseButtonSettingsDialogHelper::updateMinAccelThreshold(double value) { button->setMinAccelThreshold(value); } void MouseButtonSettingsDialogHelper::updateMaxAccelThreshold(double value) { button->setMaxAccelThreshold(value); } void MouseButtonSettingsDialogHelper::updateAccelExtraDuration(double value) { button->setAccelExtraDuration(value); } void MouseButtonSettingsDialogHelper::updateReleaseSpringRadius(int value) { button->setSpringDeadCircleMultiplier(value); } void MouseButtonSettingsDialogHelper::updateSpringRelativeStatus(bool value) { button->setSpringRelativeStatus(value); } antimicro-2.23/src/mousedialog/uihelpers/mousebuttonsettingsdialoghelper.h000066400000000000000000000031511300750276700274310ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MOUSEBUTTONSETTINGSDIALOGHELPER_H #define MOUSEBUTTONSETTINGSDIALOGHELPER_H #include #include "joybutton.h" #include "joybuttonslot.h" class MouseButtonSettingsDialogHelper : public QObject { Q_OBJECT public: explicit MouseButtonSettingsDialogHelper(JoyButton *button, QObject *parent = 0); protected: JoyButton *button; signals: public slots: void updateExtraAccelerationStatus(bool checked); void updateExtraAccelerationMultiplier(double value); void updateStartMultiPercentage(double value); void updateMinAccelThreshold(double value); void updateMaxAccelThreshold(double value); void updateAccelExtraDuration(double value); void updateReleaseSpringRadius(int value); void updateSpringRelativeStatus(bool value); //void updateExtraAccelerationCurve(int index); }; #endif // MOUSEBUTTONSETTINGSDIALOGHELPER_H antimicro-2.23/src/mousedialog/uihelpers/mousecontrolsticksettingsdialoghelper.cpp000066400000000000000000000040541300750276700311720ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "mousecontrolsticksettingsdialoghelper.h" MouseControlStickSettingsDialogHelper::MouseControlStickSettingsDialogHelper(JoyControlStick *stick, QObject *parent) : QObject(parent) { Q_ASSERT(stick); this->stick = stick; } void MouseControlStickSettingsDialogHelper::updateExtraAccelerationStatus(bool checked) { stick->setButtonsExtraAccelerationStatus(checked); } void MouseControlStickSettingsDialogHelper::updateExtraAccelerationMultiplier(double value) { stick->setButtonsExtraAccelerationMultiplier(value); } void MouseControlStickSettingsDialogHelper::updateStartMultiPercentage(double value) { stick->setButtonsStartAccelerationMultiplier(value); } void MouseControlStickSettingsDialogHelper::updateMinAccelThreshold(double value) { stick->setButtonsMinAccelerationThreshold(value); } void MouseControlStickSettingsDialogHelper::updateMaxAccelThreshold(double value) { stick->setButtonsMaxAccelerationThreshold(value); } void MouseControlStickSettingsDialogHelper::updateAccelExtraDuration(double value) { stick->setButtonsAccelerationExtraDuration(value); } void MouseControlStickSettingsDialogHelper::updateReleaseSpringRadius(int value) { stick->setButtonsSpringDeadCircleMultiplier(value); } antimicro-2.23/src/mousedialog/uihelpers/mousecontrolsticksettingsdialoghelper.h000066400000000000000000000030271300750276700306360ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MOUSECONTROLSTICKSETTINGSDIALOGHELPER_H #define MOUSECONTROLSTICKSETTINGSDIALOGHELPER_H #include #include "joycontrolstick.h" class MouseControlStickSettingsDialogHelper : public QObject { Q_OBJECT public: explicit MouseControlStickSettingsDialogHelper(JoyControlStick *stick, QObject *parent = 0); protected: JoyControlStick *stick; signals: public slots: void updateExtraAccelerationStatus(bool checked); void updateExtraAccelerationMultiplier(double value); void updateStartMultiPercentage(double value); void updateMinAccelThreshold(double value); void updateMaxAccelThreshold(double value); void updateAccelExtraDuration(double value); void updateReleaseSpringRadius(int value); }; #endif // MOUSECONTROLSTICKSETTINGSDIALOGHELPER_H antimicro-2.23/src/mousedialog/uihelpers/mousedpadsettingsdialoghelper.cpp000066400000000000000000000017041300750276700273630ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "mousedpadsettingsdialoghelper.h" MouseDpadSettingsDialogHelper::MouseDpadSettingsDialogHelper(JoyDPad *dpad, QObject *parent) : QObject(parent) { Q_ASSERT(dpad); this->dpad = dpad; } antimicro-2.23/src/mousedialog/uihelpers/mousedpadsettingsdialoghelper.h000066400000000000000000000022221300750276700270240ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MOUSEDPADSETTINGSDIALOGHELPER_H #define MOUSEDPADSETTINGSDIALOGHELPER_H #include #include "joydpad.h" #include "joydpadbuttonwidget.h" class MouseDpadSettingsDialogHelper : public QObject { Q_OBJECT public: explicit MouseDpadSettingsDialogHelper(JoyDPad *dpad, QObject *parent = 0); protected: JoyDPad *dpad; signals: public slots: }; #endif // MOUSEDPADSETTINGSDIALOGHELPER_H antimicro-2.23/src/mousehelper.cpp000066400000000000000000000027711300750276700172660ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "mousehelper.h" MouseHelper::MouseHelper(QObject *parent) : QObject(parent) { springMouseMoving = false; previousCursorLocation[0] = 0; previousCursorLocation[1] = 0; pivotPoint[0] = -1; pivotPoint[1] = -1; mouseTimer.setParent(this); mouseTimer.setSingleShot(true); QObject::connect(&mouseTimer, SIGNAL(timeout()), this, SLOT(resetSpringMouseMoving())); } void MouseHelper::resetSpringMouseMoving() { springMouseMoving = false; } void MouseHelper::initDeskWid() { if (!deskWid) { deskWid = new QDesktopWidget; } } void MouseHelper::deleteDeskWid() { if (deskWid) { delete deskWid; deskWid = 0; } } QDesktopWidget* MouseHelper::getDesktopWidget() { return deskWid; } antimicro-2.23/src/mousehelper.h000066400000000000000000000024331300750276700167260ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MOUSEHELPER_H #define MOUSEHELPER_H #include #include #include class MouseHelper : public QObject { Q_OBJECT public: explicit MouseHelper(QObject *parent = 0); QDesktopWidget* getDesktopWidget(); bool springMouseMoving; int previousCursorLocation[2]; int pivotPoint[2]; QTimer mouseTimer; QDesktopWidget *deskWid; signals: public slots: void deleteDeskWid(); void initDeskWid(); private slots: void resetSpringMouseMoving(); }; #endif // MOUSEHELPER_H antimicro-2.23/src/mousesettingsdialog.cpp000066400000000000000000000306071300750276700210260ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include "mousesettingsdialog.h" #include "ui_mousesettingsdialog.h" MouseSettingsDialog::MouseSettingsDialog(QWidget *parent) : QDialog(parent, Qt::Window), ui(new Ui::MouseSettingsDialog) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); JoyButtonMouseHelper *mouseHelper = JoyButton::getMouseHelper(); connect(mouseHelper, SIGNAL(mouseCursorMoved(int,int,int)), this, SLOT(updateMouseCursorStatusLabels(int,int,int))); connect(mouseHelper, SIGNAL(mouseSpringMoved(int,int)), this, SLOT(updateMouseSpringStatusLabels(int,int))); lastMouseStatUpdate.start(); connect(ui->accelerationComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeSettingsWidgetStatus(int))); connect(ui->accelerationComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(refreshMouseCursorSpeedValues(int))); connect(ui->mouseModeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeSpringSectionStatus(int))); connect(ui->mouseModeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeMouseSpeedBoxStatus(int))); connect(ui->mouseModeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeWheelSpeedBoxStatus(int))); connect(ui->mouseModeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeSensitivityStatusForMouseMode(int))); connect(ui->horizontalSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateHorizontalSpeedConvertLabel(int))); connect(ui->horizontalSpinBox, SIGNAL(valueChanged(int)), this, SLOT(moveSpeedsTogether(int))); connect(ui->verticalSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateVerticalSpeedConvertLabel(int))); connect(ui->verticalSpinBox, SIGNAL(valueChanged(int)), this, SLOT(moveSpeedsTogether(int))); connect(ui->wheelVertSpeedSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateWheelVerticalSpeedLabel(int))); connect(ui->wheelHoriSpeedSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateWheelHorizontalSpeedLabel(int))); connect(ui->relativeSpringCheckBox, SIGNAL(clicked(bool)), this, SLOT(disableReleaseSpringBox(bool))); connect(ui->relativeSpringCheckBox, SIGNAL(clicked(bool)), this, SLOT(resetReleaseRadius(bool))); } MouseSettingsDialog::~MouseSettingsDialog() { delete ui; } void MouseSettingsDialog::changeSettingsWidgetStatus(int index) { JoyButton::JoyMouseCurve temp = getMouseCurveForIndex(index); int currentMouseMode = ui->mouseModeComboBox->currentIndex(); if (currentMouseMode == 1 && temp == JoyButton::PowerCurve) { ui->sensitivityDoubleSpinBox->setEnabled(true); } else { ui->sensitivityDoubleSpinBox->setEnabled(false); } if (currentMouseMode == 1 && (temp == JoyButton::EasingQuadraticCurve || temp == JoyButton::EasingCubicCurve)) { ui->easingDoubleSpinBox->setEnabled(true); } else { ui->easingDoubleSpinBox->setEnabled(false); } } void MouseSettingsDialog::changeSpringSectionStatus(int index) { if (index == 2) { ui->springWidthSpinBox->setEnabled(true); ui->springHeightSpinBox->setEnabled(true); ui->relativeSpringCheckBox->setEnabled(true); bool enableSpringRadiusBox = !ui->relativeSpringCheckBox->isChecked(); ui->releaseSpringRadiusspinBox->setEnabled(enableSpringRadiusBox); } else { ui->springWidthSpinBox->setEnabled(false); ui->springHeightSpinBox->setEnabled(false); ui->relativeSpringCheckBox->setEnabled(false); ui->releaseSpringRadiusspinBox->setEnabled(false); } } void MouseSettingsDialog::updateHorizontalSpeedConvertLabel(int value) { QString label = QString (QString::number(value)); int currentCurveIndex = ui->accelerationComboBox->currentIndex(); JoyButton::JoyMouseCurve tempCurve = getMouseCurveForIndex(currentCurveIndex); int finalSpeed = JoyButton::calculateFinalMouseSpeed(tempCurve, value); label = label.append(" = ").append(QString::number(finalSpeed)).append(" pps"); ui->horizontalSpeedLabel->setText(label); } void MouseSettingsDialog::updateVerticalSpeedConvertLabel(int value) { QString label = QString (QString::number(value)); int currentCurveIndex = ui->accelerationComboBox->currentIndex(); JoyButton::JoyMouseCurve tempCurve = getMouseCurveForIndex(currentCurveIndex); int finalSpeed = JoyButton::calculateFinalMouseSpeed(tempCurve, value); label = label.append(" = ").append(QString::number(finalSpeed)).append(" pps"); ui->verticalSpeedLabel->setText(label); } void MouseSettingsDialog::moveSpeedsTogether(int value) { if (ui->changeMouseSpeedsTogetherCheckBox->isChecked()) { ui->horizontalSpinBox->setValue(value); ui->verticalSpinBox->setValue(value); } } void MouseSettingsDialog::changeMouseSpeedBoxStatus(int index) { if (index == 2) { ui->horizontalSpinBox->setEnabled(false); ui->verticalSpinBox->setEnabled(false); ui->changeMouseSpeedsTogetherCheckBox->setEnabled(false); ui->extraAccelerationGroupBox->setChecked(false); ui->extraAccelerationGroupBox->setEnabled(false); } else { ui->horizontalSpinBox->setEnabled(true); ui->verticalSpinBox->setEnabled(true); ui->changeMouseSpeedsTogetherCheckBox->setEnabled(true); ui->extraAccelerationGroupBox->setEnabled(true); if (ui->extraAccelerationGroupBox->isChecked()) { ui->extraAccelerationGroupBox->setEnabled(true); } } } void MouseSettingsDialog::changeWheelSpeedBoxStatus(int index) { if (index == 2) { ui->wheelHoriSpeedSpinBox->setEnabled(false); ui->wheelVertSpeedSpinBox->setEnabled(false); } else { ui->wheelHoriSpeedSpinBox->setEnabled(true); ui->wheelVertSpeedSpinBox->setEnabled(true); } } void MouseSettingsDialog::updateWheelVerticalSpeedLabel(int value) { QString label = QString(QString::number(value)); label.append(" = "); label.append(tr("%n notch(es)/s", "", value)); ui->wheelVertSpeedUnitsLabel->setText(label); } void MouseSettingsDialog::updateWheelHorizontalSpeedLabel(int value) { QString label = QString(QString::number(value)); label.append(" = "); label.append(tr("%n notch(es)/s", "", value)); ui->wheelHoriSpeedUnitsLabel->setText(label); } void MouseSettingsDialog::updateAccelerationCurvePresetComboBox(JoyButton::JoyMouseCurve mouseCurve) { if (mouseCurve == JoyButton::EnhancedPrecisionCurve) { ui->accelerationComboBox->setCurrentIndex(1); } else if (mouseCurve == JoyButton::LinearCurve) { ui->accelerationComboBox->setCurrentIndex(2); } else if (mouseCurve == JoyButton::QuadraticCurve) { ui->accelerationComboBox->setCurrentIndex(3); } else if (mouseCurve == JoyButton::CubicCurve) { ui->accelerationComboBox->setCurrentIndex(4); } else if (mouseCurve == JoyButton::QuadraticExtremeCurve) { ui->accelerationComboBox->setCurrentIndex(5); } else if (mouseCurve == JoyButton::PowerCurve) { ui->accelerationComboBox->setCurrentIndex(6); } else if (mouseCurve == JoyButton::EasingQuadraticCurve) { ui->accelerationComboBox->setCurrentIndex(7); } else if (mouseCurve == JoyButton::EasingCubicCurve) { ui->accelerationComboBox->setCurrentIndex(8); } } JoyButton::JoyMouseCurve MouseSettingsDialog::getMouseCurveForIndex(int index) { JoyButton::JoyMouseCurve temp = JoyButton::DEFAULTMOUSECURVE; if (index == 1) { temp = JoyButton::EnhancedPrecisionCurve; } else if (index == 2) { temp = JoyButton::LinearCurve; } else if (index == 3) { temp = JoyButton::QuadraticCurve; } else if (index == 4) { temp = JoyButton::CubicCurve; } else if (index == 5) { temp = JoyButton::QuadraticExtremeCurve; } else if (index == 6) { temp = JoyButton::PowerCurve; } else if (index == 7) { temp = JoyButton::EasingQuadraticCurve; } else if (index == 8) { temp = JoyButton::EasingCubicCurve; } return temp; } void MouseSettingsDialog::changeSensitivityStatusForMouseMode(int index) { if (index == 2) { ui->sensitivityDoubleSpinBox->setEnabled(false); } else if (index == 1) { int currentCurveIndex = ui->accelerationComboBox->currentIndex(); JoyButton::JoyMouseCurve temp = getMouseCurveForIndex(currentCurveIndex); if (temp == JoyButton::PowerCurve) { ui->sensitivityDoubleSpinBox->setEnabled(true); } } else { ui->sensitivityDoubleSpinBox->setEnabled(false); } } /** * @brief Update mouse status labels with cursor mouse information provided by * an InputDevice. * @param X distance in pixels * @param Y distance in pixels * @param Time elapsed for generated event */ void MouseSettingsDialog::updateMouseCursorStatusLabels(int mouseX, int mouseY, int elapsed) { if (lastMouseStatUpdate.elapsed() >= 100 && elapsed > 0) { QString tempX("%1 (%2 pps) (%3 ms)"); QString tempY("%1 (%2 pps) (%3 ms)"); //QString tempPoll("%1 Hz"); ui->mouseStatusXLabel->setText(tempX.arg(mouseX).arg(mouseX * (1000/elapsed)).arg(elapsed)); ui->mouseStatusYLabel->setText(tempY.arg(mouseY).arg(mouseY * (1000/elapsed)).arg(elapsed)); //ui->mouseStatusPollLabel->setText(tempPoll.arg(1000/elapsed)); lastMouseStatUpdate.start(); } } /** * @brief Update mouse status labels with spring mouse information * provided by an InputDevice. * @param X coordinate of cursor * @param Y coordinate of cursor */ void MouseSettingsDialog::updateMouseSpringStatusLabels(int coordX, int coordY) { if (lastMouseStatUpdate.elapsed() >= 100) { QString tempX("%1"); QString tempY("%1"); ui->mouseStatusXLabel->setText(tempX.arg(coordX)); ui->mouseStatusYLabel->setText(tempY.arg(coordY)); lastMouseStatUpdate.start(); } } void MouseSettingsDialog::refreshMouseCursorSpeedValues(int index) { Q_UNUSED(index); updateHorizontalSpeedConvertLabel(ui->horizontalSpinBox->value()); updateVerticalSpeedConvertLabel(ui->verticalSpinBox->value()); } void MouseSettingsDialog::disableReleaseSpringBox(bool enable) { ui->releaseSpringRadiusspinBox->setEnabled(!enable); } void MouseSettingsDialog::resetReleaseRadius(bool enabled) { if (enabled && ui->releaseSpringRadiusspinBox->value() > 0) { ui->releaseSpringRadiusspinBox->setValue(0); } } JoyButton::JoyExtraAccelerationCurve MouseSettingsDialog::getExtraAccelCurveForIndex(int index) { JoyButton::JoyExtraAccelerationCurve temp = JoyButton::LinearAccelCurve; if (index == 1) { temp = JoyButton::LinearAccelCurve; } else if (index == 2) { temp = JoyButton::EaseOutSineCurve; } else if (index == 3) { temp = JoyButton::EaseOutQuadAccelCurve; } else if (index == 4) { temp = JoyButton::EaseOutCubicAccelCurve; } return temp; } void MouseSettingsDialog::updateExtraAccelerationCurvePresetComboBox (JoyButton::JoyExtraAccelerationCurve curve) { int temp = 0; if (curve == JoyButton::LinearAccelCurve) { temp = 1; } else if (curve == JoyButton::EaseOutSineCurve) { temp = 2; } else if (curve == JoyButton::EaseOutQuadAccelCurve) { temp = 3; } else if (curve == JoyButton::EaseOutCubicAccelCurve) { temp = 4; } ui->extraAccelCurveComboBox->setCurrentIndex(temp); } antimicro-2.23/src/mousesettingsdialog.h000066400000000000000000000046531300750276700204750ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef MOUSESETTINGSDIALOG_H #define MOUSESETTINGSDIALOG_H #include #include #include "joybutton.h" namespace Ui { class MouseSettingsDialog; } class MouseSettingsDialog : public QDialog { Q_OBJECT public: explicit MouseSettingsDialog(QWidget *parent = 0); ~MouseSettingsDialog(); protected: void updateAccelerationCurvePresetComboBox(JoyButton::JoyMouseCurve mouseCurve); void updateExtraAccelerationCurvePresetComboBox(JoyButton::JoyExtraAccelerationCurve curve); JoyButton::JoyMouseCurve getMouseCurveForIndex(int index); JoyButton::JoyExtraAccelerationCurve getExtraAccelCurveForIndex(int index); Ui::MouseSettingsDialog *ui; QTime lastMouseStatUpdate; public slots: void changeSettingsWidgetStatus(int index); void changeSpringSectionStatus(int index); void changeMouseSpeedBoxStatus(int index); void changeWheelSpeedBoxStatus(int index); void updateHorizontalSpeedConvertLabel(int value); void updateVerticalSpeedConvertLabel(int value); void moveSpeedsTogether(int value); //void changeSmoothingStatus(int index); void updateWheelVerticalSpeedLabel(int value); void updateWheelHorizontalSpeedLabel(int value); void changeSensitivityStatusForMouseMode(int index); virtual void changeMouseMode(int index) = 0; virtual void changeMouseCurve(int index) = 0; private slots: void updateMouseCursorStatusLabels(int mouseX, int mouseY, int elapsed); void updateMouseSpringStatusLabels(int coordX, int coordY); void refreshMouseCursorSpeedValues(int index); void disableReleaseSpringBox(bool enable); void resetReleaseRadius(bool enabled); }; #endif // MOUSESETTINGSDIALOG_H antimicro-2.23/src/mousesettingsdialog.ui000066400000000000000000001014061300750276700206550ustar00rootroot00000000000000 MouseSettingsDialog Qt::WindowModal 0 0 587 612 Mouse Settings Mouse Mode: Cursor mode is used to move the mouse cursor around the screen relative to its current position depending on how much you move an axis or if a button is pressed. Spring mode is used to move the mouse cursor from the center of the screen depending on how much you move an axis. The mouse cursor will be returned to the center of the screen when the axis is moved back to the dead zone. Cursor Spring 160 0 Acceleration: Enhanced: Three tier curve that makes the mouse move slow on the low end of an axis and fast on the high end. Linear: Mouse moves proportionally to axis. Quadratic: Mouse accelerates slowly on low end. Cubic: Mouse accelerates slower than Quadratic. Quadratic Extreme: Raises mouse speed 1.5 times once 95% axis travel has been reached. Power Function: Allows for a more custom curve option. Easing Quadratic: Axis high end is gradually accelerated over a period of time using a Quadratic curve. Easing Cubic: Axis high end is gradually accelerated over a period of time using a Cubic curve. Enhanced Precision Linear Quadratic Cubic Quadratic Extreme Power Function Easing Quadratic Easing Cubic Qt::Vertical QSizePolicy::Fixed 20 10 Mouse Speed Settings false false true Enable to change the horizontal and vertical speed boxes at the same time. Change Together 16 10 10 10 Hori&zontal Speed: horizontalSpinBox true 1 300 1 1 = 20 pps 10 10 &Vertical Speed: verticalSpinBox true 1 300 1 1 = 20 pps 16 10 10 Wheel Hori. Speed: wheelHoriSpeedSpinBox Set the speed used for horizontal mouse wheel movement according to number of simulated notches per second. 1 100 1 1 1 = 1 notch(es)/s 10 Wheel Vert. Speed: wheelVertSpeedSpinBox Set the speed used for vertical mouse wheel movement according to number of simulated notches per second. 1 100 1 = 1 notch(es)/s Sensitivit&y: sensitivityDoubleSpinBox false For Power Function acceleration curve. Specifies the factor to use for curve sensitivity. When the value is above 1.0, the mouse movement will be accelerated faster at the low end of an axis. 3 0.001000000000000 1000.000000000000000 0.100000000000000 1.000000000000000 Easing Duration: sensitivityDoubleSpinBox false Specifies the amount of time (in seconds) that will be required before the mouse is fully accelerated after reaching the high end of an axis. s 2 0.000000000000000 5.000000000000000 0.100000000000000 0.500000000000000 Qt::Vertical QSizePolicy::Fixed 20 10 true Options for adding more acceleration to the mouse movement beyond what the acceleration curve would produce. Acceleration is added based on how quickly an axis is moved in one gamepad poll. This is meant to help work around some of the issues of the very limited input range available using typical gamepad analog sticks. Delta Acceleration false true false &Multiplier: extraAccelDoubleSpinBox Highest value to accelerate mouse movement by x 1.000000000000000 200.000000000000000 2.000000000000000 Start %: minMultiDoubleSpinBox Acceleration begins at this percentage of the base multiplier % 0.000000000000000 100.000000000000000 1.000000000000000 0.000000000000000 Mi&n Threshold: minThresholdDoubleSpinBox Minimum amount of axis travel required for acceleration to begin % 100.000000000000000 10.000000000000000 Max Threshold: maxThresholdDoubleSpinBox Maximum axis travel before acceleration has reached the multiplier value % 100.000000000000000 100.000000000000000 E&xtra Duration: accelExtraDurationDoubleSpinBox Extend the time that extra acceleration is applied. Axis travel will be taken into account. A slower flick will decrease the actual time that extra acceleration will be applied. s 0.000000000000000 5.000000000000000 0.050000000000000 Curve: Linear Ease Out Sine Ease Out Quad Ease Out Cubic 10 Spring Settings Spring Width: springWidthSpinBox false Changes the width of the region that the cursor can move in spring mode. 0 will use the entire width of your screen. 16777215 Spring Height: springHeightSpinBox false Changes the height of the region that the cursor can move in spring mode. 0 will use the entire height of your screen. 16777215 Release Radius: releaseSpringRadiusspinBox false % 100 false Specifies that the spring area will be relative to the mouse position set by a non-relative spring. Relative Qt::Vertical 20 40 Mouse Status X: 0 (0 pps) Y: 0 (0 pps) Qt::Vertical QSizePolicy::Fixed 20 10 Qt::Horizontal QDialogButtonBox::Close buttonBox accepted() MouseSettingsDialog accept() 248 254 157 274 buttonBox rejected() MouseSettingsDialog reject() 316 260 286 274 antimicro-2.23/src/qkeydisplaydialog.cpp000066400000000000000000000117411300750276700204520ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include "qkeydisplaydialog.h" #include "ui_qkeydisplaydialog.h" #include "eventhandlerfactory.h" #include "antkeymapper.h" #ifdef Q_OS_WIN #include "winextras.h" #endif #ifdef Q_OS_UNIX #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include #endif #ifdef WITH_X11 #include "x11extras.h" #endif #endif QKeyDisplayDialog::QKeyDisplayDialog(QWidget *parent) : QDialog(parent), ui(new Ui::QKeyDisplayDialog) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); this->setFocus(); BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); ui->eventHandlerLabel->setText(handler->getName()); #ifdef Q_OS_UNIX #if defined(WITH_UINPUT) #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif /*ui->formLayout->removeWidget(ui->nativeTitleLabel); ui->formLayout->removeWidget(ui->nativeKeyLabel); ui->nativeTitleLabel->setVisible(false); ui->nativeKeyLabel->setVisible(false); */ #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } #endif #endif #else /*ui->formLayout->removeWidget(ui->eventHandlerTitleLabel); ui->formLayout->removeWidget(ui->eventHandlerLabel); ui->eventHandlerTitleLabel->setVisible(false); ui->eventHandlerLabel->setVisible(false); */ #endif } QKeyDisplayDialog::~QKeyDisplayDialog() { delete ui; } void QKeyDisplayDialog::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Escape: case Qt::Key_Enter: case Qt::Key_Return: break; default: QDialog::keyPressEvent(event); } } void QKeyDisplayDialog::keyReleaseEvent(QKeyEvent *event) { unsigned int scancode = event->nativeScanCode(); unsigned int virtualkey = event->nativeVirtualKey(); BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); #ifdef Q_OS_WIN unsigned int finalvirtual = WinExtras::correctVirtualKey(scancode, virtualkey); unsigned int tempvirtual = finalvirtual; #ifdef WITH_VMULTI if (handler->getIdentifier() == "vmulti") { QtKeyMapperBase *nativeWinKeyMapper = AntKeyMapper::getInstance()->getNativeKeyMapper(); if (nativeWinKeyMapper) { unsigned int tempQtKey = nativeWinKeyMapper->returnQtKey(finalvirtual); if (tempQtKey > 0) { tempvirtual = AntKeyMapper::getInstance()->returnVirtualKey(tempQtKey); } } } #endif #else unsigned int finalvirtual = 0; #ifdef WITH_X11 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif // Obtain group 1 X11 keysym. Removes effects from modifiers. finalvirtual = X11Extras::getInstance()->getGroup1KeySym(virtualkey); #ifdef WITH_UINPUT unsigned int tempalias = 0; QtKeyMapperBase *nativeKeyMapper = AntKeyMapper::getInstance()->getNativeKeyMapper(); if (nativeKeyMapper && nativeKeyMapper->getIdentifier() == "xtest") { tempalias = nativeKeyMapper->returnQtKey(virtualkey); finalvirtual = AntKeyMapper::getInstance()->returnVirtualKey(tempalias); } #endif #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } else { finalvirtual = scancode; } #endif #else #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif finalvirtual = AntKeyMapper::getInstance()->returnVirtualKey(event->key()); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } else { finalvirtual = scancode; } #endif #endif #endif ui->nativeKeyLabel->setText(QString("0x%1").arg(finalvirtual, 0, 16)); ui->qtKeyLabel->setText(QString("0x%1").arg(event->key(), 0, 16)); #ifdef Q_OS_WIN QString tempValue = QString("0x%1").arg(AntKeyMapper::getInstance()->returnQtKey(tempvirtual, scancode), 0, 16); #else QString tempValue = QString("0x%1").arg(AntKeyMapper::getInstance()->returnQtKey(finalvirtual), 0, 16); #endif ui->antimicroKeyLabel->setText(tempValue); } antimicro-2.23/src/qkeydisplaydialog.h000066400000000000000000000023161300750276700201150ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef QKEYDISPLAYDIALOG_H #define QKEYDISPLAYDIALOG_H #include #include namespace Ui { class QKeyDisplayDialog; } class QKeyDisplayDialog : public QDialog { Q_OBJECT public: explicit QKeyDisplayDialog(QWidget *parent = 0); ~QKeyDisplayDialog(); protected: virtual void keyPressEvent(QKeyEvent *event); virtual void keyReleaseEvent(QKeyEvent *event); private: Ui::QKeyDisplayDialog *ui; }; #endif // QKEYDISPLAYDIALOG_H antimicro-2.23/src/qkeydisplaydialog.ui000066400000000000000000000157231300750276700203110ustar00rootroot00000000000000 QKeyDisplayDialog Qt::ApplicationModal 0 0 550 360 0 0 Qt::StrongFocus Key Checker true 8 8 <html><head/><body><p>Press a key on your keyboard to see how the key is detected by this application. The window will show the system native key value, the original value given by Qt (if applicable), and the custom value used by antimicro.</p><p>The antimicro key value and the Qt key value will usually be the same. antimicro tries to use the key values defined in Qt when possible. Check the page <a href="https://doc.qt.io/qt-4.8/qt.html#Key-enum"><span style=" text-decoration: underline; color:#0057ae;">https://doc.qt.io/qt-4.8/qt.html#Key-enum</span></a> for a list of values defined by Qt. If you discover that a key is not natively supported by this program, please report the problem to antimicro's <a href="https://github.com/AntiMicro/antimicro"><span style=" text-decoration: underline; color:#0057ae;">GitHub page</span></a> so that the program can be edited to support it directly. As it is, a custom prefix is added to unknown values so they can still be used; the main problem is that the profile will no longer be portable.</p></body></html> Qt::AutoText true true Qt::LinksAccessibleByMouse Qt::Vertical QSizePolicy::Fixed 20 10 QFormLayout::ExpandingFieldsGrow 20 10 6 10 75 true Event Handler: 75 true Native Key Value: 0x00000000 Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 75 true Qt Key Value: 0x00000000 Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse 75 true antimicro Key Value: 0x00000000 Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse Qt::NoFocus Qt::Horizontal QDialogButtonBox::Close buttonBox accepted() QKeyDisplayDialog accept() 248 254 157 274 buttonBox rejected() QKeyDisplayDialog reject() 316 260 286 274 antimicro-2.23/src/qtkeymapperbase.cpp000066400000000000000000000043321300750276700201260ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "qtkeymapperbase.h" const unsigned int QtKeyMapperBase::customQtKeyPrefix; const unsigned int QtKeyMapperBase::customKeyPrefix; const unsigned int QtKeyMapperBase::nativeKeyPrefix; QtKeyMapperBase::QtKeyMapperBase(QObject *parent) : QObject(parent) { } unsigned int QtKeyMapperBase::returnQtKey(unsigned int key, unsigned int scancode) { Q_UNUSED(scancode); return virtualKeyToQtKey.value(key); } unsigned int QtKeyMapperBase::returnVirtualKey(unsigned int qkey) { return qtKeyToVirtualKey.value(qkey); } bool QtKeyMapperBase::isModifier(unsigned int qkey) { bool modifier = false; unsigned int qtKeyValue = qkey & 0x0FFFFFFF; if (qtKeyValue == Qt::Key_Shift) { modifier = true; } else if (qtKeyValue == Qt::Key_Control) { modifier = true; } else if (qtKeyValue == Qt::Key_Alt) { modifier = true; } else if (qtKeyValue == Qt::Key_Meta) { modifier = true; } return modifier; } QtKeyMapperBase::charKeyInformation QtKeyMapperBase::getCharKeyInformation(QChar value) { charKeyInformation temp; temp.virtualkey = 0; temp.modifiers = Qt::NoModifier; if (virtualkeyToCharKeyInformation.contains(value.unicode())) { temp = virtualkeyToCharKeyInformation.value(value.unicode()); } return temp; } /** * @brief Obtain identifier string for key mapper. * @return Identifier string. */ QString QtKeyMapperBase::getIdentifier() { return identifier; } antimicro-2.23/src/qtkeymapperbase.h000066400000000000000000000074161300750276700176010ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef QTKEYMAPPERBASE_H #define QTKEYMAPPERBASE_H #include #include class QtKeyMapperBase : public QObject { Q_OBJECT public: explicit QtKeyMapperBase(QObject *parent = 0); typedef struct _charKeyInformation { Qt::KeyboardModifiers modifiers; unsigned int virtualkey; } charKeyInformation; virtual unsigned int returnVirtualKey(unsigned int qkey); virtual unsigned int returnQtKey(unsigned int key, unsigned int scancode=0); virtual bool isModifier(unsigned int qkey); charKeyInformation getCharKeyInformation(QChar value); QString getIdentifier(); static const unsigned int customQtKeyPrefix = 0x10000000; static const unsigned int customKeyPrefix = 0x20000000; static const unsigned int nativeKeyPrefix = 0x60000000; enum { AntKey_Shift_R = Qt::Key_Shift | customQtKeyPrefix, AntKey_Control_R = Qt::Key_Control | customQtKeyPrefix, AntKey_Shift_Lock = 0xffe6 | customKeyPrefix, // XK_Shift_Lock | 0x20000000 AntKey_Meta_R = Qt::Key_Meta | customQtKeyPrefix, AntKey_Alt_R = Qt::Key_Alt | customQtKeyPrefix, AntKey_KP_Divide = Qt::Key_Slash | customQtKeyPrefix, AntKey_KP_Multiply = Qt::Key_Asterisk | customQtKeyPrefix, AntKey_KP_Subtract = Qt::Key_Minus | customQtKeyPrefix, AntKey_KP_Add = Qt::Key_Plus | customQtKeyPrefix, AntKey_KP_Decimal = Qt::Key_Period | customQtKeyPrefix, AntKey_KP_Insert = Qt::Key_Insert | customQtKeyPrefix, AntKey_KP_Delete = Qt::Key_Delete | customQtKeyPrefix, AntKey_KP_End = Qt::Key_End | customQtKeyPrefix, AntKey_KP_Down = Qt::Key_Down | customQtKeyPrefix, AntKey_KP_Prior = Qt::Key_PageDown | customQtKeyPrefix, AntKey_KP_Left = Qt::Key_Left | customQtKeyPrefix, AntKey_KP_Begin = Qt::Key_Clear | customQtKeyPrefix, AntKey_KP_Right = Qt::Key_Right | customQtKeyPrefix, AntKey_KP_Home = Qt::Key_Home | customQtKeyPrefix, AntKey_KP_Up = Qt::Key_Up | customQtKeyPrefix, AntKey_KP_Next = Qt::Key_PageUp | customQtKeyPrefix, AntKey_KP_0 = Qt::Key_0 | customQtKeyPrefix, AntKey_KP_1 = Qt::Key_1 | customQtKeyPrefix, AntKey_KP_2 = Qt::Key_2 | customQtKeyPrefix, AntKey_KP_3 = Qt::Key_3 | customQtKeyPrefix, AntKey_KP_4 = Qt::Key_4 | customQtKeyPrefix, AntKey_KP_5 = Qt::Key_5 | customQtKeyPrefix, AntKey_KP_6 = Qt::Key_6 | customQtKeyPrefix, AntKey_KP_7 = Qt::Key_7 | customQtKeyPrefix, AntKey_KP_8 = Qt::Key_8 | customQtKeyPrefix, AntKey_KP_9 = Qt::Key_9 | customQtKeyPrefix }; protected: virtual void populateMappingHashes() = 0; virtual void populateCharKeyInformation() = 0; QHash qtKeyToVirtualKey; QHash virtualKeyToQtKey; // Unicode representation -> VK+Modifier information QHash virtualkeyToCharKeyInformation; QString identifier; signals: public slots: }; #endif // QTKEYMAPPERBASE_H antimicro-2.23/src/qtuinputkeymapper.cpp000066400000000000000000000502201300750276700205350ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include //#include #include #include #include #include "qtuinputkeymapper.h" QtUInputKeyMapper::QtUInputKeyMapper(QObject *parent) : QtKeyMapperBase(parent) { identifier = "uinput"; populateMappingHashes(); populateCharKeyInformation(); } void QtUInputKeyMapper::populateAlphaHashes() { // Map lowercase alpha keys qtKeyToVirtualKey[Qt::Key_A] = KEY_A; qtKeyToVirtualKey[Qt::Key_B] = KEY_B; qtKeyToVirtualKey[Qt::Key_C] = KEY_C; qtKeyToVirtualKey[Qt::Key_D] = KEY_D; qtKeyToVirtualKey[Qt::Key_E] = KEY_E; qtKeyToVirtualKey[Qt::Key_F] = KEY_F; qtKeyToVirtualKey[Qt::Key_G] = KEY_G; qtKeyToVirtualKey[Qt::Key_H] = KEY_H; qtKeyToVirtualKey[Qt::Key_I] = KEY_I; qtKeyToVirtualKey[Qt::Key_J] = KEY_J; qtKeyToVirtualKey[Qt::Key_K] = KEY_K; qtKeyToVirtualKey[Qt::Key_L] = KEY_L; qtKeyToVirtualKey[Qt::Key_M] = KEY_M; qtKeyToVirtualKey[Qt::Key_N] = KEY_N; qtKeyToVirtualKey[Qt::Key_O] = KEY_O; qtKeyToVirtualKey[Qt::Key_P] = KEY_P; qtKeyToVirtualKey[Qt::Key_Q] = KEY_Q; qtKeyToVirtualKey[Qt::Key_R] = KEY_R; qtKeyToVirtualKey[Qt::Key_S] = KEY_S; qtKeyToVirtualKey[Qt::Key_T] = KEY_T; qtKeyToVirtualKey[Qt::Key_U] = KEY_U; qtKeyToVirtualKey[Qt::Key_V] = KEY_V; qtKeyToVirtualKey[Qt::Key_W] = KEY_W; qtKeyToVirtualKey[Qt::Key_X] = KEY_X; qtKeyToVirtualKey[Qt::Key_Y] = KEY_Y; qtKeyToVirtualKey[Qt::Key_Z] = KEY_Z; } void QtUInputKeyMapper::populateFKeyHashes() { // Map F1 - F10 for (int i=0; i <= (KEY_F10 - KEY_F1); i++) { qtKeyToVirtualKey[Qt::Key_F1 + i] = KEY_F1 + i; } // Map F11 and F12 for (int i=0; i <= (KEY_F12 - KEY_F11); i++) { qtKeyToVirtualKey[Qt::Key_F11 + i] = KEY_F11 + i; } // Map F13 - F24 for (int i=0; i <= (KEY_F24 - KEY_F13); i++) { qtKeyToVirtualKey[Qt::Key_F13 + i] = KEY_F13 + i; } } void QtUInputKeyMapper::populateNumPadHashes() { // Map Numpad 0 qtKeyToVirtualKey[AntKey_KP_0] = KEY_KP0; // Map Numpad 1 - 3 for (int i=0; i <= (KEY_KP3 - KEY_KP1); i++) { qtKeyToVirtualKey[AntKey_KP_1 + i] = KEY_KP1 + i; } // Map Numpad 4 - 6 for (int i=0; i <= (KEY_KP6 - KEY_KP4); i++) { qtKeyToVirtualKey[AntKey_KP_4 + i] = KEY_KP4 + i; } // Map Numpad 7 - 9 for (int i=0; i <= (KEY_KP9 - KEY_KP7); i++) { qtKeyToVirtualKey[AntKey_KP_7 + i] = KEY_KP7 + i; } } void QtUInputKeyMapper::populateSpecialCharHashes() { qtKeyToVirtualKey[Qt::Key_QuoteLeft] = KEY_GRAVE; qtKeyToVirtualKey[Qt::Key_Minus] = KEY_MINUS; qtKeyToVirtualKey[Qt::Key_Equal] = KEY_EQUAL; qtKeyToVirtualKey[Qt::Key_BracketLeft] = KEY_LEFTBRACE; qtKeyToVirtualKey[Qt::Key_BracketRight] = KEY_RIGHTBRACE; qtKeyToVirtualKey[Qt::Key_Semicolon] = KEY_SEMICOLON; qtKeyToVirtualKey[Qt::Key_Apostrophe] = KEY_APOSTROPHE; qtKeyToVirtualKey[Qt::Key_Comma] = KEY_COMMA; qtKeyToVirtualKey[Qt::Key_Period] = KEY_DOT; qtKeyToVirtualKey[Qt::Key_Slash] = KEY_SLASH; qtKeyToVirtualKey[Qt::Key_Backslash] = KEY_BACKSLASH; } void QtUInputKeyMapper::populateMappingHashes() { if (qtKeyToVirtualKey.isEmpty()) { // misc keys qtKeyToVirtualKey[Qt::Key_Escape] = KEY_ESC; qtKeyToVirtualKey[Qt::Key_Tab] = KEY_TAB; qtKeyToVirtualKey[Qt::Key_Backspace] = KEY_BACKSPACE; qtKeyToVirtualKey[Qt::Key_Return] = KEY_ENTER; qtKeyToVirtualKey[Qt::Key_Insert] = KEY_INSERT; qtKeyToVirtualKey[Qt::Key_Delete] = KEY_DELETE; qtKeyToVirtualKey[Qt::Key_Pause] = KEY_PAUSE; qtKeyToVirtualKey[Qt::Key_Print] = KEY_PRINT; qtKeyToVirtualKey[Qt::Key_Space] = KEY_SPACE; qtKeyToVirtualKey[Qt::Key_SysReq] = KEY_SYSRQ; qtKeyToVirtualKey[Qt::Key_PowerOff] = KEY_POWER; qtKeyToVirtualKey[Qt::Key_Stop] = KEY_STOP; qtKeyToVirtualKey[Qt::Key_Refresh] = KEY_REFRESH; qtKeyToVirtualKey[Qt::Key_Copy] = KEY_COPY; qtKeyToVirtualKey[Qt::Key_Paste] = KEY_PASTE; //qtKeyToVirtualKey[Qt::Key_Search] = KEY_FIND; qtKeyToVirtualKey[Qt::Key_Cut] = KEY_CUT; qtKeyToVirtualKey[Qt::Key_Sleep] = KEY_SLEEP; //qtKeyToVirtualKey[Qt::Key_Calculator] = KEY_CALC; qtKeyToVirtualKey[Qt::Key_Launch0] = KEY_COMPUTER; qtKeyToVirtualKey[Qt::Key_Launch1] = KEY_CALC; qtKeyToVirtualKey[Qt::Key_Launch2] = KEY_PROG1; qtKeyToVirtualKey[Qt::Key_Launch3] = KEY_PROG2; qtKeyToVirtualKey[Qt::Key_Launch4] = KEY_PROG3; qtKeyToVirtualKey[Qt::Key_Launch5] = KEY_PROG4; qtKeyToVirtualKey[Qt::Key_HomePage] = KEY_HOMEPAGE; qtKeyToVirtualKey[Qt::Key_LaunchMail] = KEY_MAIL; qtKeyToVirtualKey[Qt::Key_Back] = KEY_BACK; qtKeyToVirtualKey[Qt::Key_Favorites] = KEY_FAVORITES; qtKeyToVirtualKey[Qt::Key_Forward] = KEY_FORWARD; qtKeyToVirtualKey[Qt::Key_Suspend] = KEY_SUSPEND; qtKeyToVirtualKey[Qt::Key_Close] = KEY_CLOSE; //qtKeyToVirtualKey[Qt::Key_Search] = KEY_SEARCH; qtKeyToVirtualKey[Qt::Key_Camera] = KEY_CAMERA; qtKeyToVirtualKey[Qt::Key_MonBrightnessUp] = KEY_BRIGHTNESSUP; qtKeyToVirtualKey[Qt::Key_MonBrightnessDown] = KEY_BRIGHTNESSDOWN; qtKeyToVirtualKey[Qt::Key_Send] = KEY_SEND; qtKeyToVirtualKey[Qt::Key_Reply] = KEY_REPLY; qtKeyToVirtualKey[Qt::Key_Forward] = KEY_FORWARDMAIL; qtKeyToVirtualKey[Qt::Key_Save] = KEY_SAVE; qtKeyToVirtualKey[Qt::Key_Documents] = KEY_DOCUMENTS; qtKeyToVirtualKey[Qt::Key_Battery] = KEY_BATTERY; qtKeyToVirtualKey[Qt::Key_Bluetooth] = KEY_BLUETOOTH; qtKeyToVirtualKey[Qt::Key_WLAN] = KEY_WLAN; qtKeyToVirtualKey[Qt::Key_Cancel] = KEY_CANCEL; qtKeyToVirtualKey[Qt::Key_Shop] = KEY_SHOP; qtKeyToVirtualKey[Qt::Key_Finance] = KEY_FINANCE; qtKeyToVirtualKey[Qt::Key_Question] = KEY_QUESTION; qtKeyToVirtualKey[Qt::Key_BassBoost] = KEY_BASSBOOST; // cursor movement qtKeyToVirtualKey[Qt::Key_Home] = KEY_HOME; qtKeyToVirtualKey[Qt::Key_End] = KEY_END; qtKeyToVirtualKey[Qt::Key_Left] = KEY_LEFT; qtKeyToVirtualKey[Qt::Key_Up] = KEY_UP; qtKeyToVirtualKey[Qt::Key_Right] = KEY_RIGHT; qtKeyToVirtualKey[Qt::Key_Down] = KEY_DOWN; qtKeyToVirtualKey[Qt::Key_PageUp] = KEY_PAGEUP; qtKeyToVirtualKey[Qt::Key_PageDown] = KEY_PAGEDOWN; // modifiers qtKeyToVirtualKey[Qt::Key_Shift] = KEY_LEFTSHIFT; qtKeyToVirtualKey[Qt::Key_Control] = KEY_LEFTCTRL; qtKeyToVirtualKey[Qt::Key_Alt] = KEY_LEFTALT; qtKeyToVirtualKey[Qt::Key_CapsLock] = KEY_CAPSLOCK; qtKeyToVirtualKey[Qt::Key_NumLock] = KEY_NUMLOCK; qtKeyToVirtualKey[Qt::Key_ScrollLock] = KEY_SCROLLLOCK; qtKeyToVirtualKey[Qt::Key_Meta] = KEY_LEFTMETA; qtKeyToVirtualKey[AntKey_Meta_R] = KEY_RIGHTMETA; qtKeyToVirtualKey[Qt::Key_Menu] = KEY_COMPOSE; qtKeyToVirtualKey[Qt::Key_Help] = KEY_HELP; // media keys qtKeyToVirtualKey[Qt::Key_VolumeDown] = KEY_VOLUMEDOWN; qtKeyToVirtualKey[Qt::Key_VolumeMute] = KEY_MUTE; qtKeyToVirtualKey[Qt::Key_VolumeUp] = KEY_VOLUMEUP; qtKeyToVirtualKey[Qt::Key_MediaPlay] = KEY_PLAYPAUSE; qtKeyToVirtualKey[Qt::Key_MediaStop] = KEY_STOPCD; qtKeyToVirtualKey[Qt::Key_MediaPrevious] = KEY_PREVIOUSSONG; qtKeyToVirtualKey[Qt::Key_MediaNext] = KEY_NEXTSONG; qtKeyToVirtualKey[Qt::Key_MediaRecord] = KEY_RECORD; qtKeyToVirtualKey[Qt::Key_LaunchMedia] = KEY_MEDIA; // Map 0-9 keys for (unsigned int i=0; i <= (KEY_9 - KEY_1); i++) { qtKeyToVirtualKey[Qt::Key_1 + i] = KEY_1 + i; } qtKeyToVirtualKey[Qt::Key_0] = KEY_0; populateSpecialCharHashes(); populateAlphaHashes(); populateFKeyHashes(); populateNumPadHashes(); // Map custom defined keys qtKeyToVirtualKey[AntKey_Shift_R] = KEY_RIGHTSHIFT; qtKeyToVirtualKey[AntKey_Control_R] = KEY_RIGHTCTRL; qtKeyToVirtualKey[AntKey_Alt_R] = KEY_RIGHTALT; qtKeyToVirtualKey[AntKey_KP_Multiply] = KEY_KPASTERISK; // numeric and function keypad keys qtKeyToVirtualKey[Qt::Key_Enter] = KEY_KPENTER; qtKeyToVirtualKey[AntKey_KP_Home] = KEY_KP7; qtKeyToVirtualKey[AntKey_KP_Left] = KEY_KP4; qtKeyToVirtualKey[AntKey_KP_Up] = KEY_KP8; qtKeyToVirtualKey[AntKey_KP_Right] = KEY_KP6; qtKeyToVirtualKey[AntKey_KP_Down] = KEY_KP2; qtKeyToVirtualKey[AntKey_KP_Prior] = KEY_KP9; qtKeyToVirtualKey[AntKey_KP_Next] = KEY_KP3; qtKeyToVirtualKey[AntKey_KP_End] = KEY_KP1; qtKeyToVirtualKey[AntKey_KP_Begin] = KEY_KP5; qtKeyToVirtualKey[AntKey_KP_Insert] = KEY_KP0; qtKeyToVirtualKey[AntKey_KP_Add] = KEY_KPPLUS; qtKeyToVirtualKey[AntKey_KP_Subtract] = KEY_KPMINUS; qtKeyToVirtualKey[AntKey_KP_Decimal] = KEY_KPDOT; qtKeyToVirtualKey[AntKey_KP_Divide] = KEY_KPSLASH; /* // International input method support keys // International & multi-key character composition qtKeyToVirtualKey[Qt::Key_AltGr] = XK_ISO_Level3_Shift; qtKeyToVirtualKey[Qt::Key_Multi_key] = XK_Multi_key; qtKeyToVirtualKey[Qt::Key_Codeinput] = XK_Codeinput; qtKeyToVirtualKey[Qt::Key_SingleCandidate] = XK_SingleCandidate; qtKeyToVirtualKey[Qt::Key_MultipleCandidate] = XK_MultipleCandidate; qtKeyToVirtualKey[Qt::Key_PreviousCandidate] = XK_PreviousCandidate; // Misc Functions qtKeyToVirtualKey[Qt::Key_Mode_switch] = XK_Mode_switch; //qtKeyToX11KeySym[Qt::Key_Mode_switch] = XK_script_switch; // Japanese keyboard support qtKeyToVirtualKey[Qt::Key_Kanji] = XK_Kanji; qtKeyToVirtualKey[Qt::Key_Muhenkan] = XK_Muhenkan; qtKeyToVirtualKey[Qt::Key_Henkan] = XK_Henkan_Mode; //qtKeyToX11KeySym[Qt::Key_Henkan] = XK_Henkan; qtKeyToVirtualKey[Qt::Key_Romaji] = XK_Romaji; qtKeyToVirtualKey[Qt::Key_Hiragana] = XK_Hiragana; qtKeyToVirtualKey[Qt::Key_Katakana] = XK_Katakana; qtKeyToVirtualKey[Qt::Key_Hiragana_Katakana] = XK_Hiragana_Katakana; qtKeyToVirtualKey[Qt::Key_Zenkaku] = XK_Zenkaku; qtKeyToVirtualKey[Qt::Key_Hankaku] = XK_Hankaku; qtKeyToVirtualKey[Qt::Key_Zenkaku_Hankaku] = XK_Zenkaku_Hankaku; qtKeyToVirtualKey[Qt::Key_Touroku] = XK_Touroku; qtKeyToVirtualKey[Qt::Key_Massyo] = XK_Massyo; qtKeyToVirtualKey[Qt::Key_Kana_Lock] = XK_Kana_Lock; qtKeyToVirtualKey[Qt::Key_Kana_Shift] = XK_Kana_Shift; qtKeyToVirtualKey[Qt::Key_Eisu_Shift] = XK_Eisu_Shift; qtKeyToVirtualKey[Qt::Key_Eisu_toggle] = XK_Eisu_toggle; qtKeyToVirtualKey[Qt::Key_Codeinput] = XK_Kanji_Bangou; //qtKeyToX11KeySym[Qt::Key_MultipleCandidate] = XK_Zen_Koho; //qtKeyToX11KeySym[Qt::Key_PreviousCandidate] = XK_Mae_Koho; #ifdef XK_KOREAN qtKeyToVirtualKey[Qt::Key_Hangul] = XK_Hangul; qtKeyToVirtualKey[Qt::Key_Hangul_Start] = XK_Hangul_Start; qtKeyToVirtualKey[Qt::Key_Hangul_End] = XK_Hangul_End; qtKeyToVirtualKey[Qt::Key_Hangul_Hanja] = XK_Hangul_Hanja; qtKeyToVirtualKey[Qt::Key_Hangul_Jamo] = XK_Hangul_Jamo; qtKeyToVirtualKey[Qt::Key_Hangul_Romaja] = XK_Hangul_Romaja; //qtKeyToX11KeySym[Qt::Key_Codeinput] = XK_Hangul_Codeinput; qtKeyToVirtualKey[Qt::Key_Hangul_Jeonja] = XK_Hangul_Jeonja; qtKeyToVirtualKey[Qt::Key_Hangul_Banja] = XK_Hangul_Banja; qtKeyToVirtualKey[Qt::Key_Hangul_PreHanja] = XK_Hangul_PreHanja; qtKeyToVirtualKey[Qt::Key_Hangul_PostHanja] = XK_Hangul_PostHanja; //qtKeyToX11KeySym[Qt::Key_SingleCandidate] = XK_Hangul_SingleCandidate; //qtKeyToX11KeySym[Qt::Key_MultipleCandidate] = XK_Hangul_MultipleCandidate; //qtKeyToX11KeySym[Qt::Key_PreviousCandidate] = XK_Hangul_PreviousCandidate; qtKeyToVirtualKey[Qt::Key_Hangul_Special] = XK_Hangul_Special; //qtKeyToX11KeySym[Qt::Key_Mode_switch] = XK_Hangul_switch; #endif // XK_KOREAN // Special multimedia keys // currently only tested with MS internet keyboard // browsing keys qtKeyToVirtualKey[Qt::Key_Back] = XF86XK_Back; qtKeyToVirtualKey[Qt::Key_Forward] = XF86XK_Forward; qtKeyToVirtualKey[Qt::Key_Stop] = XF86XK_Stop; qtKeyToVirtualKey[Qt::Key_Refresh] = XF86XK_Refresh; qtKeyToVirtualKey[Qt::Key_Favorites] = XF86XK_Favorites; qtKeyToVirtualKey[Qt::Key_LaunchMedia] = XF86XK_AudioMedia; qtKeyToVirtualKey[Qt::Key_OpenUrl] = XF86XK_OpenURL; qtKeyToVirtualKey[Qt::Key_HomePage] = XF86XK_HomePage; qtKeyToVirtualKey[Qt::Key_Search] = XF86XK_Search; */ // Populate other hash. Flip key and value so mapping // goes VK -> Qt Key. QHashIterator iter(qtKeyToVirtualKey); while (iter.hasNext()) { iter.next(); virtualKeyToQtKey[iter.value()] = iter.key(); } /*int j = 0; for (int i=KEY_ESC; i < KEY_UNKNOWN; i++) { if (!virtualKeyToQtKey.contains(i) && i != 84) { qDebug() << "KEY MISSING: " << QString::number(i); j++; } } qDebug() << "TOTAL MISSING: " << j; */ // Override some entries. virtualKeyToQtKey[KEY_KP0] = AntKey_KP_0; virtualKeyToQtKey[KEY_KP1] = AntKey_KP_1; virtualKeyToQtKey[KEY_KP2] = AntKey_KP_2; virtualKeyToQtKey[KEY_KP3] = AntKey_KP_3; virtualKeyToQtKey[KEY_KP4] = AntKey_KP_4; virtualKeyToQtKey[KEY_KP5] = AntKey_KP_5; virtualKeyToQtKey[KEY_KP6] = AntKey_KP_6; virtualKeyToQtKey[KEY_KP7] = AntKey_KP_7; virtualKeyToQtKey[KEY_KP8] = AntKey_KP_8; virtualKeyToQtKey[KEY_KP9] = AntKey_KP_9; virtualKeyToQtKey[KEY_CALC] = Qt::Key_Launch1; } } void QtUInputKeyMapper::populateCharKeyInformation() { virtualkeyToCharKeyInformation.clear(); unsigned int unicodeTempValue = 0; unsigned int listIndex = 0; charKeyInformation temp; temp.modifiers = Qt::NoModifier; temp.virtualkey = 0; // Map 0-9 keys for (unsigned int i=QChar('1').unicode(); i <= QChar('9').unicode(); i++) { temp.virtualkey = KEY_1 + i; virtualkeyToCharKeyInformation.insert(i, temp); } temp.virtualkey = KEY_0; virtualkeyToCharKeyInformation.insert(QChar('0').unicode(), temp); temp.virtualkey = KEY_MINUS; virtualkeyToCharKeyInformation.insert(QChar('-').unicode(), temp); temp.virtualkey = KEY_EQUAL; virtualkeyToCharKeyInformation.insert(QChar('=').unicode(), temp); QList tempKeys; tempKeys.append(KEY_A); tempKeys.append(KEY_B); tempKeys.append(KEY_C); tempKeys.append(KEY_D); tempKeys.append(KEY_E); tempKeys.append(KEY_F); tempKeys.append(KEY_G); tempKeys.append(KEY_H); tempKeys.append(KEY_I); tempKeys.append(KEY_J); tempKeys.append(KEY_K); tempKeys.append(KEY_L); tempKeys.append(KEY_M); tempKeys.append(KEY_N); tempKeys.append(KEY_O); tempKeys.append(KEY_P); tempKeys.append(KEY_Q); tempKeys.append(KEY_R); tempKeys.append(KEY_S); tempKeys.append(KEY_T); tempKeys.append(KEY_U); tempKeys.append(KEY_V); tempKeys.append(KEY_W); tempKeys.append(KEY_X); tempKeys.append(KEY_Y); tempKeys.append(KEY_Z); unicodeTempValue = QChar('a').unicode(); QListIterator tempIter(tempKeys); while (tempIter.hasNext()) { temp.virtualkey = tempIter.next(); virtualkeyToCharKeyInformation.insert(unicodeTempValue, temp); unicodeTempValue++; } tempIter.toFront(); temp.modifiers = Qt::ShiftModifier; unicodeTempValue = QChar('A').unicode(); while (tempIter.hasNext()) { temp.virtualkey = tempIter.next(); virtualkeyToCharKeyInformation.insert(unicodeTempValue, temp); unicodeTempValue++; } tempKeys.clear(); temp.modifiers = Qt::ShiftModifier; tempKeys.append(QChar('!').unicode()); tempKeys.append(QChar('@').unicode()); tempKeys.append(QChar('#').unicode()); tempKeys.append(QChar('$').unicode()); tempKeys.append(QChar('%').unicode()); tempKeys.append(QChar('^').unicode()); tempKeys.append(QChar('&').unicode()); tempKeys.append(QChar('*').unicode()); tempKeys.append(QChar('(').unicode()); tempKeys.append(QChar(')').unicode()); tempKeys.append(QChar('_').unicode()); tempKeys.append(QChar('+').unicode()); tempIter = QListIterator(tempKeys); listIndex = 0; while (tempIter.hasNext()) { unicodeTempValue = tempIter.next(); temp.virtualkey = KEY_1 + listIndex; virtualkeyToCharKeyInformation.insert(unicodeTempValue, temp); listIndex++; } tempKeys.clear(); temp.modifiers = Qt::NoModifier; temp.virtualkey = KEY_SPACE; unicodeTempValue = QChar(' ').unicode(); virtualkeyToCharKeyInformation.insert(unicodeTempValue, temp); temp.virtualkey = KEY_LEFTBRACE; unicodeTempValue = QChar('[').unicode(); virtualkeyToCharKeyInformation.insert(unicodeTempValue, temp); temp.virtualkey = KEY_RIGHTBRACE; unicodeTempValue = QChar(']').unicode(); virtualkeyToCharKeyInformation.insert(unicodeTempValue, temp); temp.virtualkey = KEY_BACKSLASH; unicodeTempValue = QChar('\\').unicode(); virtualkeyToCharKeyInformation.insert(unicodeTempValue, temp); temp.virtualkey = KEY_SEMICOLON; unicodeTempValue = QChar(';').unicode(); virtualkeyToCharKeyInformation.insert(unicodeTempValue, temp); temp.virtualkey = KEY_APOSTROPHE; unicodeTempValue = QChar('\'').unicode(); virtualkeyToCharKeyInformation.insert(unicodeTempValue, temp); temp.virtualkey = KEY_COMMA; unicodeTempValue = QChar(',').unicode(); virtualkeyToCharKeyInformation.insert(unicodeTempValue, temp); temp.virtualkey = KEY_DOT; unicodeTempValue = QChar('.').unicode(); virtualkeyToCharKeyInformation.insert(unicodeTempValue, temp); temp.virtualkey = KEY_SLASH; unicodeTempValue = QChar('/').unicode(); virtualkeyToCharKeyInformation.insert(unicodeTempValue, temp); temp.modifiers = Qt::ShiftModifier; temp.virtualkey = KEY_LEFTBRACE; unicodeTempValue = QChar('{').unicode(); virtualkeyToCharKeyInformation.insert(unicodeTempValue, temp); temp.virtualkey = KEY_RIGHTBRACE; unicodeTempValue = QChar('}').unicode(); virtualkeyToCharKeyInformation.insert(unicodeTempValue, temp); temp.virtualkey = KEY_BACKSLASH; unicodeTempValue = QChar('|').unicode(); virtualkeyToCharKeyInformation.insert(unicodeTempValue, temp); temp.virtualkey = KEY_SEMICOLON; unicodeTempValue = QChar(':').unicode(); virtualkeyToCharKeyInformation.insert(unicodeTempValue, temp); temp.virtualkey = KEY_APOSTROPHE; unicodeTempValue = QChar('"').unicode(); virtualkeyToCharKeyInformation.insert(unicodeTempValue, temp); temp.virtualkey = KEY_COMMA; unicodeTempValue = QChar('<').unicode(); virtualkeyToCharKeyInformation.insert(unicodeTempValue, temp); temp.virtualkey = KEY_DOT; unicodeTempValue = QChar('>').unicode(); virtualkeyToCharKeyInformation.insert(unicodeTempValue, temp); temp.virtualkey = KEY_SLASH; unicodeTempValue = QChar('?').unicode(); virtualkeyToCharKeyInformation.insert(unicodeTempValue, temp); } antimicro-2.23/src/qtuinputkeymapper.h000066400000000000000000000024051300750276700202040ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef QTUINPUTKEYMAPPER_H #define QTUINPUTKEYMAPPER_H #include #include #include "qtkeymapperbase.h" class QtUInputKeyMapper : public QtKeyMapperBase { Q_OBJECT public: explicit QtUInputKeyMapper(QObject *parent = 0); protected: void populateMappingHashes(); void populateCharKeyInformation(); void populateAlphaHashes(); void populateFKeyHashes(); void populateNumPadHashes(); void populateSpecialCharHashes(); signals: public slots: }; #endif // QTUINPUTKEYMAPPER_H antimicro-2.23/src/qtvmultikeymapper.cpp000066400000000000000000000161671300750276700205450ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "qtvmultikeymapper.h" QtVMultiKeyMapper::QtVMultiKeyMapper(QObject *parent) : QtKeyMapperBase(parent) { identifier = "vmulti"; populateMappingHashes(); } void QtVMultiKeyMapper::populateMappingHashes() { if (qtKeyToVirtualKey.isEmpty()) { // Map A - Z keys for (int i=0; i <= (Qt::Key_Z - Qt::Key_A); i++) { qtKeyToVirtualKey[Qt::Key_A + i] = 0x04 + i; } // Map 1 - 9 numeric keys for (int i=0; i <= (Qt::Key_9 - Qt::Key_1); i++) { qtKeyToVirtualKey[Qt::Key_1 + i] = 0x1E + i; } // Map 0 numeric key qtKeyToVirtualKey[Qt::Key_0] = 0x27; qtKeyToVirtualKey[Qt::Key_Return] = 0x28; qtKeyToVirtualKey[Qt::Key_Escape] = 0x29; qtKeyToVirtualKey[Qt::Key_Backspace] = 0x2A; qtKeyToVirtualKey[Qt::Key_Tab] = 0x2B; qtKeyToVirtualKey[Qt::Key_Space] = 0x2C; qtKeyToVirtualKey[Qt::Key_Minus] = 0x2D; qtKeyToVirtualKey[Qt::Key_Equal] = 0x2E; qtKeyToVirtualKey[Qt::Key_BracketLeft] = 0x2F; qtKeyToVirtualKey[Qt::Key_BracketRight] = 0x30; qtKeyToVirtualKey[Qt::Key_Backslash] = 0x31; qtKeyToVirtualKey[Qt::Key_NumberSign] = 0x32; qtKeyToVirtualKey[Qt::Key_Semicolon] = 0x33; qtKeyToVirtualKey[Qt::Key_Apostrophe] = 0x34; qtKeyToVirtualKey[Qt::Key_QuoteLeft] = 0x35; qtKeyToVirtualKey[Qt::Key_Comma] = 0x36; qtKeyToVirtualKey[Qt::Key_Period] = 0x37; qtKeyToVirtualKey[Qt::Key_Slash] = 0x38; qtKeyToVirtualKey[Qt::Key_CapsLock] = 0x39; // Map F1 - F12 keys for (int i=0; i <= (Qt::Key_F12 - Qt::Key_F1); i++) { qtKeyToVirtualKey[Qt::Key_F1 + i] = 0x3A + i; } qtKeyToVirtualKey[Qt::Key_Print] = 0x46; qtKeyToVirtualKey[Qt::Key_ScrollLock] = 0x47; qtKeyToVirtualKey[Qt::Key_Pause] = 0x48; qtKeyToVirtualKey[Qt::Key_Insert] = 0x49; qtKeyToVirtualKey[Qt::Key_Home] = 0x4A; qtKeyToVirtualKey[Qt::Key_PageUp] = 0x4B; qtKeyToVirtualKey[Qt::Key_Delete] = 0x4C; qtKeyToVirtualKey[Qt::Key_End] = 0x4D; qtKeyToVirtualKey[Qt::Key_PageDown] = 0x4E; qtKeyToVirtualKey[Qt::Key_Right] = 0x4F; qtKeyToVirtualKey[Qt::Key_Left] = 0x50; qtKeyToVirtualKey[Qt::Key_Down] = 0x51; qtKeyToVirtualKey[Qt::Key_Up] = 0x52; qtKeyToVirtualKey[Qt::Key_NumLock] = 0x53; qtKeyToVirtualKey[AntKey_KP_Divide] = 0x54; qtKeyToVirtualKey[AntKey_KP_Multiply] = 0x55; qtKeyToVirtualKey[AntKey_KP_Subtract] = 0x56; qtKeyToVirtualKey[AntKey_KP_Add] = 0x57; qtKeyToVirtualKey[Qt::Key_Enter] = 0x58; // Map Numpad 1 - 9 keys for (int i=0; i <= (AntKey_KP_9 - AntKey_KP_1); i++) { qtKeyToVirtualKey[AntKey_KP_1 + i] = 0x59 + i; } // Map Numpad 0 key qtKeyToVirtualKey[AntKey_KP_0] = 0x62; qtKeyToVirtualKey[AntKey_KP_Decimal] = 0x63; //qtKeyToVirtualKey[Qt::Key_Backslash] = 0x64; qtKeyToVirtualKey[Qt::Key_ApplicationLeft] = 0x65; qtKeyToVirtualKey[Qt::Key_PowerOff] = 0x66; //qtKeyToVirtualKey[] = 0x67; for (int i=0; i <= (Qt::Key_F24 - Qt::Key_F13); i++) { qtKeyToVirtualKey[Qt::Key_F13 + i] = 0x68 + i; } qtKeyToVirtualKey[Qt::Key_Execute] = 0x74; qtKeyToVirtualKey[Qt::Key_Help] = 0x75; qtKeyToVirtualKey[Qt::Key_Menu] = 0x76; qtKeyToVirtualKey[Qt::Key_Select] = 0x77; qtKeyToVirtualKey[Qt::Key_Stop] = 0x78; //qtKeyToVirtualKey[] = 0x79; qtKeyToVirtualKey[Qt::Key_Undo] = 0x7A; qtKeyToVirtualKey[Qt::Key_Cut] = 0x7B; qtKeyToVirtualKey[Qt::Key_Copy] = 0x7C; qtKeyToVirtualKey[Qt::Key_Paste] = 0x7D; qtKeyToVirtualKey[Qt::Key_Find] = 0x7E; qtKeyToVirtualKey[Qt::Key_VolumeMute] = 0x7F; qtKeyToVirtualKey[Qt::Key_VolumeUp] = 0x80; qtKeyToVirtualKey[Qt::Key_VolumeDown] = 0x81; //qtKeyToVirtualKey[] = 0x82; //qtKeyToVirtualKey[] = 0x83; //qtKeyToVirtualKey[] = 0x84; //qtKeyToVirtualKey[] = 0x85; // International Keys? //qtKeyToVirtualKey[] = 0x87; //qtKeyToVirtualKey[] = 0x88; //qtKeyToVirtualKey[] = 0x89; //qtKeyToVirtualKey[] = 0x8A; //qtKeyToVirtualKey[] = 0x8B; //qtKeyToVirtualKey[] = 0x8C; //qtKeyToVirtualKey[] = 0x8D; //qtKeyToVirtualKey[] = 0x8E; //qtKeyToVirtualKey[] = 0x8F; qtKeyToVirtualKey[Qt::Key_Control] = 0xE0; qtKeyToVirtualKey[Qt::Key_Shift] = 0xE1; qtKeyToVirtualKey[Qt::Key_Alt] = 0xE2; qtKeyToVirtualKey[Qt::Key_Meta] = 0xE3; qtKeyToVirtualKey[AntKey_Control_R] = 0xE4; qtKeyToVirtualKey[AntKey_Shift_R] = 0xE5; qtKeyToVirtualKey[AntKey_Meta_R] = 0xE7; qtKeyToVirtualKey[Qt::Key_MediaPause] = 0xB1 | consumerUsagePagePrefix; qtKeyToVirtualKey[Qt::Key_MediaNext] = 0xB5 | consumerUsagePagePrefix; qtKeyToVirtualKey[Qt::Key_MediaPrevious] = 0xB6 | consumerUsagePagePrefix; qtKeyToVirtualKey[Qt::Key_MediaStop] = 0xB7 | consumerUsagePagePrefix; qtKeyToVirtualKey[Qt::Key_HomePage] = 0x189 | consumerUsagePagePrefix; qtKeyToVirtualKey[Qt::Key_Launch0] = 0x194 | consumerUsagePagePrefix; qtKeyToVirtualKey[Qt::Key_Calculator] = 0x192 | consumerUsagePagePrefix; qtKeyToVirtualKey[Qt::Key_Favorites] = 0x22a | consumerUsagePagePrefix; qtKeyToVirtualKey[Qt::Key_Search] = 0x221 | consumerUsagePagePrefix; qtKeyToVirtualKey[Qt::Key_Stop] = 0x226 | consumerUsagePagePrefix; qtKeyToVirtualKey[Qt::Key_Back] = 0x224 | consumerUsagePagePrefix; qtKeyToVirtualKey[Qt::Key_LaunchMedia] = 0x87 | consumerUsagePagePrefix; qtKeyToVirtualKey[Qt::Key_LaunchMail] = 0x18a | consumerUsagePagePrefix; // Populate other hash. Flip key and value so mapping // goes VK -> Qt Key. QHashIterator iter(qtKeyToVirtualKey); while (iter.hasNext()) { iter.next(); virtualKeyToQtKey[iter.value()] = iter.key(); } } } void QtVMultiKeyMapper::populateCharKeyInformation() { } antimicro-2.23/src/qtvmultikeymapper.h000066400000000000000000000024671300750276700202100ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef QTVMULTIKEYMAPPER_H #define QTVMULTIKEYMAPPER_H #include #include #include "qtkeymapperbase.h" #include "qtwinkeymapper.h" class QtVMultiKeyMapper : public QtKeyMapperBase { Q_OBJECT public: explicit QtVMultiKeyMapper(QObject *parent = 0); static const unsigned int consumerUsagePagePrefix = 0x12000; protected: void populateMappingHashes(); void populateCharKeyInformation(); //static QtWinKeyMapper nativeKeyMapper; signals: public slots: }; #endif // QTVMULTIKEYMAPPER_H antimicro-2.23/src/qtwinkeymapper.cpp000066400000000000000000000376421300750276700200230ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include //#include #include #include "winextras.h" #include "qtwinkeymapper.h" static QHash initDynamicKeyMapping() { QHash temp; temp[VK_OEM_1] = 0; //temp[VK_OEM_PLUS] = 0; //temp[VK_OEM_COMMA] = 0; //temp[VK_OEM_MINUS] = 0; //temp[VK_OEM_PERIOD] = 0; temp[VK_OEM_2] = 0; temp[VK_OEM_3] = 0; temp[VK_OEM_4] = 0; temp[VK_OEM_5] = 0; temp[VK_OEM_6] = 0; temp[VK_OEM_7] = 0; temp[VK_OEM_8] = 0; temp[VK_OEM_102] = 0; return temp; } static QHash intCharToQtKey() { QHash temp; temp.insert(QString('!'), Qt::Key_Exclam); temp.insert(QString('"'), Qt::Key_QuoteDbl); temp.insert(QString('#'), Qt::Key_NumberSign); temp.insert(QString('$'), Qt::Key_Dollar); temp.insert(QString('\''), Qt::Key_Apostrophe); temp.insert(QString('('), Qt::Key_ParenLeft); temp.insert(QString(')'), Qt::Key_ParenRight); temp.insert(QString('*'), Qt::Key_Asterisk); temp.insert(QString('+'), Qt::Key_Plus); temp.insert(QString(','), Qt::Key_Comma); temp.insert(QString('-'), Qt::Key_Minus); temp.insert(QString('.'), Qt::Key_Period); temp.insert(QString('/'), Qt::Key_Slash); temp.insert(QString(':'), Qt::Key_Colon); temp.insert(QString(';'), Qt::Key_Semicolon); temp.insert(QString('<'), Qt::Key_Less); temp.insert(QString('='), Qt::Key_Equal); temp.insert(QString('>'), Qt::Key_Greater); temp.insert(QString('@'), Qt::Key_At); temp.insert(QString('['), Qt::Key_BracketLeft); temp.insert(QString('\\'), Qt::Key_Backslash); temp.insert(QString(']'), Qt::Key_BracketRight); temp.insert(QString('^'), Qt::Key_AsciiCircum); temp.insert(QString('_'), Qt::Key_Underscore); temp.insert(QString('`'), Qt::Key_QuoteLeft); temp.insert(QString('{'), Qt::Key_BraceLeft); temp.insert(QString('}'), Qt::Key_BraceRight); temp.insert(QString::fromUtf8("\u00A1"), Qt::Key_exclamdown); temp.insert(QString('~'), Qt::Key_AsciiTilde); //temp.insert(QString::fromUtf8("\u20A0"), Qt::Key_) return temp; } static QHash initDeadKeyToQtKey() { QHash temp; //temp.insert(QString('`'), Qt::Key_Dead_Grave); //temp.insert(QString('\''), Qt::Key_Dead_Acute); temp.insert(QString::fromUtf8("\u00B4"), Qt::Key_Dead_Grave); //temp.insert(QString('^'), Qt::Key_Dead_Circumflex); //temp.insert(QString('~'), Qt::Key_Dead_Tilde); temp.insert(QString::fromUtf8("\u02DC"), Qt::Key_Dead_Tilde); temp.insert(QString::fromUtf8("\u00AF"), Qt::Key_Dead_Macron); temp.insert(QString::fromUtf8("\u02D8"), Qt::Key_Dead_Breve); temp.insert(QString::fromUtf8("\u02D9"), Qt::Key_Dead_Abovedot); //temp.insert(QString('"'), Qt::Key_Dead_Diaeresis); temp.insert(QString::fromUtf8("\u00A8"), Qt::Key_Dead_Diaeresis); temp.insert(QString::fromUtf8("\u02DA"), Qt::Key_Dead_Abovering); temp.insert(QString::fromUtf8("\u02DD"), Qt::Key_Dead_Doubleacute); temp.insert(QString::fromUtf8("\u02C7"), Qt::Key_Dead_Caron); //temp.insert(QString(','), Qt::Key_Dead_Cedilla); temp.insert(QString::fromUtf8("\u00B8"), Qt::Key_Dead_Cedilla); temp.insert(QString::fromUtf8("\u02DB"), Qt::Key_Dead_Ogonek); temp.insert(QString::fromUtf8("\u037A"), Qt::Key_Dead_Iota); temp.insert(QString::fromUtf8("\u309B"), Qt::Key_Dead_Voiced_Sound); temp.insert(QString::fromUtf8("\u309C"), Qt::Key_Dead_Semivoiced_Sound); return temp; } static QHash dynamicOEMToQtKeyHash = initDynamicKeyMapping(); static QHash charToQtKeyHash = intCharToQtKey(); static QHash deadKeyToQtKeyHash = initDeadKeyToQtKey(); QtWinKeyMapper::QtWinKeyMapper(QObject *parent) : QtKeyMapperBase(parent) { identifier = "sendinput"; populateMappingHashes(); populateCharKeyInformation(); } void QtWinKeyMapper::populateMappingHashes() { if (qtKeyToVirtualKey.isEmpty()) { qtKeyToVirtualKey[Qt::Key_Cancel] = VK_CANCEL; qtKeyToVirtualKey[Qt::Key_Backspace] = VK_BACK; qtKeyToVirtualKey[Qt::Key_Tab] = VK_TAB; qtKeyToVirtualKey[Qt::Key_Clear] = VK_CLEAR; qtKeyToVirtualKey[Qt::Key_Return] = VK_RETURN; qtKeyToVirtualKey[Qt::Key_Enter] = VK_RETURN; //qtKeyToWinVirtualKey[Qt::Key_Shift] = VK_SHIFT; //qtKeyToWinVirtualKey[Qt::Key_Control] = VK_CONTROL; //qtKeyToWinVirtualKey[Qt::Key_Alt] = VK_MENU; qtKeyToVirtualKey[Qt::Key_Pause] = VK_PAUSE; qtKeyToVirtualKey[Qt::Key_CapsLock] = VK_CAPITAL; qtKeyToVirtualKey[Qt::Key_Escape] = VK_ESCAPE; qtKeyToVirtualKey[Qt::Key_Mode_switch] = VK_MODECHANGE; qtKeyToVirtualKey[Qt::Key_Space] = VK_SPACE; qtKeyToVirtualKey[Qt::Key_PageUp] = VK_PRIOR; qtKeyToVirtualKey[Qt::Key_PageDown] = VK_NEXT; qtKeyToVirtualKey[Qt::Key_End] = VK_END; qtKeyToVirtualKey[Qt::Key_Home] = VK_HOME; qtKeyToVirtualKey[Qt::Key_Left] = VK_LEFT; qtKeyToVirtualKey[Qt::Key_Up] = VK_UP; qtKeyToVirtualKey[Qt::Key_Right] = VK_RIGHT; qtKeyToVirtualKey[Qt::Key_Down] = VK_DOWN; qtKeyToVirtualKey[Qt::Key_Select] = VK_SELECT; qtKeyToVirtualKey[Qt::Key_Printer] = VK_PRINT; qtKeyToVirtualKey[Qt::Key_Execute] = VK_EXECUTE; qtKeyToVirtualKey[Qt::Key_Print] = VK_SNAPSHOT; qtKeyToVirtualKey[Qt::Key_Insert] = VK_INSERT; qtKeyToVirtualKey[Qt::Key_Delete] = VK_DELETE; qtKeyToVirtualKey[Qt::Key_Help] = VK_HELP; qtKeyToVirtualKey[Qt::Key_Meta] = VK_LWIN; //qtKeyToWinVirtualKey[Qt::Key_Meta] = VK_RWIN; qtKeyToVirtualKey[Qt::Key_Menu] = VK_APPS; qtKeyToVirtualKey[Qt::Key_Sleep] = VK_SLEEP; qtKeyToVirtualKey[AntKey_KP_Multiply] = VK_MULTIPLY; //qtKeyToVirtualKey[Qt::Key_Asterisk] = VK_MULTIPLY; qtKeyToVirtualKey[AntKey_KP_Add] = VK_ADD; //qtKeyToVirtualKey[Qt::Key_Comma] = VK_SEPARATOR; qtKeyToVirtualKey[AntKey_KP_Subtract] = VK_SUBTRACT; qtKeyToVirtualKey[AntKey_KP_Decimal] = VK_DECIMAL; qtKeyToVirtualKey[AntKey_KP_Divide] = VK_DIVIDE; qtKeyToVirtualKey[Qt::Key_NumLock] = VK_NUMLOCK; qtKeyToVirtualKey[Qt::Key_ScrollLock] = VK_SCROLL; qtKeyToVirtualKey[Qt::Key_Massyo] = VK_OEM_FJ_MASSHOU; qtKeyToVirtualKey[Qt::Key_Touroku] = VK_OEM_FJ_TOUROKU; qtKeyToVirtualKey[Qt::Key_Shift] = VK_LSHIFT; //qtKeyToWinVirtualKey[Qt::Key_Shift] = VK_RSHIFT; qtKeyToVirtualKey[Qt::Key_Control] = VK_LCONTROL; //qtKeyToWinVirtualKey[Qt::Key_Control] = VK_RCONTROL; qtKeyToVirtualKey[Qt::Key_Alt] = VK_LMENU; //qtKeyToWinVirtualKey[Qt::Key_Alt] = VK_RMENU; qtKeyToVirtualKey[Qt::Key_Back] = VK_BROWSER_BACK; qtKeyToVirtualKey[Qt::Key_Forward] = VK_BROWSER_FORWARD; qtKeyToVirtualKey[Qt::Key_Refresh] = VK_BROWSER_REFRESH; qtKeyToVirtualKey[Qt::Key_Stop] = VK_BROWSER_STOP; qtKeyToVirtualKey[Qt::Key_Search] = VK_BROWSER_SEARCH; qtKeyToVirtualKey[Qt::Key_Favorites] = VK_BROWSER_FAVORITES; qtKeyToVirtualKey[Qt::Key_HomePage] = VK_BROWSER_HOME; qtKeyToVirtualKey[Qt::Key_VolumeMute] = VK_VOLUME_MUTE; qtKeyToVirtualKey[Qt::Key_VolumeDown] = VK_VOLUME_DOWN; qtKeyToVirtualKey[Qt::Key_VolumeUp] = VK_VOLUME_UP; qtKeyToVirtualKey[Qt::Key_MediaNext] = VK_MEDIA_NEXT_TRACK; qtKeyToVirtualKey[Qt::Key_MediaPrevious] = VK_MEDIA_PREV_TRACK; qtKeyToVirtualKey[Qt::Key_MediaStop] = VK_MEDIA_STOP; qtKeyToVirtualKey[Qt::Key_MediaPlay] = VK_MEDIA_PLAY_PAUSE; qtKeyToVirtualKey[Qt::Key_LaunchMail] = VK_LAUNCH_MAIL; qtKeyToVirtualKey[Qt::Key_LaunchMedia] = VK_LAUNCH_MEDIA_SELECT; qtKeyToVirtualKey[Qt::Key_Launch0] = VK_LAUNCH_APP1; qtKeyToVirtualKey[Qt::Key_Launch1] = VK_LAUNCH_APP2; qtKeyToVirtualKey[Qt::Key_Kanji] = VK_KANJI; // The following VK_OEM_* keys are consistent across all // keyboard layouts. qtKeyToVirtualKey[Qt::Key_Equal] = VK_OEM_PLUS; qtKeyToVirtualKey[Qt::Key_Minus] = VK_OEM_MINUS; qtKeyToVirtualKey[Qt::Key_Period] = VK_OEM_PERIOD; qtKeyToVirtualKey[Qt::Key_Comma] = VK_OEM_COMMA; /*qtKeyToVirtualKey[Qt::Key_Semicolon] = VK_OEM_1; qtKeyToVirtualKey[Qt::Key_Slash] = VK_OEM_2; qtKeyToVirtualKey[Qt::Key_Equal] = VK_OEM_PLUS; qtKeyToVirtualKey[Qt::Key_Minus] = VK_OEM_MINUS; qtKeyToVirtualKey[Qt::Key_Period] = VK_OEM_PERIOD; qtKeyToVirtualKey[Qt::Key_QuoteLeft] = VK_OEM_3; qtKeyToVirtualKey[Qt::Key_BracketLeft] = VK_OEM_4; qtKeyToVirtualKey[Qt::Key_Backslash] = VK_OEM_5; qtKeyToVirtualKey[Qt::Key_BracketRight] = VK_OEM_6; qtKeyToVirtualKey[Qt::Key_Apostrophe] = VK_OEM_7;*/ qtKeyToVirtualKey[Qt::Key_Play] = VK_PLAY; qtKeyToVirtualKey[Qt::Key_Zoom] = VK_ZOOM; //qtKeyToWinVirtualKey[Qt::Key_Clear] = VK_OEM_CLEAR; // Map 0-9 ASCII codes for (int i=0; i <= (0x39 - 0x30); i++) { qtKeyToVirtualKey[Qt::Key_0 + i] = 0x30 + i; } // Map A-Z ASCII codes for (int i=0; i <= (0x5a - 0x41); i++) { qtKeyToVirtualKey[Qt::Key_A + i] = 0x41 + i; } // Map function keys for (int i=0; i <= (VK_F24 - VK_F1); i++) { qtKeyToVirtualKey[Qt::Key_F1 + i] = VK_F1 + i; } // Map numpad keys for (int i=0; i <= (VK_NUMPAD9 - VK_NUMPAD0); i++) { qtKeyToVirtualKey[AntKey_KP_0 + i] = VK_NUMPAD0 + i; } // Map custom keys qtKeyToVirtualKey[AntKey_Alt_R] = VK_RMENU; qtKeyToVirtualKey[AntKey_Meta_R] = VK_RWIN; qtKeyToVirtualKey[AntKey_Shift_R] = VK_RSHIFT; qtKeyToVirtualKey[AntKey_Control_R] = VK_RCONTROL; // Go through VK_OEM_* values and find the appropriate association // with a key defined in Qt. Association is decided based on char // returned from Windows for the VK_OEM_* key. QHashIterator iterDynamic(dynamicOEMToQtKeyHash); while (iterDynamic.hasNext()) { iterDynamic.next(); byte ks[256]; char cbuf[2] = {'\0', '\0'}; GetKeyboardState(ks); unsigned int oemkey = iterDynamic.key(); unsigned int scancode = MapVirtualKey(oemkey, 0); int charlength = ToAscii(oemkey, scancode, ks, (WORD*)cbuf, 0); if (charlength < 0) { charlength = ToAscii(VK_SPACE, scancode, ks, (WORD*)cbuf, 0); QString temp = QString::fromUtf8(cbuf); if (temp.length() > 0) { QHashIterator tempiter(charToQtKeyHash); while (tempiter.hasNext()) { tempiter.next(); QString currentChar = tempiter.key(); if (currentChar == temp) { dynamicOEMToQtKeyHash[oemkey] = tempiter.value(); tempiter.toBack(); } } } } else if (charlength == 1) { QString temp = QString::fromUtf8(cbuf); QHashIterator tempiter(charToQtKeyHash); while (tempiter.hasNext()) { tempiter.next(); QString currentChar = tempiter.key(); if (currentChar == temp) { dynamicOEMToQtKeyHash[oemkey] = tempiter.value(); tempiter.toBack(); } } } } // Populate hash with values found for the VK_OEM_* keys. // Values will likely be different across various keyboard // layouts. iterDynamic = QHashIterator(dynamicOEMToQtKeyHash); while (iterDynamic.hasNext()) { iterDynamic.next(); unsigned int tempvalue = iterDynamic.value(); if (tempvalue != 0 && !qtKeyToVirtualKey.contains(tempvalue)) { qtKeyToVirtualKey.insert(tempvalue, iterDynamic.key()); } } // Populate other hash. Flip key and value so mapping // goes VK -> Qt Key. QHashIterator iter(qtKeyToVirtualKey); while (iter.hasNext()) { iter.next(); virtualKeyToQtKey[iter.value()] = iter.key(); } // Override current item for VK_RETURN virtualKeyToQtKey[VK_RETURN] = Qt::Key_Return; // Insert more aliases that would have resulted in // overwrites in other hash. virtualKeyToQtKey[VK_SHIFT] = Qt::Key_Shift; virtualKeyToQtKey[VK_CONTROL] = Qt::Key_Control; virtualKeyToQtKey[VK_MENU] = Qt::Key_Alt; } } unsigned int QtWinKeyMapper::returnQtKey(unsigned int key, unsigned int scancode) { unsigned int tempkey = virtualKeyToQtKey.value(key); int extended = scancode & WinExtras::EXTENDED_FLAG; if (key == VK_RETURN && extended) { tempkey = Qt::Key_Enter; } return tempkey; } void QtWinKeyMapper::populateCharKeyInformation() { virtualkeyToCharKeyInformation.clear(); unsigned int total = 0; //BYTE ks[256]; //GetKeyboardState(ks); /*for (int x=0; x <= 255; x++) { if (ks[x] != 0) { qDebug() << "TEST: " << QString::number(x) << " | " << QString::number(ks[x]); } } */ for (int i=VK_SPACE; i <= VK_OEM_CLEAR; i++) { unsigned int scancode = MapVirtualKey(i, 0); for (int j=0; j <= 3; j++) { WCHAR cbuf[256]; BYTE tempks[256]; memset(tempks, 0, sizeof(tempks)); Qt::KeyboardModifiers dicis; if (j >= 2) { dicis |= Qt::MetaModifier; tempks[VK_LWIN] = 1 << 7; //tempks[VK_RWIN] = 1 << 7; } if (j == 1 || j == 3) { dicis |= Qt::ShiftModifier; tempks[VK_LSHIFT] = 1 << 7; tempks[VK_SHIFT] = 1 << 7; //qDebug() << "NEVER ME: "; } int charlength = ToUnicode(i, scancode, tempks, cbuf, 255, 0); if (charlength == 1 || charlength < 0) { QString temp = QString::fromWCharArray(cbuf); if (temp.size() > 0) { QChar tempchar(temp.at(0)); charKeyInformation tempinfo; tempinfo.modifiers = dicis; tempinfo.virtualkey = i; if (!virtualkeyToCharKeyInformation.contains(tempchar.unicode())) { virtualkeyToCharKeyInformation.insert(tempchar.unicode(), tempinfo); total++; } } } } } //qDebug() << "TOTAL: " << total; } antimicro-2.23/src/qtwinkeymapper.h000066400000000000000000000023221300750276700174530ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef QTWINKEYMAPPER_H #define QTWINKEYMAPPER_H #include #include #include #include "qtkeymapperbase.h" class QtWinKeyMapper : public QtKeyMapperBase { Q_OBJECT public: explicit QtWinKeyMapper(QObject *parent = 0); virtual unsigned int returnQtKey(unsigned int key, unsigned int scancode=0); protected: void populateMappingHashes(); void populateCharKeyInformation(); signals: public slots: }; #endif // QTWINKEYMAPPER_H antimicro-2.23/src/qtx11keymapper.cpp000066400000000000000000000404771300750276700176370ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #define XK_MISCELLANY #define XK_LATIN1 #define XK_KOREAN #define XK_XKB_KEYS //#include #include #include #include #include #include #include #include "qtx11keymapper.h" #include "x11extras.h" QtX11KeyMapper::QtX11KeyMapper(QObject *parent) : QtKeyMapperBase(parent) { identifier = "xtest"; populateMappingHashes(); populateCharKeyInformation(); } /* * The following mappings are mainly taken from qkeymapper_x11.cpp. * There are portions of the mapping that are customized to work around * some of the ambiguity introduced with some Qt keys * (XK_Alt_L and XK_Alt_R become Qt::Key_Alt in Qt). */ void QtX11KeyMapper::populateMappingHashes() { if (qtKeyToVirtualKey.isEmpty()) { // misc keys qtKeyToVirtualKey[Qt::Key_Escape] = XK_Escape; qtKeyToVirtualKey[Qt::Key_Tab] = XK_Tab; qtKeyToVirtualKey[Qt::Key_Backtab] = XK_ISO_Left_Tab; qtKeyToVirtualKey[Qt::Key_Backspace] = XK_BackSpace; qtKeyToVirtualKey[Qt::Key_Return] = XK_Return; qtKeyToVirtualKey[Qt::Key_Insert] = XK_Insert; qtKeyToVirtualKey[Qt::Key_Delete] = XK_Delete; qtKeyToVirtualKey[Qt::Key_Delete] = XK_Delete; //qtKeyToX11KeySym[Qt::Key_Delete] = XK_Clear; qtKeyToVirtualKey[Qt::Key_Pause] = XK_Pause; qtKeyToVirtualKey[Qt::Key_Print] = XK_Print; // cursor movement qtKeyToVirtualKey[Qt::Key_Home] = XK_Home; qtKeyToVirtualKey[Qt::Key_End] = XK_End; qtKeyToVirtualKey[Qt::Key_Left] = XK_Left; qtKeyToVirtualKey[Qt::Key_Up] = XK_Up; qtKeyToVirtualKey[Qt::Key_Right] = XK_Right; qtKeyToVirtualKey[Qt::Key_Down] = XK_Down; qtKeyToVirtualKey[Qt::Key_PageUp] = XK_Prior; qtKeyToVirtualKey[Qt::Key_PageDown] = XK_Next; // modifiers qtKeyToVirtualKey[Qt::Key_Shift] = XK_Shift_L; //qtKeyToX11KeySym[Qt::Key_Shift] = XK_Shift_R; //qtKeyToX11KeySym[Qt::Key_Shift] = XK_Shift_Lock; qtKeyToVirtualKey[Qt::Key_Control] = XK_Control_L; //qtKeyToX11KeySym[Qt::Key_Control] = XK_Control_R; //qtKeyToVirtualKey[Qt::Key_Meta] = XK_Meta_L; //qtKeyToX11KeySym[Qt::Key_Meta] = XK_Meta_R; qtKeyToVirtualKey[Qt::Key_Alt] = XK_Alt_L; //qtKeyToX11KeySym[Qt::Key_Alt] = XK_Alt_R; qtKeyToVirtualKey[Qt::Key_CapsLock] = XK_Caps_Lock; qtKeyToVirtualKey[Qt::Key_NumLock] = XK_Num_Lock; qtKeyToVirtualKey[Qt::Key_ScrollLock] = XK_Scroll_Lock; qtKeyToVirtualKey[Qt::Key_Meta] = XK_Super_L; qtKeyToVirtualKey[AntKey_Meta_R] = XK_Super_R; //qtKeyToVirtualKey[Qt::Key_Super_L] = XK_Super_L; //qtKeyToVirtualKey[Qt::Key_Super_R] = XK_Super_R; qtKeyToVirtualKey[Qt::Key_Menu] = XK_Menu; qtKeyToVirtualKey[Qt::Key_Hyper_L] = XK_Hyper_L; qtKeyToVirtualKey[Qt::Key_Hyper_R] = XK_Hyper_R; qtKeyToVirtualKey[Qt::Key_Help] = XK_Help; // numeric and function keypad keys //qtKeyToVirtualKey[Qt::Key_Space] = XK_KP_Space; //qtKeyToX11KeySym[Qt::Key_Tab] = XK_KP_Tab; qtKeyToVirtualKey[Qt::Key_Enter] = XK_KP_Enter; qtKeyToVirtualKey[AntKey_KP_Home] = XK_KP_Home; //qtKeyToX11KeySym[Qt::Key_Home] = XK_KP_Home; qtKeyToVirtualKey[AntKey_KP_Left] = XK_KP_Left; qtKeyToVirtualKey[AntKey_KP_Up] = XK_KP_Up; qtKeyToVirtualKey[AntKey_KP_Right] = XK_KP_Right; qtKeyToVirtualKey[AntKey_KP_Down] = XK_KP_Down; qtKeyToVirtualKey[AntKey_KP_Prior] = XK_KP_Prior; qtKeyToVirtualKey[AntKey_KP_Next] = XK_KP_Next; qtKeyToVirtualKey[AntKey_KP_End] = XK_KP_End; qtKeyToVirtualKey[AntKey_KP_Begin] = XK_KP_Begin; qtKeyToVirtualKey[AntKey_KP_Insert] = XK_KP_Insert; qtKeyToVirtualKey[AntKey_KP_Delete] = XK_KP_Delete; //qtKeyToX11KeySym[AntKey_KP_Equal] = XK_KP_Equal; qtKeyToVirtualKey[AntKey_KP_Add] = XK_KP_Add; //qtKeyToX11KeySym[AntKey_KP_Separator] = XK_KP_Separator; qtKeyToVirtualKey[AntKey_KP_Subtract] = XK_KP_Subtract; qtKeyToVirtualKey[AntKey_KP_Decimal] = XK_KP_Decimal; qtKeyToVirtualKey[AntKey_KP_Divide] = XK_KP_Divide; // International input method support keys // International & multi-key character composition qtKeyToVirtualKey[Qt::Key_AltGr] = XK_ISO_Level3_Shift; qtKeyToVirtualKey[Qt::Key_Multi_key] = XK_Multi_key; qtKeyToVirtualKey[Qt::Key_Codeinput] = XK_Codeinput; qtKeyToVirtualKey[Qt::Key_SingleCandidate] = XK_SingleCandidate; qtKeyToVirtualKey[Qt::Key_MultipleCandidate] = XK_MultipleCandidate; qtKeyToVirtualKey[Qt::Key_PreviousCandidate] = XK_PreviousCandidate; // Misc Functions qtKeyToVirtualKey[Qt::Key_Mode_switch] = XK_Mode_switch; //qtKeyToX11KeySym[Qt::Key_Mode_switch] = XK_script_switch; // Japanese keyboard support qtKeyToVirtualKey[Qt::Key_Kanji] = XK_Kanji; qtKeyToVirtualKey[Qt::Key_Muhenkan] = XK_Muhenkan; qtKeyToVirtualKey[Qt::Key_Henkan] = XK_Henkan_Mode; //qtKeyToX11KeySym[Qt::Key_Henkan] = XK_Henkan; qtKeyToVirtualKey[Qt::Key_Romaji] = XK_Romaji; qtKeyToVirtualKey[Qt::Key_Hiragana] = XK_Hiragana; qtKeyToVirtualKey[Qt::Key_Katakana] = XK_Katakana; qtKeyToVirtualKey[Qt::Key_Hiragana_Katakana] = XK_Hiragana_Katakana; qtKeyToVirtualKey[Qt::Key_Zenkaku] = XK_Zenkaku; qtKeyToVirtualKey[Qt::Key_Hankaku] = XK_Hankaku; qtKeyToVirtualKey[Qt::Key_Zenkaku_Hankaku] = XK_Zenkaku_Hankaku; qtKeyToVirtualKey[Qt::Key_Touroku] = XK_Touroku; qtKeyToVirtualKey[Qt::Key_Massyo] = XK_Massyo; qtKeyToVirtualKey[Qt::Key_Kana_Lock] = XK_Kana_Lock; qtKeyToVirtualKey[Qt::Key_Kana_Shift] = XK_Kana_Shift; qtKeyToVirtualKey[Qt::Key_Eisu_Shift] = XK_Eisu_Shift; qtKeyToVirtualKey[Qt::Key_Eisu_toggle] = XK_Eisu_toggle; qtKeyToVirtualKey[Qt::Key_Codeinput] = XK_Kanji_Bangou; //qtKeyToX11KeySym[Qt::Key_MultipleCandidate] = XK_Zen_Koho; //qtKeyToX11KeySym[Qt::Key_PreviousCandidate] = XK_Mae_Koho; #ifdef XK_KOREAN qtKeyToVirtualKey[Qt::Key_Hangul] = XK_Hangul; qtKeyToVirtualKey[Qt::Key_Hangul_Start] = XK_Hangul_Start; qtKeyToVirtualKey[Qt::Key_Hangul_End] = XK_Hangul_End; qtKeyToVirtualKey[Qt::Key_Hangul_Hanja] = XK_Hangul_Hanja; qtKeyToVirtualKey[Qt::Key_Hangul_Jamo] = XK_Hangul_Jamo; qtKeyToVirtualKey[Qt::Key_Hangul_Romaja] = XK_Hangul_Romaja; //qtKeyToX11KeySym[Qt::Key_Codeinput] = XK_Hangul_Codeinput; qtKeyToVirtualKey[Qt::Key_Hangul_Jeonja] = XK_Hangul_Jeonja; qtKeyToVirtualKey[Qt::Key_Hangul_Banja] = XK_Hangul_Banja; qtKeyToVirtualKey[Qt::Key_Hangul_PreHanja] = XK_Hangul_PreHanja; qtKeyToVirtualKey[Qt::Key_Hangul_PostHanja] = XK_Hangul_PostHanja; //qtKeyToX11KeySym[Qt::Key_SingleCandidate] = XK_Hangul_SingleCandidate; //qtKeyToX11KeySym[Qt::Key_MultipleCandidate] = XK_Hangul_MultipleCandidate; //qtKeyToX11KeySym[Qt::Key_PreviousCandidate] = XK_Hangul_PreviousCandidate; qtKeyToVirtualKey[Qt::Key_Hangul_Special] = XK_Hangul_Special; //qtKeyToX11KeySym[Qt::Key_Mode_switch] = XK_Hangul_switch; #endif // XK_KOREAN // dead keys qtKeyToVirtualKey[Qt::Key_Dead_Grave] = XK_dead_grave; qtKeyToVirtualKey[Qt::Key_Dead_Acute] = XK_dead_acute; qtKeyToVirtualKey[Qt::Key_Dead_Circumflex] = XK_dead_circumflex; qtKeyToVirtualKey[Qt::Key_Dead_Tilde] = XK_dead_tilde; qtKeyToVirtualKey[Qt::Key_Dead_Macron] = XK_dead_macron; qtKeyToVirtualKey[Qt::Key_Dead_Breve] = XK_dead_breve; qtKeyToVirtualKey[Qt::Key_Dead_Abovedot] = XK_dead_abovedot; qtKeyToVirtualKey[Qt::Key_Dead_Diaeresis] = XK_dead_diaeresis; qtKeyToVirtualKey[Qt::Key_Dead_Abovering] = XK_dead_abovering; qtKeyToVirtualKey[Qt::Key_Dead_Doubleacute] = XK_dead_doubleacute; qtKeyToVirtualKey[Qt::Key_Dead_Caron] = XK_dead_caron; qtKeyToVirtualKey[Qt::Key_Dead_Cedilla] = XK_dead_cedilla; qtKeyToVirtualKey[Qt::Key_Dead_Ogonek] = XK_dead_ogonek; qtKeyToVirtualKey[Qt::Key_Dead_Iota] = XK_dead_iota; qtKeyToVirtualKey[Qt::Key_Dead_Voiced_Sound] = XK_dead_voiced_sound; qtKeyToVirtualKey[Qt::Key_Dead_Semivoiced_Sound] = XK_dead_semivoiced_sound; qtKeyToVirtualKey[Qt::Key_Dead_Belowdot] = XK_dead_belowdot; qtKeyToVirtualKey[Qt::Key_Dead_Hook] = XK_dead_hook; qtKeyToVirtualKey[Qt::Key_Dead_Horn] = XK_dead_horn; // Special multimedia keys // currently only tested with MS internet keyboard // browsing keys qtKeyToVirtualKey[Qt::Key_Back] = XF86XK_Back; qtKeyToVirtualKey[Qt::Key_Forward] = XF86XK_Forward; qtKeyToVirtualKey[Qt::Key_Stop] = XF86XK_Stop; qtKeyToVirtualKey[Qt::Key_Refresh] = XF86XK_Refresh; qtKeyToVirtualKey[Qt::Key_Favorites] = XF86XK_Favorites; qtKeyToVirtualKey[Qt::Key_LaunchMedia] = XF86XK_AudioMedia; qtKeyToVirtualKey[Qt::Key_OpenUrl] = XF86XK_OpenURL; qtKeyToVirtualKey[Qt::Key_HomePage] = XF86XK_HomePage; qtKeyToVirtualKey[Qt::Key_Search] = XF86XK_Search; // media keys qtKeyToVirtualKey[Qt::Key_VolumeDown] = XF86XK_AudioLowerVolume; qtKeyToVirtualKey[Qt::Key_VolumeMute] = XF86XK_AudioMute; qtKeyToVirtualKey[Qt::Key_VolumeUp] = XF86XK_AudioRaiseVolume; qtKeyToVirtualKey[Qt::Key_MediaPlay] = XF86XK_AudioPlay; qtKeyToVirtualKey[Qt::Key_MediaStop] = XF86XK_AudioStop; qtKeyToVirtualKey[Qt::Key_MediaPrevious] = XF86XK_AudioPrev; qtKeyToVirtualKey[Qt::Key_MediaNext] = XF86XK_AudioNext; qtKeyToVirtualKey[Qt::Key_MediaRecord] = XF86XK_AudioRecord; // launch keys qtKeyToVirtualKey[Qt::Key_LaunchMail] = XF86XK_Mail; qtKeyToVirtualKey[Qt::Key_Launch0] = XF86XK_MyComputer; qtKeyToVirtualKey[Qt::Key_Launch1] = XF86XK_Calculator; qtKeyToVirtualKey[Qt::Key_Standby] = XF86XK_Standby; qtKeyToVirtualKey[Qt::Key_Launch2] = XF86XK_Launch0; qtKeyToVirtualKey[Qt::Key_Launch3] = XF86XK_Launch1; qtKeyToVirtualKey[Qt::Key_Launch4] = XF86XK_Launch2; qtKeyToVirtualKey[Qt::Key_Launch5] = XF86XK_Launch3; qtKeyToVirtualKey[Qt::Key_Launch6] = XF86XK_Launch4; qtKeyToVirtualKey[Qt::Key_Launch7] = XF86XK_Launch5; qtKeyToVirtualKey[Qt::Key_Launch8] = XF86XK_Launch6; qtKeyToVirtualKey[Qt::Key_Launch9] = XF86XK_Launch7; qtKeyToVirtualKey[Qt::Key_LaunchA] = XF86XK_Launch8; qtKeyToVirtualKey[Qt::Key_LaunchB] = XF86XK_Launch9; qtKeyToVirtualKey[Qt::Key_LaunchC] = XF86XK_LaunchA; qtKeyToVirtualKey[Qt::Key_LaunchD] = XF86XK_LaunchB; qtKeyToVirtualKey[Qt::Key_LaunchE] = XF86XK_LaunchC; qtKeyToVirtualKey[Qt::Key_LaunchF] = XF86XK_LaunchD; // Map initial ASCII keys for (int i=0; i <= (XK_at - XK_space); i++) { qtKeyToVirtualKey[Qt::Key_Space + i] = XK_space + i; } // Map lowercase alpha keys for (int i=0; i <= (XK_z - XK_a); i++) { qtKeyToVirtualKey[Qt::Key_A + i] = XK_a + i; } // Map [ to ` ASCII keys for (int i=0; i <= (XK_grave - XK_bracketleft); i++) { qtKeyToVirtualKey[Qt::Key_BracketLeft + i] = XK_bracketleft + i; } // Map { to ~ ASCII keys for (int i=0; i <= (XK_asciitilde - XK_braceleft); i++) { qtKeyToVirtualKey[Qt::Key_BraceLeft + i] = XK_braceleft + i; } // Map function keys for (int i=0; i <= (XK_F35 - XK_F1); i++) { qtKeyToVirtualKey[Qt::Key_F1 + i] = XK_F1 + i; } // Misc //qtKeyToVirtualKey[Qt::KeyBri] // Map custom defined keys qtKeyToVirtualKey[AntKey_Shift_R] = XK_Shift_R; qtKeyToVirtualKey[AntKey_Control_R] = XK_Control_R; //qtKeyToX11KeySym[AntKey_Shift_Lock] = XK_Shift_Lock; //qtKeyToVirtualKey[AntKey_Meta_R] = XK_Meta_R; qtKeyToVirtualKey[AntKey_Alt_R] = XK_Alt_R; qtKeyToVirtualKey[AntKey_KP_Multiply] = XK_KP_Multiply; // Map 0 to 9 for (int i=0; i <= (XK_KP_9 - XK_KP_0); i++) { qtKeyToVirtualKey[AntKey_KP_0 + i] = XK_KP_0 + i; } // Map lower-case latin characters to their capital equivalents for( int i=0; i <= (XK_odiaeresis - XK_agrave); i++) { qtKeyToVirtualKey[ Qt::Key_Agrave + i ] = XK_agrave + i; } for( int i=0; i <= (XK_thorn - XK_oslash); i++) { qtKeyToVirtualKey[ Qt::Key_Ooblique + i ] = XK_oslash + i; } QHashIterator iter(qtKeyToVirtualKey); while (iter.hasNext()) { iter.next(); virtualKeyToQtKey[iter.value()] = iter.key(); } } } void QtX11KeyMapper::populateCharKeyInformation() { virtualkeyToCharKeyInformation.clear(); Display* display = X11Extras::getInstance()->display(); unsigned int total = 0; for (int i=8; i <= 255; i++) { for (int j=0; j <= 3; j++) { Qt::KeyboardModifiers dicis; if (j >= 2) { dicis |= Qt::MetaModifier; } if (j == 1 || j == 3) { dicis |= Qt::ShiftModifier; } unsigned int testsym = XkbKeycodeToKeysym(display, i, dicis & Qt::MetaModifier ? 1 : 0, dicis & Qt::ShiftModifier ? 1 : 0); if (testsym != NoSymbol) { XKeyPressedEvent tempevent; tempevent.keycode = i; tempevent.type = KeyPress; tempevent.display = display; tempevent.state = 0; if (dicis & Qt::ShiftModifier) { tempevent.state |= ShiftMask; } if (dicis & Qt::MetaModifier) { tempevent.state |= Mod1Mask; } char returnstring[256]; memset(returnstring, 0, sizeof(returnstring)); int bitestoreturn = sizeof(returnstring) - 1; int numchars = XLookupString(&tempevent, returnstring, bitestoreturn, NULL, NULL); if (numchars > 0) { returnstring[numchars] = '\0'; QString tempstring = QString::fromUtf8(returnstring); if (tempstring.length() == 1) { QChar tempchar(tempstring.at(0)); charKeyInformation testKeyInformation; testKeyInformation.modifiers = dicis; testKeyInformation.virtualkey = testsym; if (!virtualkeyToCharKeyInformation.contains(tempchar.unicode())) { virtualkeyToCharKeyInformation.insert(tempchar.unicode(), testKeyInformation); //qDebug() << "I FOUND SOMETHING: " << tempchar; total++; } } else { //qDebug() << "YOU FAIL: " << tempchar; } } } } } //qDebug() << "TOTAL: " << total; //qDebug() << ""; QChar tempa('*'); if (virtualkeyToCharKeyInformation.contains(tempa.unicode())) { charKeyInformation projects = virtualkeyToCharKeyInformation.value(tempa.unicode()); } } antimicro-2.23/src/qtx11keymapper.h000066400000000000000000000022001300750276700172620ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef QTX11KEYMAPPER_H #define QTX11KEYMAPPER_H #include #include #include #include "qtkeymapperbase.h" class QtX11KeyMapper : public QtKeyMapperBase { Q_OBJECT public: explicit QtX11KeyMapper(QObject *parent = 0); protected: void populateMappingHashes(); void populateCharKeyInformation(); signals: public slots: }; #endif // QTX11KEYMAPPER_H antimicro-2.23/src/quicksetdialog.cpp000066400000000000000000000263641300750276700177520ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "quicksetdialog.h" #include "ui_quicksetdialog.h" #include "setjoystick.h" #include "buttoneditdialog.h" QuickSetDialog::QuickSetDialog(InputDevice *joystick, QWidget *parent) : QDialog(parent), ui(new Ui::QuickSetDialog) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); this->joystick = joystick; this->currentButtonDialog = 0; setWindowTitle(tr("Quick Set %1").arg(joystick->getName())); SetJoystick *currentset = joystick->getActiveSetJoystick(); currentset->release(); joystick->resetButtonDownCount(); QString temp = ui->joystickDialogLabel->text(); temp = temp.arg(joystick->getSDLName()).arg(joystick->getName()); ui->joystickDialogLabel->setText(temp); for (int i=0; i < currentset->getNumberSticks(); i++) { JoyControlStick *stick = currentset->getJoyStick(i); QHash *stickButtons = stick->getButtons(); QHashIterator iter(*stickButtons); while (iter.hasNext()) { JoyControlStickButton *stickbutton = iter.next().value(); if (stick->getJoyMode() != JoyControlStick::EightWayMode) { if (stickbutton->getJoyNumber() != JoyControlStick::StickLeftUp && stickbutton->getJoyNumber() != JoyControlStick::StickRightUp && stickbutton->getJoyNumber() != JoyControlStick::StickLeftDown && stickbutton->getJoyNumber() != JoyControlStick::StickRightDown) { connect(stickbutton, SIGNAL(clicked(int)), this, SLOT(showStickButtonDialog())); } } else { connect(stickbutton, SIGNAL(clicked(int)), this, SLOT(showStickButtonDialog())); } if (!stickbutton->getIgnoreEventState()) { stickbutton->setIgnoreEventState(true); } } } for (int i=0; i < currentset->getNumberAxes(); i++) { JoyAxis *axis = currentset->getJoyAxis(i); if (!axis->isPartControlStick() && axis->hasControlOfButtons()) { JoyAxisButton *naxisbutton = axis->getNAxisButton(); JoyAxisButton *paxisbutton = axis->getPAxisButton(); connect(naxisbutton, SIGNAL(clicked(int)), this, SLOT(showAxisButtonDialog())); connect(paxisbutton, SIGNAL(clicked(int)), this, SLOT(showAxisButtonDialog())); if (!naxisbutton->getIgnoreEventState()) { naxisbutton->setIgnoreEventState(true); } if (!paxisbutton->getIgnoreEventState()) { paxisbutton->setIgnoreEventState(true); } } } for (int i=0; i < currentset->getNumberHats(); i++) { JoyDPad *dpad = currentset->getJoyDPad(i); QHash* dpadbuttons = dpad->getButtons(); QHashIterator iter(*dpadbuttons); while (iter.hasNext()) { JoyDPadButton *dpadbutton = iter.next().value(); if (dpad->getJoyMode() != JoyDPad::EightWayMode) { if (dpadbutton->getJoyNumber() != JoyDPadButton::DpadLeftUp && dpadbutton->getJoyNumber() != JoyDPadButton::DpadRightUp && dpadbutton->getJoyNumber() != JoyDPadButton::DpadLeftDown && dpadbutton->getJoyNumber() != JoyDPadButton::DpadRightDown) { connect(dpadbutton, SIGNAL(clicked(int)), this, SLOT(showDPadButtonDialog())); } } else { connect(dpadbutton, SIGNAL(clicked(int)), this, SLOT(showDPadButtonDialog())); } if (!dpadbutton->getIgnoreEventState()) { dpadbutton->setIgnoreEventState(true); } } } for (int i=0; i < currentset->getNumberVDPads(); i++) { VDPad *dpad = currentset->getVDPad(i); if (dpad) { QHash* dpadbuttons = dpad->getButtons(); QHashIterator iter(*dpadbuttons); while (iter.hasNext()) { JoyDPadButton *dpadbutton = iter.next().value(); if (dpad->getJoyMode() != JoyDPad::EightWayMode) { if (dpadbutton->getJoyNumber() != JoyDPadButton::DpadLeftUp && dpadbutton->getJoyNumber() != JoyDPadButton::DpadRightUp && dpadbutton->getJoyNumber() != JoyDPadButton::DpadLeftDown && dpadbutton->getJoyNumber() != JoyDPadButton::DpadRightDown) { connect(dpadbutton, SIGNAL(clicked(int)), this, SLOT(showDPadButtonDialog())); } } else { connect(dpadbutton, SIGNAL(clicked(int)), this, SLOT(showDPadButtonDialog())); } if (!dpadbutton->getIgnoreEventState()) { dpadbutton->setIgnoreEventState(true); } } } } for (int i=0; i < currentset->getNumberButtons(); i++) { JoyButton *button = currentset->getJoyButton(i); if (button && !button->isPartVDPad()) { connect(button, SIGNAL(clicked(int)), this, SLOT(showButtonDialog())); if (!button->getIgnoreEventState()) { button->setIgnoreEventState(true); } } } connect(this, SIGNAL(finished(int)), this, SLOT(restoreButtonStates())); } QuickSetDialog::~QuickSetDialog() { delete ui; } void QuickSetDialog::showAxisButtonDialog() { if (!currentButtonDialog) { JoyAxisButton *axisbutton = static_cast(sender()); currentButtonDialog = new ButtonEditDialog(axisbutton, this); currentButtonDialog->show(); connect(currentButtonDialog, SIGNAL(finished(int)), this, SLOT(nullifyDialogPointer())); } } void QuickSetDialog::showButtonDialog() { if (!currentButtonDialog) { JoyButton *button = static_cast(sender()); currentButtonDialog = new ButtonEditDialog(button, this); currentButtonDialog->show(); connect(currentButtonDialog, SIGNAL(finished(int)), this, SLOT(nullifyDialogPointer())); } } void QuickSetDialog::showStickButtonDialog() { if (!currentButtonDialog) { JoyControlStickButton *stickbutton = static_cast(sender()); currentButtonDialog = new ButtonEditDialog(stickbutton, this); currentButtonDialog->show(); connect(currentButtonDialog, SIGNAL(finished(int)), this, SLOT(nullifyDialogPointer())); } } void QuickSetDialog::showDPadButtonDialog() { if (!currentButtonDialog) { JoyDPadButton *dpadbutton = static_cast(sender()); currentButtonDialog = new ButtonEditDialog(dpadbutton, this); currentButtonDialog->show(); connect(currentButtonDialog, SIGNAL(finished(int)), this, SLOT(nullifyDialogPointer())); } } void QuickSetDialog::nullifyDialogPointer() { if (currentButtonDialog) { currentButtonDialog = 0; emit buttonDialogClosed(); } } void QuickSetDialog::restoreButtonStates() { SetJoystick *currentset = joystick->getActiveSetJoystick(); for (int i=0; i < currentset->getNumberSticks(); i++) { JoyControlStick *stick = currentset->getJoyStick(i); QHash *stickButtons = stick->getButtons(); QHashIterator iter(*stickButtons); while (iter.hasNext()) { JoyControlStickButton *stickbutton = iter.next().value(); if (stickbutton->getIgnoreEventState()) { stickbutton->setIgnoreEventState(false); } disconnect(stickbutton, SIGNAL(clicked(int)), this, 0); } } for (int i=0; i < currentset->getNumberAxes(); i++) { JoyAxis *axis = currentset->getJoyAxis(i); if (!axis->isPartControlStick() && axis->hasControlOfButtons()) { JoyAxisButton *naxisbutton = axis->getNAxisButton(); if (naxisbutton->getIgnoreEventState()) { naxisbutton->setIgnoreEventState(false); } JoyAxisButton *paxisbutton = axis->getPAxisButton(); if (paxisbutton->getIgnoreEventState()) { paxisbutton->setIgnoreEventState(false); } disconnect(naxisbutton, SIGNAL(clicked(int)), this, 0); disconnect(paxisbutton, SIGNAL(clicked(int)), this, 0); } } for (int i=0; i < currentset->getNumberHats(); i++) { JoyDPad *dpad = currentset->getJoyDPad(i); QHash* dpadbuttons = dpad->getButtons(); QHashIterator iter(*dpadbuttons); while (iter.hasNext()) { JoyDPadButton *dpadbutton = iter.next().value(); if (dpadbutton->getIgnoreEventState()) { dpadbutton->setIgnoreEventState(false); } disconnect(dpadbutton, SIGNAL(clicked(int)), this, 0); } } for (int i=0; i < currentset->getNumberVDPads(); i++) { VDPad *dpad = currentset->getVDPad(i); if (dpad) { QHash* dpadbuttons = dpad->getButtons(); QHashIterator iter(*dpadbuttons); while (iter.hasNext()) { JoyDPadButton *dpadbutton = iter.next().value(); if (dpadbutton->getIgnoreEventState()) { dpadbutton->setIgnoreEventState(false); } disconnect(dpadbutton, SIGNAL(clicked(int)), this, 0); } } } for (int i=0; i < currentset->getNumberButtons(); i++) { JoyButton *button = currentset->getJoyButton(i); if (button && !button->isPartVDPad()) { if (button->getIgnoreEventState()) { button->setIgnoreEventState(false); } disconnect(button, SIGNAL(clicked(int)), this, 0); } } currentset->release(); } antimicro-2.23/src/quicksetdialog.h000066400000000000000000000026451300750276700174130ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef QUICKSETDIALOG_H #define QUICKSETDIALOG_H #include #include "inputdevice.h" namespace Ui { class QuickSetDialog; } class QuickSetDialog : public QDialog { Q_OBJECT public: explicit QuickSetDialog(InputDevice *joystick, QWidget *parent = 0); ~QuickSetDialog(); protected: InputDevice *joystick; QDialog *currentButtonDialog; private: Ui::QuickSetDialog *ui; signals: void buttonDialogClosed(); private slots: void showAxisButtonDialog(); void showButtonDialog(); void showStickButtonDialog(); void showDPadButtonDialog(); void nullifyDialogPointer(); void restoreButtonStates(); }; #endif // QUICKSETDIALOG_H antimicro-2.23/src/quicksetdialog.ui000066400000000000000000000040761300750276700176010ustar00rootroot00000000000000 QuickSetDialog 0 0 400 300 Quick Set true <html><head/><body><p>Please press a button or move an axis on %1 (<span style=" font-weight:600;">%2</span>).<br/>A dialog window will then appear which will<br/>allow you to make an assignment.</p></body></html> Qt::AlignCenter false Qt::Horizontal QDialogButtonBox::Close buttonBox accepted() QuickSetDialog accept() 248 254 157 274 buttonBox rejected() QuickSetDialog reject() 316 260 286 274 antimicro-2.23/src/resources.qrc000066400000000000000000000006541300750276700167510ustar00rootroot00000000000000 images/antimicro.png images/antimicro_trayicon.png images/controllermap.png images/axis.png images/button.png Changelog icons/16x16/actions/document-save.png icons/16x16/actions/document-open-folder.png antimicro-2.23/src/resources_windows.qrc000066400000000000000000000031171300750276700205200ustar00rootroot00000000000000 icons/16x16/actions/application-exit.png icons/16x16/actions/archive-insert.png icons/16x16/actions/dialog-cancel.png icons/16x16/actions/dialog-close.png icons/16x16/actions/dialog-ok.png icons/16x16/actions/document-close.png icons/16x16/actions/document-open-folder.png icons/16x16/actions/document-open.png icons/16x16/actions/document-revert-small.png icons/16x16/actions/document-revert.png icons/16x16/actions/document-save-as.png icons/16x16/actions/document-save.png icons/16x16/actions/edit-clear-list.png icons/16x16/actions/edit-clear.png icons/16x16/actions/edit-delete.png icons/16x16/actions/edit-select.png icons/16x16/actions/games-config-custom.png icons/16x16/actions/games-config-options.png icons/16x16/actions/text-field.png icons/16x16/actions/view-refresh.png icons/16x16/actions/view-restore.png icons/index.theme icons/16x16/actions/edit-table-delete-row.png icons/16x16/actions/edit-table-insert-row-below.png icons/16x16/actions/help-about.png icons/16x16/actions/view-fullscreen.png antimicro-2.23/src/sdleventreader.cpp000066400000000000000000000154611300750276700177450ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include #include //#include "logger.h" #include "sdleventreader.h" SDLEventReader::SDLEventReader(QMap *joysticks, AntiMicroSettings *settings, QObject *parent) : QObject(parent) { this->joysticks = joysticks; this->settings = settings; settings->getLock()->lock(); this->pollRate = settings->value("GamepadPollRate", AntiMicroSettings::defaultSDLGamepadPollRate).toUInt(); settings->getLock()->unlock(); pollRateTimer.setParent(this); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) pollRateTimer.setTimerType(Qt::PreciseTimer); #endif initSDL(); connect(&pollRateTimer, SIGNAL(timeout()), this, SLOT(performWork())); } SDLEventReader::~SDLEventReader() { if (sdlIsOpen) { closeSDL(); } } void SDLEventReader::initSDL() { #ifdef USE_SDL_2 // SDL_INIT_GAMECONTROLLER should automatically initialize SDL_INIT_JOYSTICK // but it doesn't seem to be the case with v2.0.4 SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK); #else // Video support is required to use event system in SDL 1.2. SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK); #endif SDL_JoystickEventState(SDL_ENABLE); sdlIsOpen = true; #ifdef USE_SDL_2 //QSettings settings(PadderCommon::configFilePath, QSettings::IniFormat); settings->getLock()->lock(); settings->beginGroup("Mappings"); QStringList mappings = settings->allKeys(); QStringListIterator iter(mappings); while (iter.hasNext()) { QString tempstring = iter.next(); QString mappingSetting = settings->value(tempstring, QString()).toString(); if (!mappingSetting.isEmpty()) { QByteArray temparray = mappingSetting.toUtf8(); char *mapping = temparray.data(); SDL_GameControllerAddMapping(mapping); // Let SDL take care of validation } } settings->endGroup(); settings->getLock()->unlock(); //SDL_GameControllerAddMapping("03000000100800000100000010010000,Twin USB Joystick,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2"); #endif pollRateTimer.stop(); pollRateTimer.setInterval(pollRate); //pollRateTimer.start(); //pollRateTimer.setSingleShot(true); emit sdlStarted(); } void SDLEventReader::closeSDL() { pollRateTimer.stop(); SDL_Event event; closeDevices(); // Clear any pending events while (SDL_PollEvent(&event) > 0) { } SDL_Quit(); sdlIsOpen = false; emit sdlClosed(); } void SDLEventReader::performWork() { if (sdlIsOpen) { //int status = SDL_WaitEvent(NULL); int status = CheckForEvents(); if (status) { pollRateTimer.stop(); emit eventRaised(); } } } void SDLEventReader::stop() { if (sdlIsOpen) { SDL_Event event; event.type = SDL_QUIT; SDL_PushEvent(&event); } pollRateTimer.stop(); } void SDLEventReader::refresh() { if (sdlIsOpen) { stop(); QTimer::singleShot(0, this, SLOT(secondaryRefresh())); } } void SDLEventReader::secondaryRefresh() { if (sdlIsOpen) { closeSDL(); } initSDL(); } void SDLEventReader::clearEvents() { if (sdlIsOpen) { SDL_Event event; while (SDL_PollEvent(&event) > 0) { } } } bool SDLEventReader::isSDLOpen() { return sdlIsOpen; } int SDLEventReader::CheckForEvents() { int result = 0; bool exit = false; /*Logger::LogInfo( QString("Gamepad Poll %1").arg( QTime::currentTime().toString("hh:mm:ss.zzz")), true, true); */ SDL_PumpEvents(); #ifdef USE_SDL_2 switch (SDL_PeepEvents(NULL, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT)) #else switch (SDL_PeepEvents(NULL, 1, SDL_GETEVENT, 0xFFFF)) #endif { case -1: { Logger::LogError(QString("SDL Error: %1"). arg(QString(SDL_GetError())), true, true); result = 0; exit = true; break; } case 0: { if (!pollRateTimer.isActive()) { pollRateTimer.start(); } //exit = true; //SDL_Delay(10); break; } default: { /*Logger::LogInfo( QString("Gamepad Poll %1").arg( QTime::currentTime().toString("hh:mm:ss.zzz")), true, true); */ result = 1; exit = true; break; } } return result; } void SDLEventReader::updatePollRate(unsigned int tempPollRate) { if (tempPollRate >= 1 && tempPollRate <= 16) { bool wasActive = pollRateTimer.isActive(); pollRateTimer.stop(); this->pollRate = tempPollRate; pollRateTimer.setInterval(pollRate); if (wasActive) { pollRateTimer.start(); } } } void SDLEventReader::resetJoystickMap() { joysticks = 0; } void SDLEventReader::quit() { if (sdlIsOpen) { closeSDL(); joysticks = 0; } } void SDLEventReader::closeDevices() { if (sdlIsOpen) { if (joysticks) { QMapIterator iter(*joysticks); while (iter.hasNext()) { iter.next(); InputDevice *current = iter.value(); current->closeSDLDevice(); } } } } /** * @brief Method to block activity on the SDLEventReader object and its thread * event loop. */ void SDLEventReader::haltServices() { PadderCommon::lockInputDevices(); PadderCommon::unlockInputDevices(); } antimicro-2.23/src/sdleventreader.h000066400000000000000000000036551300750276700174140ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SDLEVENTREADER_H #define SDLEVENTREADER_H #include #include #include #ifdef USE_SDL_2 #include #else #include #endif #include "joystick.h" #include "inputdevice.h" #include "antimicrosettings.h" class SDLEventReader : public QObject { Q_OBJECT public: explicit SDLEventReader(QMap *joysticks, AntiMicroSettings *settings, QObject *parent = 0); ~SDLEventReader(); bool isSDLOpen(); protected: void initSDL(); void closeSDL(); void clearEvents(); int CheckForEvents(); QMap *joysticks; bool sdlIsOpen; AntiMicroSettings *settings; unsigned int pollRate; QTimer pollRateTimer; signals: void eventRaised(); void finished(); void sdlStarted(); void sdlClosed(); public slots: void performWork(); void stop(); void refresh(); void updatePollRate(unsigned int tempPollRate); void resetJoystickMap(); void quit(); void closeDevices(); void haltServices(); private slots: void secondaryRefresh(); }; #endif // SDLEVENTREADER_H antimicro-2.23/src/setaxisthrottledialog.cpp000066400000000000000000000030241300750276700213540ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include "setaxisthrottledialog.h" #include "ui_setaxisthrottledialog.h" SetAxisThrottleDialog::SetAxisThrottleDialog(JoyAxis *axis, QWidget *parent) : QDialog(parent), ui(new Ui::SetAxisThrottleDialog) { ui->setupUi(this); this->axis = axis; QString currentText = ui->label->text(); currentText = currentText.arg(QString::number(axis->getRealJoyIndex())); ui->label->setText(currentText); connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(propogateThrottleChange())); connect(this, SIGNAL(initiateSetAxisThrottleChange()), axis, SLOT(propogateThrottleChange())); } SetAxisThrottleDialog::~SetAxisThrottleDialog() { delete ui; } void SetAxisThrottleDialog::propogateThrottleChange() { emit initiateSetAxisThrottleChange(); } antimicro-2.23/src/setaxisthrottledialog.h000066400000000000000000000024341300750276700210250ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SETAXISTHROTTLEDIALOG_H #define SETAXISTHROTTLEDIALOG_H #include #include "joyaxis.h" namespace Ui { class SetAxisThrottleDialog; } class SetAxisThrottleDialog : public QDialog { Q_OBJECT public: explicit SetAxisThrottleDialog(JoyAxis *axis, QWidget *parent = 0); ~SetAxisThrottleDialog(); private: Ui::SetAxisThrottleDialog *ui; protected: JoyAxis *axis; signals: void initiateSetAxisThrottleChange(); private slots: void propogateThrottleChange(); }; #endif // SETAXISTHROTTLEDIALOG_H antimicro-2.23/src/setaxisthrottledialog.ui000066400000000000000000000035411300750276700212130ustar00rootroot00000000000000 SetAxisThrottleDialog 0 0 400 207 Throttle Change The throttle setting for Axis %1 has been changed. Would you like to distribute this throttle change to all sets? Qt::AlignCenter Qt::Horizontal QDialogButtonBox::No|QDialogButtonBox::Yes false buttonBox accepted() SetAxisThrottleDialog accept() 248 254 157 274 buttonBox rejected() SetAxisThrottleDialog reject() 316 260 286 274 antimicro-2.23/src/setjoystick.cpp000066400000000000000000000767711300750276700173240ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include "setjoystick.h" #include "inputdevice.h" const int SetJoystick::MAXNAMELENGTH = 30; const int SetJoystick::RAISEDDEADZONE = 20000; SetJoystick::SetJoystick(InputDevice *device, int index, QObject *parent) : QObject(parent) { this->device = device; this->index = index; reset(); } SetJoystick::SetJoystick(InputDevice *device, int index, bool runreset, QObject *parent) : QObject(parent) { this->device = device; this->index = index; if (runreset) { reset(); } } SetJoystick::~SetJoystick() { deleteSticks(); deleteVDpads(); deleteButtons(); deleteAxes(); deleteHats(); } JoyButton* SetJoystick::getJoyButton(int index) { return buttons.value(index); } JoyAxis* SetJoystick::getJoyAxis(int index) { return axes.value(index); } JoyDPad* SetJoystick::getJoyDPad(int index) { return hats.value(index); } VDPad* SetJoystick::getVDPad(int index) { return vdpads.value(index); } JoyControlStick* SetJoystick::getJoyStick(int index) { return sticks.value(index); } void SetJoystick::refreshButtons() { deleteButtons(); for (int i=0; i < device->getNumberRawButtons(); i++) { JoyButton *button = new JoyButton (i, index, this, this); buttons.insert(i, button); enableButtonConnections(button); } } void SetJoystick::refreshAxes() { deleteAxes(); InputDevice *device = getInputDevice(); for (int i=0; i < device->getNumberRawAxes(); i++) { JoyAxis *axis = new JoyAxis(i, index, this, this); axes.insert(i, axis); if (device->hasCalibrationThrottle(i)) { JoyAxis::ThrottleTypes throttle = device->getCalibrationThrottle(i); axis->setInitialThrottle(throttle); } enableAxisConnections(axis); } } void SetJoystick::refreshHats() { deleteHats(); for (int i=0; i < device->getNumberRawHats(); i++) { JoyDPad *dpad = new JoyDPad(i, index, this, this); hats.insert(i, dpad); enableHatConnections(dpad); } } void SetJoystick::deleteButtons() { QHashIterator iter(buttons); while (iter.hasNext()) { JoyButton *button = iter.next().value(); if (button) { delete button; button = 0; } } buttons.clear(); } void SetJoystick::deleteAxes() { QHashIterator iter(axes); while (iter.hasNext()) { JoyAxis *axis = iter.next().value(); if (axis) { delete axis; axis = 0; } } axes.clear(); } void SetJoystick::deleteSticks() { QHashIterator iter(sticks); while (iter.hasNext()) { JoyControlStick *stick = iter.next().value(); if (stick) { delete stick; stick = 0; } } sticks.clear(); } void SetJoystick::deleteVDpads() { QHashIterator iter(vdpads); while (iter.hasNext()) { VDPad *dpad = iter.next().value(); if (dpad) { delete dpad; dpad = 0; } } vdpads.clear(); } void SetJoystick::deleteHats() { QHashIterator iter(hats); while (iter.hasNext()) { JoyDPad *dpad = iter.next().value(); if (dpad) { delete dpad; dpad = 0; } } hats.clear(); } int SetJoystick::getNumberButtons() { return buttons.count(); } int SetJoystick::getNumberAxes() { return axes.count(); } int SetJoystick::getNumberHats() { return hats.count(); } int SetJoystick::getNumberSticks() { return sticks.size(); } int SetJoystick::getNumberVDPads() { return vdpads.size(); } void SetJoystick::reset() { deleteSticks(); deleteVDpads(); refreshAxes(); refreshButtons(); refreshHats(); name = QString(); } void SetJoystick::propogateSetChange(int index) { emit setChangeActivated(index); } void SetJoystick::propogateSetButtonAssociation(int button, int newset, int mode) { if (newset != index) { emit setAssignmentButtonChanged(button, index, newset, mode); } } void SetJoystick::propogateSetAxisButtonAssociation(int button, int axis, int newset, int mode) { if (newset != index) { emit setAssignmentAxisChanged(button, axis, index, newset, mode); } } void SetJoystick::propogateSetStickButtonAssociation(int button, int stick, int newset, int mode) { if (newset != index) { emit setAssignmentStickChanged(button, stick, index, newset, mode); } } void SetJoystick::propogateSetDPadButtonAssociation(int button, int dpad, int newset, int mode) { if (newset != index) { emit setAssignmentDPadChanged(button, dpad, index, newset, mode); } } void SetJoystick::propogateSetVDPadButtonAssociation(int button, int dpad, int newset, int mode) { if (newset != index) { emit setAssignmentVDPadChanged(button, dpad, index, newset, mode); } } /** * @brief Perform a release of all elements of a set. Stick and vdpad * releases will be handled by the associated button or axis. */ void SetJoystick::release() { QHashIterator iterAxes(axes); while (iterAxes.hasNext()) { JoyAxis *axis = iterAxes.next().value(); axis->clearPendingEvent(); axis->joyEvent(axis->getCurrentThrottledDeadValue(), true); axis->eventReset(); } QHashIterator iterDPads(hats); while (iterDPads.hasNext()) { JoyDPad *dpad = iterDPads.next().value(); dpad->clearPendingEvent(); dpad->joyEvent(0, true); dpad->eventReset(); } QHashIterator iterButtons(buttons); while (iterButtons.hasNext()) { JoyButton *button = iterButtons.next().value(); button->clearPendingEvent(); button->joyEvent(false, true); button->eventReset(); } } void SetJoystick::readConfig(QXmlStreamReader *xml) { if (xml->isStartElement() && xml->name() == "set") { //reset(); xml->readNextStartElement(); while (!xml->atEnd() && (!xml->isEndElement() && xml->name() != "set")) { if (xml->name() == "button" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); JoyButton *button = getJoyButton(index-1); if (button) { button->readConfig(xml); } else { xml->skipCurrentElement(); } } else if (xml->name() == "axis" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); JoyAxis *axis = getJoyAxis(index-1); if (axis) { axis->readConfig(xml); } else { xml->skipCurrentElement(); } } else if (xml->name() == "dpad" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); JoyDPad *dpad = getJoyDPad(index-1); if (dpad) { dpad->readConfig(xml); } else { xml->skipCurrentElement(); } } else if (xml->name() == "stick" && xml->isStartElement()) { int stickIndex = xml->attributes().value("index").toString().toInt(); if (stickIndex > 0) { stickIndex -= 1; JoyControlStick *stick = getJoyStick(stickIndex); if (stick) { stick->readConfig(xml); } else { xml->skipCurrentElement(); } } else { xml->skipCurrentElement(); } } else if (xml->name() == "vdpad" && xml->isStartElement()) { int index = xml->attributes().value("index").toString().toInt(); VDPad *vdpad = getVDPad(index-1); if (vdpad) { vdpad->readConfig(xml); } else { xml->skipCurrentElement(); } } else if (xml->name() == "name" && xml->isStartElement()) { QString temptext = xml->readElementText(); if (!temptext.isEmpty()) { setName(temptext); } } else { // If none of the above, skip the element xml->skipCurrentElement(); } xml->readNextStartElement(); } } } void SetJoystick::writeConfig(QXmlStreamWriter *xml) { if (!isSetEmpty()) { xml->writeStartElement("set"); xml->writeAttribute("index", QString::number(index+1)); if (!name.isEmpty()) { xml->writeTextElement("name", name); } for (int i=0; i < getNumberSticks(); i++) { JoyControlStick *stick = getJoyStick(i); stick->writeConfig(xml); } for (int i=0; i < getNumberVDPads(); i++) { VDPad *vdpad = getVDPad(i); if (vdpad) { vdpad->writeConfig(xml); } } for (int i=0; i < getNumberAxes(); i++) { JoyAxis *axis = getJoyAxis(i); if (!axis->isPartControlStick() && axis->hasControlOfButtons()) { axis->writeConfig(xml); } } for (int i=0; i < getNumberHats(); i++) { JoyDPad *dpad = getJoyDPad(i); dpad->writeConfig(xml); } for (int i=0; i < getNumberButtons(); i++) { JoyButton *button = getJoyButton(i); if (button && !button->isPartVDPad()) { button->writeConfig(xml); } } xml->writeEndElement(); } } bool SetJoystick::isSetEmpty() { bool result = true; QHashIterator iter(buttons); while (iter.hasNext() && result) { JoyButton *button = iter.next().value(); if (!button->isDefault()) { result = false; } } QHashIterator iter2(axes); while (iter2.hasNext() && result) { JoyAxis *axis = iter2.next().value(); if (!axis->isDefault()) { result = false; } } QHashIterator iter3(hats); while (iter3.hasNext() && result) { JoyDPad *dpad = iter3.next().value(); if (!dpad->isDefault()) { result = false; } } QHashIterator iter4(sticks); while (iter4.hasNext() && result) { JoyControlStick *stick = iter4.next().value(); if (!stick->isDefault()) { result = false; } } QHashIterator iter5(vdpads); while (iter5.hasNext() && result) { VDPad *vdpad = iter5.next().value(); if (!vdpad->isDefault()) { result = false; } } return result; } void SetJoystick::propogateSetAxisThrottleSetting(int index) { JoyAxis *axis = axes.value(index); if (axis) { emit setAssignmentAxisThrottleChanged(index, axis->getCurrentlyAssignedSet()); } } void SetJoystick::addControlStick(int index, JoyControlStick *stick) { sticks.insert(index, stick); connect(stick, SIGNAL(stickNameChanged()), this, SLOT(propogateSetStickNameChange())); QHashIterator iter(*stick->getButtons()); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); if (button) { connect(button, SIGNAL(setChangeActivated(int)), this, SLOT(propogateSetChange(int))); connect(button, SIGNAL(setAssignmentChanged(int,int,int,int)), this, SLOT(propogateSetStickButtonAssociation(int,int,int,int))); connect(button, SIGNAL(clicked(int)), this, SLOT(propogateSetStickButtonClick(int)), Qt::QueuedConnection); connect(button, SIGNAL(released(int)), this, SLOT(propogateSetStickButtonRelease(int)), Qt::QueuedConnection); connect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetStickButtonNameChange())); } } } void SetJoystick::removeControlStick(int index) { if (sticks.contains(index)) { JoyControlStick *stick = sticks.value(index); sticks.remove(index); delete stick; stick = 0; } } void SetJoystick::addVDPad(int index, VDPad *vdpad) { vdpads.insert(index, vdpad); connect(vdpad, SIGNAL(dpadNameChanged()), this, SLOT(propogateSetVDPadNameChange())); QHashIterator iter(*vdpad->getButtons()); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); if (button) { connect(button, SIGNAL(setChangeActivated(int)), this, SLOT(propogateSetChange(int))); connect(button, SIGNAL(setAssignmentChanged(int,int,int,int)), this, SLOT(propogateSetVDPadButtonAssociation(int,int,int,int))); connect(button, SIGNAL(clicked(int)), this, SLOT(propogateSetDPadButtonClick(int)), Qt::QueuedConnection); connect(button, SIGNAL(released(int)), this, SLOT(propogateSetDPadButtonRelease(int)), Qt::QueuedConnection); connect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetVDPadButtonNameChange())); } } } void SetJoystick::removeVDPad(int index) { if (vdpads.contains(index)) { VDPad *vdpad = vdpads.value(index); vdpads.remove(index); delete vdpad; vdpad = 0; } } int SetJoystick::getIndex() { return index; } unsigned int SetJoystick::getRealIndex() { return index + 1; } void SetJoystick::propogateSetButtonClick(int button) { JoyButton *jButton = static_cast(sender()); if (jButton) { if (!jButton->getIgnoreEventState()) { emit setButtonClick(index, button); } } } void SetJoystick::propogateSetButtonRelease(int button) { JoyButton *jButton = static_cast(sender()); if (jButton) { if (!jButton->getIgnoreEventState()) { emit setButtonRelease(index, button); } } } void SetJoystick::propogateSetAxisButtonClick(int button) { JoyAxisButton *axisButton = static_cast(sender()); if (axisButton) { JoyAxis *axis = axisButton->getAxis(); if (!axisButton->getIgnoreEventState()) { emit setAxisButtonClick(index, axis->getIndex(), button); } } } void SetJoystick::propogateSetAxisButtonRelease(int button) { JoyAxisButton *axisButton = static_cast(sender()); if (axisButton) { JoyAxis *axis = axisButton->getAxis(); if (!axisButton->getIgnoreEventState()) { emit setAxisButtonRelease(index, axis->getIndex(), button); } } } void SetJoystick::propogateSetStickButtonClick(int button) { JoyControlStickButton *stickButton = static_cast(sender()); if (stickButton) { JoyControlStick *stick = stickButton->getStick(); if (stick && !stickButton->getIgnoreEventState()) { emit setStickButtonClick(index, stick->getIndex(), button); } } } void SetJoystick::propogateSetStickButtonRelease(int button) { JoyControlStickButton *stickButton = static_cast(sender()); if (stickButton) { JoyControlStick *stick = stickButton->getStick(); if (!stickButton->getIgnoreEventState()) { emit setStickButtonRelease(index, stick->getIndex(), button); } } } void SetJoystick::propogateSetDPadButtonClick(int button) { JoyDPadButton *dpadButton = static_cast(sender()); if (dpadButton) { JoyDPad *dpad = dpadButton->getDPad(); if (dpad && dpadButton->getButtonState() && !dpadButton->getIgnoreEventState()) { emit setDPadButtonClick(index, dpad->getIndex(), button); } } } void SetJoystick::propogateSetDPadButtonRelease(int button) { JoyDPadButton *dpadButton = static_cast(sender()); if (dpadButton) { JoyDPad *dpad = dpadButton->getDPad(); if (dpad && !dpadButton->getButtonState() && !dpadButton->getIgnoreEventState()) { emit setDPadButtonRelease(index, dpad->getIndex(), button); } } } void SetJoystick::propogateSetButtonNameChange() { JoyButton *button = static_cast(sender()); disconnect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetButtonNameChange())); emit setButtonNameChange(button->getJoyNumber()); connect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetButtonNameChange())); } void SetJoystick::propogateSetAxisButtonNameChange() { JoyAxisButton *button = static_cast(sender()); disconnect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetAxisButtonNameChange())); emit setAxisButtonNameChange(button->getAxis()->getIndex(), button->getJoyNumber()); connect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetAxisButtonNameChange())); } void SetJoystick::propogateSetStickButtonNameChange() { JoyControlStickButton *button = static_cast(sender()); disconnect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetStickButtonNameChange())); emit setStickButtonNameChange(button->getStick()->getIndex(), button->getJoyNumber()); connect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetStickButtonNameChange())); } void SetJoystick::propogateSetDPadButtonNameChange() { JoyDPadButton *button = static_cast(sender()); disconnect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetDPadButtonNameChange())); emit setDPadButtonNameChange(button->getDPad()->getIndex(), button->getJoyNumber()); connect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetDPadButtonNameChange())); } void SetJoystick::propogateSetVDPadButtonNameChange() { JoyDPadButton *button = static_cast(sender()); disconnect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetVDPadButtonNameChange())); emit setVDPadButtonNameChange(button->getDPad()->getIndex(), button->getJoyNumber()); connect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetVDPadButtonNameChange())); } void SetJoystick::propogateSetAxisNameChange() { JoyAxis *axis = static_cast(sender()); disconnect(axis, SIGNAL(axisNameChanged()), this, SLOT(propogateSetAxisNameChange())); emit setAxisNameChange(axis->getIndex()); connect(axis, SIGNAL(axisNameChanged()), this, SLOT(propogateSetAxisNameChange())); } void SetJoystick::propogateSetStickNameChange() { JoyControlStick *stick = static_cast(sender()); disconnect(stick, SIGNAL(stickNameChanged()), this, SLOT(propogateSetStickNameChange())); emit setStickNameChange(stick->getIndex()); connect(stick, SIGNAL(stickNameChanged()), this, SLOT(propogateSetStickNameChange())); } void SetJoystick::propogateSetDPadNameChange() { JoyDPad *dpad = static_cast(sender()); disconnect(dpad, SIGNAL(dpadNameChanged()), this, SLOT(propogateSetDPadButtonNameChange())); emit setDPadNameChange(dpad->getIndex()); connect(dpad, SIGNAL(dpadNameChanged()), this, SLOT(propogateSetDPadButtonNameChange())); } void SetJoystick::propogateSetVDPadNameChange() { VDPad *vdpad = static_cast(sender()); disconnect(vdpad, SIGNAL(dpadNameChanged()), this, SLOT(propogateSetVDPadNameChange())); emit setVDPadNameChange(vdpad->getIndex()); connect(vdpad, SIGNAL(dpadNameChanged()), this, SLOT(propogateSetVDPadNameChange())); } void SetJoystick::setIgnoreEventState(bool ignore) { QHashIterator iter(buttons); while (iter.hasNext()) { JoyButton *button = iter.next().value(); if (button) { button->setIgnoreEventState(ignore); } } QHashIterator iter2(axes); while (iter2.hasNext()) { JoyAxis *axis = iter2.next().value(); if (axis) { JoyAxisButton *naxisbutton = axis->getNAxisButton(); naxisbutton->setIgnoreEventState(ignore); JoyAxisButton *paxisbutton = axis->getPAxisButton(); paxisbutton->setIgnoreEventState(ignore); } } QHashIterator iter3(hats); while (iter3.hasNext()) { JoyDPad *dpad = iter3.next().value(); if (dpad) { QHash* dpadbuttons = dpad->getButtons(); QHashIterator iterdpadbuttons(*dpadbuttons); while (iterdpadbuttons.hasNext()) { JoyDPadButton *dpadbutton = iterdpadbuttons.next().value(); if (dpadbutton) { dpadbutton->setIgnoreEventState(ignore); } } } } QHashIterator iter4(sticks); while (iter4.hasNext()) { JoyControlStick *stick = iter4.next().value(); if (stick) { QHash *stickButtons = stick->getButtons(); QHashIterator iterstickbuttons(*stickButtons); while (iterstickbuttons.hasNext()) { JoyControlStickButton *stickbutton = iterstickbuttons.next().value(); stickbutton->setIgnoreEventState(ignore); } } } QHashIterator iter5(vdpads); while (iter5.hasNext()) { VDPad *vdpad = iter5.next().value(); if (vdpad) { QHash* dpadbuttons = vdpad->getButtons(); QHashIterator itervdpadbuttons(*dpadbuttons); while (itervdpadbuttons.hasNext()) { JoyDPadButton *dpadbutton = itervdpadbuttons.next().value(); dpadbutton->setIgnoreEventState(ignore); } } } } void SetJoystick::propogateSetAxisActivated(int value) { JoyAxis *axis = static_cast(sender()); emit setAxisActivated(this->index, axis->getIndex(), value); } void SetJoystick::propogateSetAxisReleased(int value) { JoyAxis *axis = static_cast(sender()); emit setAxisReleased(this->index, axis->getIndex(), value); } void SetJoystick::enableButtonConnections(JoyButton *button) { connect(button, SIGNAL(setChangeActivated(int)), this, SLOT(propogateSetChange(int))); connect(button, SIGNAL(setAssignmentChanged(int,int,int)), this, SLOT(propogateSetButtonAssociation(int,int,int))); connect(button, SIGNAL(clicked(int)), this, SLOT(propogateSetButtonClick(int)), Qt::QueuedConnection); connect(button, SIGNAL(clicked(int)), device, SLOT(buttonClickEvent(int)), Qt::QueuedConnection); connect(button, SIGNAL(released(int)), this, SLOT(propogateSetButtonRelease(int))); connect(button, SIGNAL(released(int)), device, SLOT(buttonReleaseEvent(int))); connect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetButtonNameChange())); } void SetJoystick::enableAxisConnections(JoyAxis *axis) { connect(axis, SIGNAL(throttleChangePropogated(int)), this, SLOT(propogateSetAxisThrottleSetting(int))); connect(axis, SIGNAL(axisNameChanged()), this, SLOT(propogateSetAxisNameChange())); connect(axis, SIGNAL(active(int)), this, SLOT(propogateSetAxisActivated(int))); connect(axis, SIGNAL(released(int)), this, SLOT(propogateSetAxisReleased(int))); JoyAxisButton *button = axis->getNAxisButton(); connect(button, SIGNAL(setChangeActivated(int)), this, SLOT(propogateSetChange(int))); connect(button, SIGNAL(setAssignmentChanged(int,int,int,int)), this, SLOT(propogateSetAxisButtonAssociation(int,int,int,int))); connect(button, SIGNAL(clicked(int)), this, SLOT(propogateSetAxisButtonClick(int)), Qt::QueuedConnection); connect(button, SIGNAL(released(int)), this, SLOT(propogateSetAxisButtonRelease(int)), Qt::QueuedConnection); connect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetAxisButtonNameChange())); button = axis->getPAxisButton(); connect(button, SIGNAL(setChangeActivated(int)), this, SLOT(propogateSetChange(int))); connect(button, SIGNAL(setAssignmentChanged(int,int,int,int)), this, SLOT(propogateSetAxisButtonAssociation(int,int,int,int))); connect(button, SIGNAL(clicked(int)), this, SLOT(propogateSetAxisButtonClick(int)), Qt::QueuedConnection); connect(button, SIGNAL(released(int)), this, SLOT(propogateSetAxisButtonRelease(int)), Qt::QueuedConnection); connect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetAxisButtonNameChange())); } void SetJoystick::enableHatConnections(JoyDPad *dpad) { connect(dpad, SIGNAL(dpadNameChanged()), this, SLOT(propogateSetDPadNameChange())); QHash *buttons = dpad->getJoyButtons(); QHashIterator iter(*buttons); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); connect(button, SIGNAL(setChangeActivated(int)), this, SLOT(propogateSetChange(int))); connect(button, SIGNAL(setAssignmentChanged(int,int,int,int)), this, SLOT(propogateSetDPadButtonAssociation(int,int,int,int))); connect(button, SIGNAL(clicked(int)), this, SLOT(propogateSetDPadButtonClick(int)), Qt::QueuedConnection); connect(button, SIGNAL(clicked(int)), device, SLOT(dpadButtonClickEvent(int)), Qt::QueuedConnection); connect(button, SIGNAL(released(int)), this, SLOT(propogateSetDPadButtonRelease(int)), Qt::QueuedConnection); connect(button, SIGNAL(released(int)), device, SLOT(dpadButtonReleaseEvent(int)), Qt::QueuedConnection); connect(button, SIGNAL(buttonNameChanged()), this, SLOT(propogateSetDPadButtonNameChange())); } } InputDevice* SetJoystick::getInputDevice() { return device; } void SetJoystick::setName(QString name) { if (name.length() <= MAXNAMELENGTH) { this->name = name; emit propertyUpdated(); } else if (name.length() > MAXNAMELENGTH) { // Truncate name to 27 characters. Add ellipsis at the end. name.truncate(MAXNAMELENGTH-3); this->name = QString(name).append("..."); emit propertyUpdated(); } } QString SetJoystick::getName() { return name; } void SetJoystick::copyAssignments(SetJoystick *destSet) { for (int i=0; i < device->getNumberAxes(); i++) { JoyAxis *sourceAxis = axes.value(i); JoyAxis *destAxis = destSet->axes.value(i); if (sourceAxis && destAxis) { sourceAxis->copyAssignments(destAxis); } } QHashIterator stickIter(sticks); while (stickIter.hasNext()) { stickIter.next(); int index = stickIter.key(); JoyControlStick *sourceStick = stickIter.value(); JoyControlStick *destStick = destSet->sticks.value(index); if (sourceStick && destStick) { sourceStick->copyAssignments(destStick); } } for (int i=0; i < device->getNumberHats(); i++) { JoyDPad *sourceDPad = hats.value(i); JoyDPad *destDPad = destSet->hats.value(i); if (sourceDPad && destDPad) { sourceDPad->copyAssignments(destDPad); } } QHashIterator vdpadIter(vdpads); while (vdpadIter.hasNext()) { vdpadIter.next(); int index = vdpadIter.key(); VDPad *sourceVDpad = vdpadIter.value(); VDPad *destVDPad = destSet->vdpads.value(index); if (sourceVDpad && destVDPad) { sourceVDpad->copyAssignments(destVDPad); } } for (int i=0; i < device->getNumberButtons(); i++) { JoyButton *sourceButton = buttons.value(i); JoyButton *destButton = destSet->buttons.value(i); if (sourceButton && destButton) { sourceButton->copyAssignments(destButton); } } } QString SetJoystick::getSetLabel() { QString temp; if (!name.isEmpty()) { temp = tr("Set %1: %2").arg(index+1).arg(name); } else { temp = tr("Set %1").arg(index+1); } return temp; } void SetJoystick::establishPropertyUpdatedConnection() { connect(this, SIGNAL(propertyUpdated()), getInputDevice(), SLOT(profileEdited())); } void SetJoystick::disconnectPropertyUpdatedConnection() { disconnect(this, SIGNAL(propertyUpdated()), getInputDevice(), SLOT(profileEdited())); } /** * @brief Raise the dead zones for axes. Used when launching * the controller mapping window. */ void SetJoystick::raiseAxesDeadZones(int deadZone) { unsigned int tempDeadZone = deadZone; if (deadZone <= 0 || deadZone > 32767) { tempDeadZone = RAISEDDEADZONE; } QHashIterator axisIter(axes); while (axisIter.hasNext()) { JoyAxis *temp = axisIter.next().value(); temp->disconnectPropertyUpdatedConnection(); temp->setDeadZone(tempDeadZone); temp->establishPropertyUpdatedConnection(); } } void SetJoystick::currentAxesDeadZones(QList *axesDeadZones) { QHashIterator axisIter(axes); while (axisIter.hasNext()) { JoyAxis *temp = axisIter.next().value(); axesDeadZones->append(temp->getDeadZone()); } } void SetJoystick::setAxesDeadZones(QList *axesDeadZones) { QListIterator iter(*axesDeadZones); int axisNum = 0; while (iter.hasNext()) { int deadZoneValue = iter.next(); if (axes.contains(axisNum)) { JoyAxis *temp = getJoyAxis(axisNum); temp->disconnectPropertyUpdatedConnection(); temp->setDeadZone(deadZoneValue); temp->establishPropertyUpdatedConnection(); } axisNum++; } } void SetJoystick::setAxisThrottle(int axisNum, JoyAxis::ThrottleTypes throttle) { if (axes.contains(axisNum)) { JoyAxis *temp = axes.value(axisNum); temp->setInitialThrottle(throttle); } } antimicro-2.23/src/setjoystick.h000066400000000000000000000145171300750276700167570ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SETJOYSTICK_H #define SETJOYSTICK_H #include #include #include #include #include #include #include "joyaxis.h" #include "joycontrolstick.h" #include "joydpad.h" #include "joybutton.h" #include "vdpad.h" class InputDevice; class SetJoystick : public QObject { Q_OBJECT public: explicit SetJoystick(InputDevice *device, int index, QObject *parent=0); explicit SetJoystick(InputDevice *device, int index, bool runreset, QObject *parent=0); ~SetJoystick(); JoyAxis* getJoyAxis(int index); JoyButton* getJoyButton(int index); JoyDPad* getJoyDPad(int index); JoyControlStick* getJoyStick(int index); VDPad *getVDPad(int index); int getNumberButtons (); int getNumberAxes(); int getNumberHats(); int getNumberSticks(); int getNumberVDPads(); int getIndex(); unsigned int getRealIndex(); virtual void refreshButtons (); virtual void refreshAxes(); virtual void refreshHats(); void release(); void addControlStick(int index, JoyControlStick *stick); void removeControlStick(int index); void addVDPad(int index, VDPad *vdpad); void removeVDPad(int index); void setIgnoreEventState(bool ignore); InputDevice* getInputDevice(); void setName(QString name); QString getName(); QString getSetLabel(); void raiseAxesDeadZones(int deadZone=0); void currentAxesDeadZones(QList *axesDeadZones); void setAxesDeadZones(QList *axesDeadZones); void setAxisThrottle(int axisNum, JoyAxis::ThrottleTypes throttle); virtual void readConfig(QXmlStreamReader *xml); virtual void writeConfig(QXmlStreamWriter *xml); static const int MAXNAMELENGTH; static const int RAISEDDEADZONE; protected: bool isSetEmpty(); void deleteButtons(); void deleteAxes(); void deleteHats(); void deleteSticks(); void deleteVDpads(); void enableButtonConnections(JoyButton *button); void enableAxisConnections(JoyAxis *axis); void enableHatConnections(JoyDPad *dpad); QHash buttons; QHash axes; QHash hats; QHash sticks; QHash vdpads; int index; InputDevice *device; QString name; signals: void setChangeActivated(int index); void setAssignmentButtonChanged(int button, int originset, int newset, int mode); void setAssignmentAxisChanged(int button, int axis, int originset, int newset, int mode); void setAssignmentStickChanged(int button, int stick, int originset, int newset, int mode); void setAssignmentDPadChanged(int button, int dpad, int originset, int newset, int mode); void setAssignmentVDPadChanged(int button, int dpad, int originset, int newset, int mode); void setAssignmentAxisThrottleChanged(int axis, int originset); void setButtonClick(int index, int button); void setButtonRelease(int index, int button); void setAxisButtonClick(int setindex, int axis, int button); void setAxisButtonRelease(int setindex, int axis, int button); void setAxisActivated(int setindex, int axis, int value); void setAxisReleased(int setindex, int axis, int value); void setStickButtonClick(int setindex, int stick, int button); void setStickButtonRelease(int setindex, int stick, int button); void setDPadButtonClick(int setindex, int dpad, int button); void setDPadButtonRelease(int setindex, int dpad, int button); void setButtonNameChange(int index); void setAxisButtonNameChange(int axisIndex, int buttonIndex); void setStickButtonNameChange(int stickIndex, int buttonIndex); void setDPadButtonNameChange(int dpadIndex, int buttonIndex); void setVDPadButtonNameChange(int vdpadIndex, int buttonIndex); void setAxisNameChange(int axisIndex); void setStickNameChange(int stickIndex); void setDPadNameChange(int dpadIndex); void setVDPadNameChange(int vdpadIndex); void propertyUpdated(); public slots: virtual void reset(); void copyAssignments(SetJoystick *destSet); void propogateSetChange(int index); void propogateSetButtonAssociation(int button, int newset, int mode); void propogateSetAxisButtonAssociation(int button, int axis, int newset, int mode); void propogateSetStickButtonAssociation(int button, int stick, int newset, int mode); void propogateSetDPadButtonAssociation(int button, int dpad, int newset, int mode); void propogateSetVDPadButtonAssociation(int button, int dpad, int newset, int mode); void establishPropertyUpdatedConnection(); void disconnectPropertyUpdatedConnection(); protected slots: void propogateSetAxisThrottleSetting(int index); void propogateSetButtonClick(int button); void propogateSetButtonRelease(int button); void propogateSetAxisButtonClick(int button); void propogateSetAxisButtonRelease(int button); void propogateSetStickButtonClick(int button); void propogateSetStickButtonRelease(int button); void propogateSetDPadButtonClick(int button); void propogateSetDPadButtonRelease(int button); void propogateSetAxisActivated(int value); void propogateSetAxisReleased(int value); void propogateSetButtonNameChange(); void propogateSetAxisButtonNameChange(); void propogateSetStickButtonNameChange(); void propogateSetDPadButtonNameChange(); void propogateSetVDPadButtonNameChange(); void propogateSetAxisNameChange(); void propogateSetStickNameChange(); void propogateSetDPadNameChange(); void propogateSetVDPadNameChange(); }; Q_DECLARE_METATYPE(SetJoystick*) #endif // SETJOYSTICK_H antimicro-2.23/src/setnamesdialog.cpp000066400000000000000000000035021300750276700177260ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "setnamesdialog.h" #include "ui_setnamesdialog.h" SetNamesDialog::SetNamesDialog(InputDevice *device, QWidget *parent) : QDialog(parent), ui(new Ui::SetNamesDialog) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); this->device = device; for (int i=0; i < InputDevice::NUMBER_JOYSETS; i++) { QString tempSetName = device->getSetJoystick(i)->getName(); ui->setNamesTableWidget->setItem(i, 0, new QTableWidgetItem(tempSetName)); } connect(this, SIGNAL(accepted()), this, SLOT(saveSetNameChanges())); } SetNamesDialog::~SetNamesDialog() { delete ui; } void SetNamesDialog::saveSetNameChanges() { for (int i=0; i < ui->setNamesTableWidget->rowCount(); i++) { QTableWidgetItem *setNameItem = ui->setNamesTableWidget->item(i, 0); QString setNameText = setNameItem->text(); QString oldSetNameText = device->getSetJoystick(i)->getName(); if (setNameText != oldSetNameText) { device->getSetJoystick(i)->setName(setNameText); } } } antimicro-2.23/src/setnamesdialog.h000066400000000000000000000022621300750276700173750ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SETNAMESDIALOG_H #define SETNAMESDIALOG_H #include #include "inputdevice.h" namespace Ui { class SetNamesDialog; } class SetNamesDialog : public QDialog { Q_OBJECT public: explicit SetNamesDialog(InputDevice *device, QWidget *parent = 0); ~SetNamesDialog(); protected: InputDevice *device; private: Ui::SetNamesDialog *ui; private slots: void saveSetNameChanges(); }; #endif // SETNAMESDIALOG_H antimicro-2.23/src/setnamesdialog.ui000066400000000000000000000076111300750276700175660ustar00rootroot00000000000000 SetNamesDialog 0 0 535 399 Set Name Settings true 1 QAbstractItemView::SingleSelection true Qt::SolidLine false true false true true true 30 18 Set 1 Set 2 Set 3 Set 4 Set 5 Set 6 Set 7 Set 8 Name Qt::Vertical QSizePolicy::Fixed 20 20 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() SetNamesDialog accept() 248 254 157 274 buttonBox rejected() SetNamesDialog reject() 316 260 286 274 antimicro-2.23/src/simplekeygrabberbutton.cpp000066400000000000000000000245511300750276700215210ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include "event.h" #include "antkeymapper.h" #include "eventhandlerfactory.h" #ifdef Q_OS_WIN #include "winextras.h" #endif #ifdef Q_OS_UNIX #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) #include #endif #endif #include "simplekeygrabberbutton.h" SimpleKeyGrabberButton::SimpleKeyGrabberButton(QWidget *parent) : QPushButton(parent) { grabNextAction = false; grabbingWheel = false; edited = false; this->installEventFilter(this); } void SimpleKeyGrabberButton::keyPressEvent(QKeyEvent *event) { // Do not allow closing of dialog using Escape key if (event->key() == Qt::Key_Escape) { return; } QPushButton::keyPressEvent(event); } bool SimpleKeyGrabberButton::eventFilter(QObject *obj, QEvent *event) { Q_UNUSED(obj); int controlcode = 0; if (grabNextAction && event->type() == QEvent::MouseButtonRelease) { QMouseEvent *mouseEve = static_cast(event); if (mouseEve->button() == Qt::RightButton) { controlcode = 3; } else if (mouseEve->button() == Qt::MiddleButton) { controlcode = 2; } else { controlcode = mouseEve->button(); } //setText(QString(tr("Mouse")).append(" ").append(QString::number(controlcode))); buttonslot.setSlotCode(controlcode); buttonslot.setSlotMode(JoyButtonSlot::JoyMouseButton); refreshButtonLabel(); edited = true; releaseMouse(); releaseKeyboard(); grabNextAction = grabbingWheel = false; emit buttonCodeChanged(controlcode); } else if (grabNextAction && event->type() == QEvent::KeyRelease) { QKeyEvent *keyEve = static_cast(event); int tempcode = keyEve->nativeScanCode(); int virtualactual = keyEve->nativeVirtualKey(); BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); #ifdef Q_OS_WIN int finalvirtual = 0; int checkalias = 0; #ifdef WITH_VMULTI if (handler->getIdentifier() == "vmulti") { finalvirtual = WinExtras::correctVirtualKey(tempcode, virtualactual); checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual); QtKeyMapperBase *nativeWinKeyMapper = AntKeyMapper::getInstance()->getNativeKeyMapper(); unsigned int tempQtKey = 0; if (nativeWinKeyMapper) { tempQtKey = nativeWinKeyMapper->returnQtKey(finalvirtual); } //unsigned int tempQtKey = nativeWinKeyMapper.returnQtKey(finalvirtual); if (tempQtKey > 0) { finalvirtual = AntKeyMapper::getInstance()->returnVirtualKey(tempQtKey); checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual); } else { finalvirtual = AntKeyMapper::getInstance()->returnVirtualKey(keyEve->key()); } } #endif BACKEND_ELSE_IF (handler->getIdentifier() == "sendinput") { // Find more specific virtual key (VK_SHIFT -> VK_LSHIFT) // by checking for extended bit in scan code. finalvirtual = WinExtras::correctVirtualKey(tempcode, virtualactual); checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual, tempcode); } #else #if defined(WITH_X11) int finalvirtual = 0; int checkalias = 0; #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif // Obtain group 1 X11 keysym. Removes effects from modifiers. finalvirtual = X11KeyCodeToX11KeySym(tempcode); #ifdef WITH_UINPUT if (handler->getIdentifier() == "uinput") { // Find Qt Key corresponding to X11 KeySym. //checkalias = x11KeyMapper.returnQtKey(finalvirtual); QtKeyMapperBase *x11KeyMapper = AntKeyMapper::getInstance()->getNativeKeyMapper(); checkalias = x11KeyMapper->returnQtKey(finalvirtual); // Find corresponding Linux input key for the Qt key. finalvirtual = AntKeyMapper::getInstance()->returnVirtualKey(checkalias); } #endif #ifdef WITH_XTEST if (handler->getIdentifier() == "xtest") { // Check for alias against group 1 keysym. checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual); } #endif #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } else { // Not running on xcb platform. finalvirtual = tempcode; checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual); } #endif #else int finalvirtual = 0; int checkalias = 0; #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) if (QApplication::platformName() == QStringLiteral("xcb")) { #endif finalvirtual = AntKeyMapper::getInstance()->returnVirtualKey(keyEve->key()); checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual); #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) } else { // Not running on xcb platform. finalvirtual = tempcode; checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual); } #endif #endif #endif controlcode = tempcode; bool valueUpdated = false; if ((keyEve->modifiers() & Qt::ControlModifier) && keyEve->key() == Qt::Key_X) { controlcode = 0; refreshButtonLabel(); } else if (controlcode <= 0) { controlcode = 0; setText(""); valueUpdated = true; edited = true; } else { if (checkalias > 0 && finalvirtual > 0) { buttonslot.setSlotCode(finalvirtual, checkalias); buttonslot.setSlotMode(JoyButtonSlot::JoyKeyboard); setText(keysymToKeyString(finalvirtual, checkalias).toUpper()); edited = true; valueUpdated = true; } else if (virtualactual > 0) { buttonslot.setSlotCode(virtualactual); buttonslot.setSlotMode(JoyButtonSlot::JoyKeyboard); setText(keysymToKeyString(virtualactual).toUpper()); edited = true; valueUpdated = true; } } grabNextAction = false; grabbingWheel = false; releaseMouse(); releaseKeyboard(); if (valueUpdated) { emit buttonCodeChanged(controlcode); } } else if (grabNextAction && event->type() == QEvent::Wheel && !grabbingWheel) { grabbingWheel = true; } else if (grabNextAction && event->type() == QEvent::Wheel) { QWheelEvent *wheelEve = static_cast(event); QString text = QString(tr("Mouse")).append(" "); if (wheelEve->orientation() == Qt::Vertical && wheelEve->delta() >= 120) { controlcode = 4; } else if (wheelEve->orientation() == Qt::Vertical && wheelEve->delta() <= -120) { controlcode = 5; } else if (wheelEve->orientation() == Qt::Horizontal && wheelEve->delta() >= 120) { controlcode = 6; } else if (wheelEve->orientation() == Qt::Horizontal && wheelEve->delta() <= -120) { controlcode = 7; } if (controlcode > 0) { text = text.append(QString::number(controlcode)); setText(text); grabNextAction = false; grabbingWheel = false; edited = true; releaseMouse(); releaseKeyboard(); buttonslot.setSlotCode(controlcode); buttonslot.setSlotMode(JoyButtonSlot::JoyMouseButton); emit buttonCodeChanged(controlcode); } } else if (event->type() == QEvent::MouseButtonRelease) { QMouseEvent *mouseEve = static_cast(event); if (mouseEve->button() == Qt::LeftButton) { grabNextAction = true; setText("..."); setFocus(); grabKeyboard(); grabMouse(); } } return false; } void SimpleKeyGrabberButton::setValue(int value, unsigned int alias, JoyButtonSlot::JoySlotInputAction mode) { buttonslot.setSlotCode(value, alias); buttonslot.setSlotMode(mode); edited = true; setText(buttonslot.getSlotString()); } void SimpleKeyGrabberButton::setValue(int value, JoyButtonSlot::JoySlotInputAction mode) { buttonslot.setSlotCode(value); buttonslot.setSlotMode(mode); edited = true; setText(buttonslot.getSlotString()); } void SimpleKeyGrabberButton::setValue(QString value, JoyButtonSlot::JoySlotInputAction mode) { switch (mode) { case JoyButtonSlot::JoyLoadProfile: case JoyButtonSlot::JoyTextEntry: case JoyButtonSlot::JoyExecute: { buttonslot.setTextData(value); buttonslot.setSlotMode(mode); edited = true; break; } } setText(buttonslot.getSlotString()); } JoyButtonSlot* SimpleKeyGrabberButton::getValue() { return &buttonslot; } void SimpleKeyGrabberButton::refreshButtonLabel() { setText(buttonslot.getSlotString()); } bool SimpleKeyGrabberButton::isEdited() { return edited; } bool SimpleKeyGrabberButton::isGrabbing() { return grabNextAction; } antimicro-2.23/src/simplekeygrabberbutton.h000066400000000000000000000035351300750276700211650ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SIMPLEKEYGRABBERBUTTON_H #define SIMPLEKEYGRABBERBUTTON_H #include #include #include #include #include "joybuttonslot.h" class SimpleKeyGrabberButton : public QPushButton { Q_OBJECT public: explicit SimpleKeyGrabberButton(QWidget *parent = 0); void setValue(int value, unsigned int alias, JoyButtonSlot::JoySlotInputAction mode=JoyButtonSlot::JoyKeyboard); void setValue(int value, JoyButtonSlot::JoySlotInputAction mode=JoyButtonSlot::JoyKeyboard); void setValue(QString value, JoyButtonSlot::JoySlotInputAction mode=JoyButtonSlot::JoyLoadProfile); JoyButtonSlot* getValue(); bool isEdited(); bool isGrabbing(); protected: virtual void keyPressEvent(QKeyEvent *event); virtual bool eventFilter(QObject *obj, QEvent *event); bool grabNextAction; bool grabbingWheel; bool edited; JoyButtonSlot buttonslot; signals: void buttonCodeChanged(int value); public slots: void refreshButtonLabel(); protected slots: }; Q_DECLARE_METATYPE(SimpleKeyGrabberButton*) #endif // SIMPLEKEYGRABBERBUTTON_H antimicro-2.23/src/slotitemlistwidget.cpp000066400000000000000000000030711300750276700206700ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "slotitemlistwidget.h" #include "simplekeygrabberbutton.h" SlotItemListWidget::SlotItemListWidget(QWidget *parent) : QListWidget(parent) { } void SlotItemListWidget::keyPressEvent(QKeyEvent *event) { bool propogate = true; QListWidgetItem *currentItem = this->item(this->currentRow()); SimpleKeyGrabberButton *tempbutton = 0; if (currentItem) { tempbutton = currentItem->data(Qt::UserRole).value(); } if (tempbutton && tempbutton->isGrabbing()) { switch (event->key()) { case Qt::Key_Home: case Qt::Key_End: { propogate = false; break; } } } if (propogate) { QListWidget::keyPressEvent(event); } } antimicro-2.23/src/slotitemlistwidget.h000066400000000000000000000021221300750276700203310ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SLOTITEMLISTWIDGET_H #define SLOTITEMLISTWIDGET_H #include #include class SlotItemListWidget : public QListWidget { Q_OBJECT public: explicit SlotItemListWidget(QWidget *parent = 0); protected: virtual void keyPressEvent(QKeyEvent *event); signals: public slots: }; #endif // SLOTITEMLISTWIDGET_H antimicro-2.23/src/springmousemoveinfo.h000066400000000000000000000025261300750276700205170ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SPRINGMOUSEMOVEINFO_H #define SPRINGMOUSEMOVEINFO_H namespace PadderCommon { typedef struct _springModeInfo { // Displacement of the X axis double displacementX; // Displacement of the Y axis double displacementY; // Width and height of the spring mode box unsigned int width; unsigned int height; // Should the cursor not move around the center // of the screen. bool relative; int screen; double springDeadX; double springDeadY; } springModeInfo; } #endif // SPRINGMOUSEMOVEINFO_H antimicro-2.23/src/stickpushbuttongroup.cpp000066400000000000000000000162761300750276700212710ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "stickpushbuttongroup.h" #include "buttoneditdialog.h" #include "joycontrolstickeditdialog.h" StickPushButtonGroup::StickPushButtonGroup(JoyControlStick *stick, bool displayNames, QWidget *parent) : QGridLayout(parent) { this->stick = stick; this->displayNames = displayNames; generateButtons(); changeButtonLayout(); connect(stick, SIGNAL(joyModeChanged()), this, SLOT(changeButtonLayout())); } void StickPushButtonGroup::generateButtons() { QHash *stickButtons = stick->getButtons(); JoyControlStickButton *button = 0; JoyControlStickButtonPushButton *pushbutton = 0; button = stickButtons->value(JoyControlStick::StickLeftUp); upLeftButton = new JoyControlStickButtonPushButton(button, displayNames, parentWidget()); pushbutton = upLeftButton; connect(pushbutton, SIGNAL(clicked()), this, SLOT(openStickButtonDialog())); button->establishPropertyUpdatedConnections(); connect(button, SIGNAL(slotsChanged()), this, SLOT(propogateSlotsChanged())); addWidget(pushbutton, 0, 0); button = stickButtons->value(JoyControlStick::StickUp); upButton = new JoyControlStickButtonPushButton(button, displayNames, parentWidget()); pushbutton = upButton; connect(pushbutton, SIGNAL(clicked()), this, SLOT(openStickButtonDialog())); button->establishPropertyUpdatedConnections(); connect(button, SIGNAL(slotsChanged()), this, SLOT(propogateSlotsChanged())); addWidget(pushbutton, 0, 1); button = stickButtons->value(JoyControlStick::StickRightUp); upRightButton = new JoyControlStickButtonPushButton(button, displayNames, parentWidget()); pushbutton = upRightButton; connect(pushbutton, SIGNAL(clicked()), this, SLOT(openStickButtonDialog())); button->establishPropertyUpdatedConnections(); connect(button, SIGNAL(slotsChanged()), this, SLOT(propogateSlotsChanged())); addWidget(pushbutton, 0, 2); button = stickButtons->value(JoyControlStick::StickLeft); leftButton = new JoyControlStickButtonPushButton(button, displayNames, parentWidget()); pushbutton = leftButton; connect(pushbutton, SIGNAL(clicked()), this, SLOT(openStickButtonDialog())); button->establishPropertyUpdatedConnections(); connect(button, SIGNAL(slotsChanged()), this, SLOT(propogateSlotsChanged())); addWidget(pushbutton, 1, 0); stickWidget = new JoyControlStickPushButton(stick, displayNames, parentWidget()); stickWidget->setIcon(QIcon::fromTheme(QString::fromUtf8("games-config-options"))); connect(stickWidget, SIGNAL(clicked()), this, SLOT(showStickDialog())); addWidget(stickWidget, 1, 1); button = stickButtons->value(JoyControlStick::StickRight); rightButton = new JoyControlStickButtonPushButton(button, displayNames, parentWidget()); pushbutton = rightButton; connect(pushbutton, SIGNAL(clicked()), this, SLOT(openStickButtonDialog())); button->establishPropertyUpdatedConnections(); connect(button, SIGNAL(slotsChanged()), this, SLOT(propogateSlotsChanged())); addWidget(pushbutton, 1, 2); button = stickButtons->value(JoyControlStick::StickLeftDown); downLeftButton = new JoyControlStickButtonPushButton(button, displayNames, parentWidget()); pushbutton = downLeftButton; connect(pushbutton, SIGNAL(clicked()), this, SLOT(openStickButtonDialog())); button->establishPropertyUpdatedConnections(); connect(button, SIGNAL(slotsChanged()), this, SLOT(propogateSlotsChanged())); addWidget(pushbutton, 2, 0); button = stickButtons->value(JoyControlStick::StickDown); downButton = new JoyControlStickButtonPushButton(button, displayNames, parentWidget()); pushbutton = downButton; connect(pushbutton, SIGNAL(clicked()), this, SLOT(openStickButtonDialog())); button->establishPropertyUpdatedConnections(); connect(button, SIGNAL(slotsChanged()), this, SLOT(propogateSlotsChanged())); addWidget(pushbutton, 2, 1); button = stickButtons->value(JoyControlStick::StickRightDown); downRightButton = new JoyControlStickButtonPushButton(button, displayNames, parentWidget()); pushbutton = downRightButton; connect(pushbutton, SIGNAL(clicked()), this, SLOT(openStickButtonDialog())); button->establishPropertyUpdatedConnections(); connect(button, SIGNAL(slotsChanged()), this, SLOT(propogateSlotsChanged())); addWidget(pushbutton, 2, 2); } void StickPushButtonGroup::changeButtonLayout() { if (stick->getJoyMode() == JoyControlStick::StandardMode || stick->getJoyMode() == JoyControlStick::EightWayMode || stick->getJoyMode() == JoyControlStick::FourWayCardinal) { upButton->setVisible(true); downButton->setVisible(true); leftButton->setVisible(true); rightButton->setVisible(true); } else { upButton->setVisible(false); downButton->setVisible(false); leftButton->setVisible(false); rightButton->setVisible(false); } if (stick->getJoyMode() == JoyControlStick::EightWayMode || stick->getJoyMode() == JoyControlStick::FourWayDiagonal) { upLeftButton->setVisible(true); upRightButton->setVisible(true); downLeftButton->setVisible(true); downRightButton->setVisible(true); } else { upLeftButton->setVisible(false); upRightButton->setVisible(false); downLeftButton->setVisible(false); downRightButton->setVisible(false); } } void StickPushButtonGroup::propogateSlotsChanged() { emit buttonSlotChanged(); } JoyControlStick* StickPushButtonGroup::getStick() { return stick; } void StickPushButtonGroup::openStickButtonDialog() { JoyControlStickButtonPushButton *pushbutton = static_cast(sender()); ButtonEditDialog *dialog = new ButtonEditDialog(pushbutton->getButton(), parentWidget()); dialog->show(); } void StickPushButtonGroup::showStickDialog() { JoyControlStickEditDialog *dialog = new JoyControlStickEditDialog(stick, parentWidget()); dialog->show(); } void StickPushButtonGroup::toggleNameDisplay() { displayNames = !displayNames; upButton->toggleNameDisplay(); downButton->toggleNameDisplay(); leftButton->toggleNameDisplay(); rightButton->toggleNameDisplay(); upLeftButton->toggleNameDisplay(); upRightButton->toggleNameDisplay(); downLeftButton->toggleNameDisplay(); downRightButton->toggleNameDisplay(); stickWidget->toggleNameDisplay(); } antimicro-2.23/src/stickpushbuttongroup.h000066400000000000000000000036711300750276700207310ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef STICKPUSHBUTTONGROUP_H #define STICKPUSHBUTTONGROUP_H #include #include "joycontrolstick.h" #include "joycontrolstickpushbutton.h" #include "joycontrolstickbuttonpushbutton.h" class StickPushButtonGroup : public QGridLayout { Q_OBJECT public: explicit StickPushButtonGroup(JoyControlStick *stick, bool displayNames = false, QWidget *parent = 0); JoyControlStick *getStick(); protected: void generateButtons(); JoyControlStick *stick; bool displayNames; JoyControlStickButtonPushButton *upButton; JoyControlStickButtonPushButton *downButton; JoyControlStickButtonPushButton *leftButton; JoyControlStickButtonPushButton *rightButton; JoyControlStickButtonPushButton *upLeftButton; JoyControlStickButtonPushButton *upRightButton; JoyControlStickButtonPushButton *downLeftButton; JoyControlStickButtonPushButton *downRightButton; JoyControlStickPushButton *stickWidget; signals: void buttonSlotChanged(); public slots: void changeButtonLayout(); void toggleNameDisplay(); private slots: void propogateSlotsChanged(); void openStickButtonDialog(); void showStickDialog(); }; #endif // STICKPUSHBUTTONGROUP_H antimicro-2.23/src/uihelpers/000077500000000000000000000000001300750276700162235ustar00rootroot00000000000000antimicro-2.23/src/uihelpers/advancebuttondialoghelper.cpp000066400000000000000000000034651300750276700241540ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "advancebuttondialoghelper.h" AdvanceButtonDialogHelper::AdvanceButtonDialogHelper(JoyButton *button, QObject *parent) : QObject(parent) { Q_ASSERT(button); this->button = button; } void AdvanceButtonDialogHelper::insertAssignedSlot(int code, unsigned int alias, int index, JoyButtonSlot::JoySlotInputAction mode) { button->eventReset(); button->insertAssignedSlot(code, alias, index, mode); } void AdvanceButtonDialogHelper::setAssignedSlot(JoyButtonSlot *otherSlot, int index) { button->eventReset(); button->setAssignedSlot(otherSlot, index); } void AdvanceButtonDialogHelper::setAssignedSlot(int code, unsigned int alias, int index, JoyButtonSlot::JoySlotInputAction mode) { button->eventReset(); button->setAssignedSlot(code, alias, index, mode); } void AdvanceButtonDialogHelper::removeAssignedSlot(int index) { button->eventReset(); button->removeAssignedSlot(index); } antimicro-2.23/src/uihelpers/advancebuttondialoghelper.h000066400000000000000000000031241300750276700236110ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef ADVANCEBUTTONDIALOGHELPER_H #define ADVANCEBUTTONDIALOGHELPER_H #include #include "joybutton.h" #include "joybuttonslot.h" class AdvanceButtonDialogHelper : public QObject { Q_OBJECT public: explicit AdvanceButtonDialogHelper(JoyButton *button, QObject *parent = 0); protected: JoyButton *button; signals: public slots: void setAssignedSlot(JoyButtonSlot *otherSlot, int index); void setAssignedSlot(int code, unsigned int alias, int index, JoyButtonSlot::JoySlotInputAction mode=JoyButtonSlot::JoyKeyboard); void insertAssignedSlot(int code, unsigned int alias, int index, JoyButtonSlot::JoySlotInputAction mode=JoyButtonSlot::JoyKeyboard); void removeAssignedSlot(int index); }; #endif // ADVANCEBUTTONDIALOGHELPER_H antimicro-2.23/src/uihelpers/buttoneditdialoghelper.cpp000066400000000000000000000024261300750276700234740ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "buttoneditdialoghelper.h" ButtonEditDialogHelper::ButtonEditDialogHelper(JoyButton *button, QObject *parent) : QObject(parent) { Q_ASSERT(button); this->button = button; } void ButtonEditDialogHelper::setAssignedSlot(int code, unsigned int alias, JoyButtonSlot::JoySlotInputAction mode) { button->clearSlotsEventReset(false); button->setAssignedSlot(code, alias, mode); } void ButtonEditDialogHelper::setUseTurbo(bool useTurbo) { button->setUseTurbo(useTurbo); } antimicro-2.23/src/uihelpers/buttoneditdialoghelper.h000066400000000000000000000024541300750276700231420ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef BUTTONEDITDIALOGHELPER_H #define BUTTONEDITDIALOGHELPER_H #include #include "joybutton.h" #include "joybuttonslot.h" class ButtonEditDialogHelper : public QObject { Q_OBJECT public: explicit ButtonEditDialogHelper(JoyButton *button, QObject *parent = 0); protected: JoyButton *button; signals: public slots: void setAssignedSlot(int code, unsigned int alias, JoyButtonSlot::JoySlotInputAction mode=JoyButtonSlot::JoyKeyboard); void setUseTurbo(bool useTurbo); }; #endif // BUTTONEDITDIALOGHELPER_H antimicro-2.23/src/uihelpers/dpadcontextmenuhelper.cpp000066400000000000000000000047611300750276700233410ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "dpadcontextmenuhelper.h" DPadContextMenuHelper::DPadContextMenuHelper(JoyDPad *dpad, QObject *parent) : QObject(parent) { Q_ASSERT(dpad); this->dpad = dpad; } void DPadContextMenuHelper::setPendingSlots(QHash *tempSlots) { pendingSlots.clear(); QHashIterator iter(*tempSlots); while (iter.hasNext()) { iter.next(); JoyButtonSlot *slot = iter.value(); JoyDPadButton::JoyDPadDirections tempDir = iter.key(); pendingSlots.insert(tempDir, slot); } } void DPadContextMenuHelper::clearPendingSlots() { pendingSlots.clear(); } void DPadContextMenuHelper::setFromPendingSlots() { if (!pendingSlots.isEmpty()) { QHashIterator iter(pendingSlots); while (iter.hasNext()) { iter.next(); JoyButtonSlot *slot = iter.value(); if (slot) { JoyDPadButton::JoyDPadDirections tempDir = iter.key(); JoyDPadButton *button = dpad->getJoyButton(tempDir); button->clearSlotsEventReset(false); button->setAssignedSlot(slot->getSlotCode(), slot->getSlotCodeAlias(), slot->getSlotMode()); slot->deleteLater(); } } } } void DPadContextMenuHelper::clearButtonsSlotsEventReset() { QHash *buttons = dpad->getButtons(); QHashIterator iter(*buttons); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); button->clearSlotsEventReset(); } } antimicro-2.23/src/uihelpers/dpadcontextmenuhelper.h000066400000000000000000000026031300750276700227770ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DPADCONTEXTMENUHELPER_H #define DPADCONTEXTMENUHELPER_H #include #include #include "joydpad.h" #include "joybuttonslot.h" class DPadContextMenuHelper : public QObject { Q_OBJECT public: explicit DPadContextMenuHelper(JoyDPad *dpad, QObject *parent = 0); void setPendingSlots(QHash *tempSlots); void clearPendingSlots(); protected: JoyDPad *dpad; QHash pendingSlots; signals: public slots: void setFromPendingSlots(); void clearButtonsSlotsEventReset(); }; #endif // DPADCONTEXTMENUHELPER_H antimicro-2.23/src/uihelpers/dpadeditdialoghelper.cpp000066400000000000000000000051751300750276700230750ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "dpadeditdialoghelper.h" DPadEditDialogHelper::DPadEditDialogHelper(JoyDPad *dpad, QObject *parent) : QObject(parent) { Q_ASSERT(dpad); this->dpad = dpad; } void DPadEditDialogHelper::setPendingSlots(QHash *tempSlots) { pendingSlots.clear(); QHashIterator iter(*tempSlots); while (iter.hasNext()) { iter.next(); JoyButtonSlot *slot = iter.value(); JoyDPadButton::JoyDPadDirections tempDir = iter.key(); pendingSlots.insert(tempDir, slot); } } void DPadEditDialogHelper::clearPendingSlots() { pendingSlots.clear(); } void DPadEditDialogHelper::setFromPendingSlots() { if (!pendingSlots.isEmpty()) { QHashIterator iter(pendingSlots); while (iter.hasNext()) { iter.next(); JoyButtonSlot *slot = iter.value(); if (slot) { JoyDPadButton::JoyDPadDirections tempDir = iter.key(); JoyDPadButton *button = dpad->getJoyButton(tempDir); button->clearSlotsEventReset(false); button->setAssignedSlot(slot->getSlotCode(), slot->getSlotCodeAlias(), slot->getSlotMode()); slot->deleteLater(); } } } } void DPadEditDialogHelper::clearButtonsSlotsEventReset() { QHash *buttons = dpad->getButtons(); QHashIterator iter(*buttons); while (iter.hasNext()) { JoyDPadButton *button = iter.next().value(); button->clearSlotsEventReset(); } } void DPadEditDialogHelper::updateJoyDPadDelay(int value) { int temp = value * 10; if (dpad->getDPadDelay() != temp) { dpad->setDPadDelay(temp); } } antimicro-2.23/src/uihelpers/dpadeditdialoghelper.h000066400000000000000000000026461300750276700225420ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DPADEDITDIALOGHELPER_H #define DPADEDITDIALOGHELPER_H #include #include #include "joydpad.h" #include "joybuttonslot.h" class DPadEditDialogHelper : public QObject { Q_OBJECT public: explicit DPadEditDialogHelper(JoyDPad *dpad, QObject *parent = 0); void setPendingSlots(QHash *tempSlots); void clearPendingSlots(); protected: JoyDPad *dpad; QHash pendingSlots; signals: public slots: void setFromPendingSlots(); void clearButtonsSlotsEventReset(); void updateJoyDPadDelay(int value); }; #endif // DPADEDITDIALOGHELPER_H antimicro-2.23/src/uihelpers/gamecontrollermappingdialoghelper.cpp000066400000000000000000000040551300750276700257040ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "gamecontrollermappingdialoghelper.h" GameControllerMappingDialogHelper::GameControllerMappingDialogHelper(InputDevice *device, QObject *parent) : QObject(parent) { this->device = device; } void GameControllerMappingDialogHelper::raiseDeadZones() { device->setRawAxisDeadZone(InputDevice::RAISEDDEADZONE); device->getActiveSetJoystick()->raiseAxesDeadZones(); } void GameControllerMappingDialogHelper::raiseDeadZones(int deadZone) { device->getActiveSetJoystick()->raiseAxesDeadZones(deadZone); device->setRawAxisDeadZone(deadZone); } void GameControllerMappingDialogHelper::setupDeadZones() { device->getActiveSetJoystick()->setIgnoreEventState(true); device->getActiveSetJoystick()->release(); device->getActiveSetJoystick()->currentAxesDeadZones(&originalAxesDeadZones); device->getActiveSetJoystick()->raiseAxesDeadZones(); device->setRawAxisDeadZone(InputDevice::RAISEDDEADZONE); } void GameControllerMappingDialogHelper::restoreDeviceDeadZones() { device->getActiveSetJoystick()->setIgnoreEventState(false); device->getActiveSetJoystick()->release(); device->getActiveSetJoystick()->setAxesDeadZones(&originalAxesDeadZones); device->setRawAxisDeadZone(InputDevice::RAISEDDEADZONE); } antimicro-2.23/src/uihelpers/gamecontrollermappingdialoghelper.h000066400000000000000000000025141300750276700253470ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef GAMECONTROLLERMAPPINGDIALOGHELPER_H #define GAMECONTROLLERMAPPINGDIALOGHELPER_H #include #include #include "inputdevice.h" class GameControllerMappingDialogHelper : public QObject { Q_OBJECT public: explicit GameControllerMappingDialogHelper(InputDevice *device, QObject *parent = 0); protected: InputDevice *device; QList originalAxesDeadZones; signals: public slots: void raiseDeadZones(); void raiseDeadZones(int deadZone); void setupDeadZones(); void restoreDeviceDeadZones(); }; #endif // GAMECONTROLLERMAPPINGDIALOGHELPER_H antimicro-2.23/src/uihelpers/joyaxiscontextmenuhelper.cpp000066400000000000000000000034151300750276700241120ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "joyaxiscontextmenuhelper.h" JoyAxisContextMenuHelper::JoyAxisContextMenuHelper(JoyAxis *axis, QObject *parent) : QObject(parent) { Q_ASSERT(axis); this->axis = axis; } void JoyAxisContextMenuHelper::setNAssignedSlot(int code, unsigned int alias, JoyButtonSlot::JoySlotInputAction mode) { JoyButton *button = axis->getNAxisButton(); button->clearSlotsEventReset(false); button->setAssignedSlot(code, alias, mode); } void JoyAxisContextMenuHelper::setPAssignedSlot(int code, unsigned int alias, JoyButtonSlot::JoySlotInputAction mode) { JoyButton *button = axis->getPAxisButton(); button->clearSlotsEventReset(false); button->setAssignedSlot(code, alias, mode); } void JoyAxisContextMenuHelper::clearAndResetAxisButtons() { JoyAxisButton *nbutton = axis->getNAxisButton(); JoyAxisButton *pbutton = axis->getPAxisButton(); nbutton->clearSlotsEventReset(); pbutton->clearSlotsEventReset(); } antimicro-2.23/src/uihelpers/joyaxiscontextmenuhelper.h000066400000000000000000000027021300750276700235550ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYAXISCONTEXTMENUHELPER_H #define JOYAXISCONTEXTMENUHELPER_H #include #include "joyaxis.h" #include "joybuttonslot.h" class JoyAxisContextMenuHelper : public QObject { Q_OBJECT public: explicit JoyAxisContextMenuHelper(JoyAxis *axis, QObject *parent = 0); protected: JoyAxis *axis; signals: public slots: void setNAssignedSlot(int code, unsigned int alias, JoyButtonSlot::JoySlotInputAction mode=JoyButtonSlot::JoyKeyboard); void setPAssignedSlot(int code, unsigned int alias, JoyButtonSlot::JoySlotInputAction mode=JoyButtonSlot::JoyKeyboard); void clearAndResetAxisButtons(); }; #endif // JOYAXISCONTEXTMENUHELPER_H antimicro-2.23/src/uihelpers/joycontrolstickcontextmenuhelper.cpp000066400000000000000000000055261300750276700256710ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "joycontrolstickcontextmenuhelper.h" JoyControlStickContextMenuHelper::JoyControlStickContextMenuHelper(JoyControlStick *stick, QObject *parent) : QObject(parent) { Q_ASSERT(stick); this->stick = stick; } void JoyControlStickContextMenuHelper::setPendingSlots(QHash *tempSlots) { pendingSlots.clear(); QHashIterator iter(*tempSlots); while (iter.hasNext()) { iter.next(); JoyButtonSlot *slot = iter.value(); JoyControlStick::JoyStickDirections tempDir = iter.key(); pendingSlots.insert(tempDir, slot); } } void JoyControlStickContextMenuHelper::clearPendingSlots() { pendingSlots.clear(); } void JoyControlStickContextMenuHelper::setFromPendingSlots() { if (!pendingSlots.isEmpty()) { QHashIterator iter(pendingSlots); while (iter.hasNext()) { iter.next(); JoyButtonSlot *slot = iter.value(); if (slot) { JoyControlStick::JoyStickDirections tempDir = iter.key(); JoyControlStickButton *button = stick->getDirectionButton(tempDir); if (button) { button->clearSlotsEventReset(false); button->setAssignedSlot(slot->getSlotCode(), slot->getSlotCodeAlias(), slot->getSlotMode()); } slot->deleteLater(); } } } } void JoyControlStickContextMenuHelper::clearButtonsSlotsEventReset() { QHash *buttons = stick->getButtons(); QHashIterator iter(*buttons); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); if (button) { button->clearSlotsEventReset(); } } } antimicro-2.23/src/uihelpers/joycontrolstickcontextmenuhelper.h000066400000000000000000000026771300750276700253420ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYCONTROLSTICKCONTEXTMENUHELPER_H #define JOYCONTROLSTICKCONTEXTMENUHELPER_H #include #include #include "joycontrolstick.h" class JoyControlStickContextMenuHelper : public QObject { Q_OBJECT public: explicit JoyControlStickContextMenuHelper(JoyControlStick *stick, QObject *parent = 0); void setPendingSlots(QHash *tempSlots); void clearPendingSlots(); protected: JoyControlStick *stick; QHash pendingSlots; signals: public slots: void setFromPendingSlots(); void clearButtonsSlotsEventReset(); }; #endif // JOYCONTROLSTICKCONTEXTMENUHELPER_H antimicro-2.23/src/uihelpers/joycontrolstickeditdialoghelper.cpp000066400000000000000000000060201300750276700254130ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "joycontrolstickeditdialoghelper.h" JoyControlStickEditDialogHelper::JoyControlStickEditDialogHelper(JoyControlStick *stick, QObject *parent) : QObject(parent) { Q_ASSERT(stick); this->stick = stick; } void JoyControlStickEditDialogHelper::setPendingSlots(QHash *tempSlots) { pendingSlots.clear(); QHashIterator iter(*tempSlots); while (iter.hasNext()) { iter.next(); JoyButtonSlot *slot = iter.value(); JoyControlStick::JoyStickDirections tempDir = iter.key(); pendingSlots.insert(tempDir, slot); } } void JoyControlStickEditDialogHelper::clearPendingSlots() { pendingSlots.clear(); } void JoyControlStickEditDialogHelper::setFromPendingSlots() { if (!pendingSlots.isEmpty()) { QHashIterator iter(pendingSlots); while (iter.hasNext()) { iter.next(); JoyButtonSlot *slot = iter.value(); if (slot) { JoyControlStick::JoyStickDirections tempDir = iter.key(); JoyControlStickButton *button = stick->getDirectionButton(tempDir); if (button) { button->clearSlotsEventReset(false); button->setAssignedSlot(slot->getSlotCode(), slot->getSlotCodeAlias(), slot->getSlotMode()); } slot->deleteLater(); } } } } void JoyControlStickEditDialogHelper::clearButtonsSlotsEventReset() { QHash *buttons = stick->getButtons(); QHashIterator iter(*buttons); while (iter.hasNext()) { JoyControlStickButton *button = iter.next().value(); if (button) { button->clearSlotsEventReset(); } } } void JoyControlStickEditDialogHelper::updateControlStickDelay(int value) { int temp = value * 10; if (stick->getStickDelay() != temp) { stick->setStickDelay(temp); } } antimicro-2.23/src/uihelpers/joycontrolstickeditdialoghelper.h000066400000000000000000000027471300750276700250740ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYCONTROLSTICKEDITDIALOGHELPER_H #define JOYCONTROLSTICKEDITDIALOGHELPER_H #include #include #include "joycontrolstick.h" class JoyControlStickEditDialogHelper : public QObject { Q_OBJECT public: explicit JoyControlStickEditDialogHelper(JoyControlStick *stick, QObject *parent = 0); void setPendingSlots(QHash *tempSlots); void clearPendingSlots(); protected: JoyControlStick *stick; QHash pendingSlots; signals: public slots: void setFromPendingSlots(); void clearButtonsSlotsEventReset(); void updateControlStickDelay(int value); }; #endif // JOYCONTROLSTICKEDITDIALOGHELPER_H antimicro-2.23/src/uihelpers/joytabwidgethelper.cpp000066400000000000000000000063461300750276700226340ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "joytabwidgethelper.h" JoyTabWidgetHelper::JoyTabWidgetHelper(InputDevice *device, QObject *parent) : QObject(parent) { Q_ASSERT(device); this->device = device; this->reader = 0; this->writer = 0; this->errorOccurred = false; } JoyTabWidgetHelper::~JoyTabWidgetHelper() { if (this->reader) { delete this->reader; this->reader = 0; } if (this->writer) { delete this->writer; this->writer = 0; } } bool JoyTabWidgetHelper::hasReader() { return (this->reader != 0); } XMLConfigReader* JoyTabWidgetHelper::getReader() { return this->reader; } bool JoyTabWidgetHelper::hasWriter() { return (this->writer != 0); } XMLConfigWriter* JoyTabWidgetHelper::getWriter() { return this->writer; } bool JoyTabWidgetHelper::hasError() { return errorOccurred; } QString JoyTabWidgetHelper::getErrorString() { return lastErrorString; } bool JoyTabWidgetHelper::readConfigFile(QString filepath) { bool result = false; device->disconnectPropertyUpdatedConnection(); if (device->getActiveSetNumber() != 0) { device->setActiveSetNumber(0); } device->resetButtonDownCount(); if (this->reader) { this->reader->deleteLater(); this->reader = 0; } this->reader = new XMLConfigReader; this->reader->setFileName(filepath); this->reader->configJoystick(device); device->establishPropertyUpdatedConnection(); result = !this->reader->hasError(); return result; } bool JoyTabWidgetHelper::readConfigFileWithRevert(QString filepath) { bool result = false; device->revertProfileEdited(); result = readConfigFile(filepath); return result; } bool JoyTabWidgetHelper::writeConfigFile(QString filepath) { bool result = false; if (this->writer) { this->writer->deleteLater(); this->writer = 0; } this->writer = new XMLConfigWriter; this->writer->setFileName(filepath); this->writer->write(device); result = !this->writer->hasError(); return result; } void JoyTabWidgetHelper::reInitDevice() { device->disconnectPropertyUpdatedConnection(); if (device->getActiveSetNumber() != 0) { device->setActiveSetNumber(0); } device->transferReset(); device->resetButtonDownCount(); device->reInitButtons(); device->establishPropertyUpdatedConnection(); } void JoyTabWidgetHelper::reInitDeviceWithRevert() { device->revertProfileEdited(); reInitDevice(); } antimicro-2.23/src/uihelpers/joytabwidgethelper.h000066400000000000000000000032561300750276700222760ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef JOYTABWIDGETHELPER_H #define JOYTABWIDGETHELPER_H #include #include "inputdevice.h" #include "joybutton.h" #include "joybuttonslot.h" #include "xmlconfigreader.h" #include "xmlconfigwriter.h" class JoyTabWidgetHelper : public QObject { Q_OBJECT public: explicit JoyTabWidgetHelper(InputDevice *device, QObject *parent = 0); ~JoyTabWidgetHelper(); bool hasReader(); XMLConfigReader* getReader(); bool hasWriter(); XMLConfigWriter* getWriter(); bool hasError(); QString getErrorString(); protected: InputDevice *device; XMLConfigReader *reader; XMLConfigWriter *writer; bool errorOccurred; QString lastErrorString; signals: public slots: bool readConfigFile(QString filepath); bool readConfigFileWithRevert(QString filepath); bool writeConfigFile(QString filepath); void reInitDevice(); void reInitDeviceWithRevert(); }; #endif // JOYTABWIDGETHELPER_H antimicro-2.23/src/uinputhelper.cpp000066400000000000000000000340151300750276700174560ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include "uinputhelper.h" UInputHelper* UInputHelper::_instance = 0; UInputHelper::UInputHelper(QObject *parent) : QObject(parent) { populateKnownAliases(); connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(deleteLater())); } UInputHelper::~UInputHelper() { _instance = 0; } void UInputHelper::populateKnownAliases() { if (knownAliasesX11SymVK.isEmpty()) { knownAliasesX11SymVK.insert("a", KEY_A); knownAliasesX11SymVK.insert("b", KEY_B); knownAliasesX11SymVK.insert("c", KEY_C); knownAliasesX11SymVK.insert("d", KEY_D); knownAliasesX11SymVK.insert("e", KEY_E); knownAliasesX11SymVK.insert("f", KEY_F); knownAliasesX11SymVK.insert("g", KEY_G); knownAliasesX11SymVK.insert("h", KEY_H); knownAliasesX11SymVK.insert("i", KEY_I); knownAliasesX11SymVK.insert("j", KEY_J); knownAliasesX11SymVK.insert("k", KEY_K); knownAliasesX11SymVK.insert("l", KEY_L); knownAliasesX11SymVK.insert("m", KEY_M); knownAliasesX11SymVK.insert("n", KEY_N); knownAliasesX11SymVK.insert("o", KEY_O); knownAliasesX11SymVK.insert("p", KEY_P); knownAliasesX11SymVK.insert("q", KEY_Q); knownAliasesX11SymVK.insert("r", KEY_R); knownAliasesX11SymVK.insert("s", KEY_S); knownAliasesX11SymVK.insert("t", KEY_T); knownAliasesX11SymVK.insert("u", KEY_U); knownAliasesX11SymVK.insert("v", KEY_V); knownAliasesX11SymVK.insert("w", KEY_W); knownAliasesX11SymVK.insert("x", KEY_X); knownAliasesX11SymVK.insert("y", KEY_Y); knownAliasesX11SymVK.insert("z", KEY_Z); knownAliasesX11SymVK.insert("Escape", KEY_ESC); knownAliasesX11SymVK.insert("F1", KEY_F1); knownAliasesX11SymVK.insert("F2", KEY_F2); knownAliasesX11SymVK.insert("F3", KEY_F3); knownAliasesX11SymVK.insert("F4", KEY_F4); knownAliasesX11SymVK.insert("F5", KEY_F5); knownAliasesX11SymVK.insert("F6", KEY_F6); knownAliasesX11SymVK.insert("F7", KEY_F7); knownAliasesX11SymVK.insert("F8", KEY_F8); knownAliasesX11SymVK.insert("F9", KEY_F9); knownAliasesX11SymVK.insert("F10", KEY_F10); knownAliasesX11SymVK.insert("F11", KEY_F11); knownAliasesX11SymVK.insert("F12", KEY_F12); knownAliasesX11SymVK.insert("grave", KEY_GRAVE); knownAliasesX11SymVK.insert("1", KEY_1); knownAliasesX11SymVK.insert("2", KEY_2); knownAliasesX11SymVK.insert("3", KEY_3); knownAliasesX11SymVK.insert("4", KEY_4); knownAliasesX11SymVK.insert("5", KEY_5); knownAliasesX11SymVK.insert("6", KEY_6); knownAliasesX11SymVK.insert("7", KEY_7); knownAliasesX11SymVK.insert("8", KEY_8); knownAliasesX11SymVK.insert("9", KEY_9); knownAliasesX11SymVK.insert("0", KEY_0); knownAliasesX11SymVK.insert("minus", KEY_MINUS); knownAliasesX11SymVK.insert("equal", KEY_EQUAL); knownAliasesX11SymVK.insert("BackSpace", KEY_BACKSPACE); knownAliasesX11SymVK.insert("Tab", KEY_TAB); knownAliasesX11SymVK.insert("bracketleft", KEY_LEFTBRACE); knownAliasesX11SymVK.insert("bracketright", KEY_RIGHTBRACE); knownAliasesX11SymVK.insert("backslash", KEY_BACKSLASH); knownAliasesX11SymVK.insert("Caps_Lock", KEY_CAPSLOCK); knownAliasesX11SymVK.insert("semicolon", KEY_SEMICOLON); knownAliasesX11SymVK.insert("apostrophe", KEY_APOSTROPHE); knownAliasesX11SymVK.insert("Return", KEY_ENTER); knownAliasesX11SymVK.insert("Shift_L", KEY_LEFTSHIFT); knownAliasesX11SymVK.insert("comma", KEY_COMMA); knownAliasesX11SymVK.insert("period", KEY_DOT); knownAliasesX11SymVK.insert("slash", KEY_SLASH); knownAliasesX11SymVK.insert("Control_L", KEY_LEFTCTRL); knownAliasesX11SymVK.insert("Super_L", KEY_MENU); knownAliasesX11SymVK.insert("Alt_L", KEY_LEFTALT); knownAliasesX11SymVK.insert("space", KEY_SPACE); knownAliasesX11SymVK.insert("Alt_R", KEY_RIGHTALT); knownAliasesX11SymVK.insert("Menu", KEY_COMPOSE); knownAliasesX11SymVK.insert("Control_R", KEY_RIGHTCTRL); knownAliasesX11SymVK.insert("Shift_R", KEY_RIGHTSHIFT); knownAliasesX11SymVK.insert("Up", KEY_UP); knownAliasesX11SymVK.insert("Left", KEY_LEFT); knownAliasesX11SymVK.insert("Down", KEY_DOWN); knownAliasesX11SymVK.insert("Right", KEY_RIGHT); knownAliasesX11SymVK.insert("Print", KEY_PRINT); knownAliasesX11SymVK.insert("Insert", KEY_INSERT); knownAliasesX11SymVK.insert("Delete", KEY_DELETE); knownAliasesX11SymVK.insert("Home", KEY_HOME); knownAliasesX11SymVK.insert("End", KEY_END); knownAliasesX11SymVK.insert("Prior", KEY_PAGEUP); knownAliasesX11SymVK.insert("Next", KEY_PAGEDOWN); knownAliasesX11SymVK.insert("Num_Lock", KEY_NUMLOCK); knownAliasesX11SymVK.insert("KP_Divide", KEY_KPSLASH); knownAliasesX11SymVK.insert("KP_Multiply", KEY_KPASTERISK); knownAliasesX11SymVK.insert("KP_Subtract", KEY_KPMINUS); knownAliasesX11SymVK.insert("KP_Add", KEY_KPPLUS); knownAliasesX11SymVK.insert("KP_Enter", KEY_KPENTER); knownAliasesX11SymVK.insert("KP_1", KEY_KP1); knownAliasesX11SymVK.insert("KP_2", KEY_KP2); knownAliasesX11SymVK.insert("KP_3", KEY_KP3); knownAliasesX11SymVK.insert("KP_4", KEY_KP4); knownAliasesX11SymVK.insert("KP_5", KEY_KP5); knownAliasesX11SymVK.insert("KP_6", KEY_KP6); knownAliasesX11SymVK.insert("KP_7", KEY_KP7); knownAliasesX11SymVK.insert("KP_8", KEY_KP8); knownAliasesX11SymVK.insert("KP_9", KEY_KP9); knownAliasesX11SymVK.insert("KP_0", KEY_KP0); knownAliasesX11SymVK.insert("KP_Decimal", KEY_KPDOT); knownAliasesX11SymVK.insert("Scroll_Lock", KEY_SCROLLLOCK); knownAliasesX11SymVK.insert("Pause", KEY_PAUSE); knownAliasesX11SymVK.insert("Multi_key", KEY_RIGHTALT); } if (knownAliasesVKStrings.isEmpty()) { knownAliasesVKStrings.insert(KEY_A, tr("a")); knownAliasesVKStrings.insert(KEY_B, tr("b")); knownAliasesVKStrings.insert(KEY_C, tr("c")); knownAliasesVKStrings.insert(KEY_D, tr("d")); knownAliasesVKStrings.insert(KEY_E, tr("e")); knownAliasesVKStrings.insert(KEY_F, tr("f")); knownAliasesVKStrings.insert(KEY_G, tr("g")); knownAliasesVKStrings.insert(KEY_H, tr("h")); knownAliasesVKStrings.insert(KEY_I, tr("i")); knownAliasesVKStrings.insert(KEY_J, tr("j")); knownAliasesVKStrings.insert(KEY_K, tr("k")); knownAliasesVKStrings.insert(KEY_L, tr("l")); knownAliasesVKStrings.insert(KEY_M, tr("m")); knownAliasesVKStrings.insert(KEY_N, tr("n")); knownAliasesVKStrings.insert(KEY_O, tr("o")); knownAliasesVKStrings.insert(KEY_P, tr("p")); knownAliasesVKStrings.insert(KEY_Q, tr("q")); knownAliasesVKStrings.insert(KEY_R, tr("r")); knownAliasesVKStrings.insert(KEY_S, tr("s")); knownAliasesVKStrings.insert(KEY_T, tr("t")); knownAliasesVKStrings.insert(KEY_U, tr("u")); knownAliasesVKStrings.insert(KEY_V, tr("v")); knownAliasesVKStrings.insert(KEY_W, tr("w")); knownAliasesVKStrings.insert(KEY_X, tr("x")); knownAliasesVKStrings.insert(KEY_Y, tr("y")); knownAliasesVKStrings.insert(KEY_Z, tr("z")); knownAliasesVKStrings.insert(KEY_ESC, tr("Esc")); knownAliasesVKStrings.insert(KEY_F1, tr("F1")); knownAliasesVKStrings.insert(KEY_F2, tr("F2")); knownAliasesVKStrings.insert(KEY_F3, tr("F3")); knownAliasesVKStrings.insert(KEY_F4, tr("F4")); knownAliasesVKStrings.insert(KEY_F5, tr("F5")); knownAliasesVKStrings.insert(KEY_F6, tr("F6")); knownAliasesVKStrings.insert(KEY_F7, tr("F7")); knownAliasesVKStrings.insert(KEY_F8, tr("F8")); knownAliasesVKStrings.insert(KEY_F9, tr("F9")); knownAliasesVKStrings.insert(KEY_F10, tr("F10")); knownAliasesVKStrings.insert(KEY_F11, tr("F11")); knownAliasesVKStrings.insert(KEY_F12, tr("F12")); knownAliasesVKStrings.insert(KEY_GRAVE, tr("`")); knownAliasesVKStrings.insert(KEY_1, tr("1")); knownAliasesVKStrings.insert(KEY_2, tr("2")); knownAliasesVKStrings.insert(KEY_3, tr("3")); knownAliasesVKStrings.insert(KEY_4, tr("4")); knownAliasesVKStrings.insert(KEY_5, tr("5")); knownAliasesVKStrings.insert(KEY_6, tr("6")); knownAliasesVKStrings.insert(KEY_7, tr("7")); knownAliasesVKStrings.insert(KEY_8, tr("8")); knownAliasesVKStrings.insert(KEY_9, tr("9")); knownAliasesVKStrings.insert(KEY_0, tr("0")); knownAliasesVKStrings.insert(KEY_MINUS, tr("-")); knownAliasesVKStrings.insert(KEY_EQUAL, tr("=")); knownAliasesVKStrings.insert(KEY_BACKSPACE, tr("BackSpace")); knownAliasesVKStrings.insert(KEY_TAB, tr("Tab")); knownAliasesVKStrings.insert(KEY_LEFTBRACE, tr("[")); knownAliasesVKStrings.insert(KEY_RIGHTBRACE, tr("]")); knownAliasesVKStrings.insert(KEY_BACKSLASH, tr("\\")); knownAliasesVKStrings.insert(KEY_CAPSLOCK, tr("CapsLock")); knownAliasesVKStrings.insert(KEY_SEMICOLON, tr(";")); knownAliasesVKStrings.insert(KEY_APOSTROPHE, tr("'")); knownAliasesVKStrings.insert(KEY_ENTER, tr("Enter")); knownAliasesVKStrings.insert(KEY_LEFTSHIFT, tr("Shift_L")); knownAliasesVKStrings.insert(KEY_COMMA, tr(",")); knownAliasesVKStrings.insert(KEY_DOT, tr(".")); knownAliasesVKStrings.insert(KEY_SLASH, tr("/")); knownAliasesVKStrings.insert(KEY_LEFTCTRL, tr("Ctrl_L")); knownAliasesVKStrings.insert(KEY_MENU, tr("Super_L")); knownAliasesVKStrings.insert(KEY_LEFTALT, tr("Alt_L")); knownAliasesVKStrings.insert(KEY_SPACE, tr("Space")); knownAliasesVKStrings.insert(KEY_RIGHTALT, tr("Alt_R")); knownAliasesVKStrings.insert(KEY_COMPOSE, tr("Menu")); knownAliasesVKStrings.insert(KEY_RIGHTCTRL, tr("Ctrl_R")); knownAliasesVKStrings.insert(KEY_RIGHTSHIFT, tr("Shift_R")); knownAliasesVKStrings.insert(KEY_UP, tr("Up")); knownAliasesVKStrings.insert(KEY_LEFT, tr("Left")); knownAliasesVKStrings.insert(KEY_DOWN, tr("Down")); knownAliasesVKStrings.insert(KEY_RIGHT, tr("Right")); knownAliasesVKStrings.insert(KEY_PRINT, tr("PrtSc")); knownAliasesVKStrings.insert(KEY_INSERT, tr("Ins")); knownAliasesVKStrings.insert(KEY_DELETE, tr("Del")); knownAliasesVKStrings.insert(KEY_HOME, tr("Home")); knownAliasesVKStrings.insert(KEY_END, tr("End")); knownAliasesVKStrings.insert(KEY_PAGEUP, tr("PgUp")); knownAliasesVKStrings.insert(KEY_PAGEDOWN, tr("PgDn")); knownAliasesVKStrings.insert(KEY_NUMLOCK, tr("NumLock")); knownAliasesVKStrings.insert(KEY_KPSLASH, tr("/")); knownAliasesVKStrings.insert(KEY_KPASTERISK, tr("*")); knownAliasesVKStrings.insert(KEY_KPMINUS, tr("-")); knownAliasesVKStrings.insert(KEY_KPPLUS, tr("+")); knownAliasesVKStrings.insert(KEY_KPENTER, tr("KP_Enter")); knownAliasesVKStrings.insert(KEY_KP1, tr("KP_1")); knownAliasesVKStrings.insert(KEY_KP2, tr("KP_2")); knownAliasesVKStrings.insert(KEY_KP3, tr("KP_3")); knownAliasesVKStrings.insert(KEY_KP4, tr("KP_4")); knownAliasesVKStrings.insert(KEY_KP5, tr("KP_5")); knownAliasesVKStrings.insert(KEY_KP6, tr("KP_6")); knownAliasesVKStrings.insert(KEY_KP7, tr("KP_7")); knownAliasesVKStrings.insert(KEY_KP8, tr("KP_8")); knownAliasesVKStrings.insert(KEY_KP9, tr("KP_9")); knownAliasesVKStrings.insert(KEY_KP0, tr("KP_0")); knownAliasesVKStrings.insert(KEY_SCROLLLOCK, tr("SCLK")); knownAliasesVKStrings.insert(KEY_PAUSE, tr("Pause")); knownAliasesVKStrings.insert(KEY_KPDOT, tr(".")); knownAliasesVKStrings.insert(KEY_LEFTMETA, tr("Super_L")); knownAliasesVKStrings.insert(KEY_RIGHTMETA, tr("Super_R")); knownAliasesVKStrings.insert(KEY_MUTE, tr("Mute")); knownAliasesVKStrings.insert(KEY_VOLUMEDOWN, tr("VolDn")); knownAliasesVKStrings.insert(KEY_VOLUMEUP, tr("VolUp")); knownAliasesVKStrings.insert(KEY_PLAYPAUSE, tr("Play")); knownAliasesVKStrings.insert(KEY_STOPCD, tr("Stop")); knownAliasesVKStrings.insert(KEY_PREVIOUSSONG, tr("Prev")); knownAliasesVKStrings.insert(KEY_NEXTSONG, tr("Next")); } } UInputHelper* UInputHelper::getInstance() { if (!_instance) { _instance = new UInputHelper(); } return _instance; } void UInputHelper::deleteInstance() { if (_instance) { delete _instance; _instance = 0; } } QString UInputHelper::getDisplayString(unsigned int virtualkey) { QString temp; if (virtualkey <= 0) { temp = tr("[NO KEY]"); } else if (knownAliasesVKStrings.contains(virtualkey)) { temp = knownAliasesVKStrings.value(virtualkey); } return temp; } unsigned int UInputHelper::getVirtualKey(QString codestring) { int temp = 0; if (knownAliasesX11SymVK.contains(codestring)) { temp = knownAliasesX11SymVK.value(codestring); } return temp; } antimicro-2.23/src/uinputhelper.h000066400000000000000000000026031300750276700171210ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UINPUTHELPER_H #define UINPUTHELPER_H #include #include #include class UInputHelper : public QObject { Q_OBJECT public: static UInputHelper* getInstance(); void deleteInstance(); QString getDisplayString(unsigned int virtualkey); unsigned int getVirtualKey(QString codestring); protected: explicit UInputHelper(QObject *parent = 0); ~UInputHelper(); void populateKnownAliases(); static UInputHelper *_instance; QHash knownAliasesX11SymVK; QHash knownAliasesVKStrings; signals: public slots: }; #endif // UINPUTHELPER_H antimicro-2.23/src/unixcapturewindowutility.cpp000066400000000000000000000072771300750276700221670ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include // for XGrabPointer #include "x11extras.h" #include "qtx11keymapper.h" #include "unixcapturewindowutility.h" UnixCaptureWindowUtility::UnixCaptureWindowUtility(QObject *parent) : QObject(parent) { targetPath = ""; failed = false; targetWindow = None; } /** * @brief Attempt to capture window selected with the mouse */ void UnixCaptureWindowUtility::attemptWindowCapture() { // Only create instance when needed. static QtX11KeyMapper x11KeyMapper; targetPath = ""; targetWindow = None; failed = false; bool escaped = false; Cursor cursor; Window target_window = None; int status = 0; Display *display = 0; QString potentialXDisplayString = X11Extras::getInstance()->getXDisplayString(); if (!potentialXDisplayString.isEmpty()) { QByteArray tempByteArray = potentialXDisplayString.toLocal8Bit(); display = XOpenDisplay(tempByteArray.constData()); } else { display = XOpenDisplay(NULL); } Window rootWin = XDefaultRootWindow(display); cursor = XCreateFontCursor(display, XC_crosshair); status = XGrabPointer(display, rootWin, False, ButtonPressMask, GrabModeSync, GrabModeAsync, None, cursor, CurrentTime); if (status == Success) { XGrabKey(display, XKeysymToKeycode(display, x11KeyMapper.returnVirtualKey(Qt::Key_Escape)), 0, rootWin, true, GrabModeAsync, GrabModeAsync); XEvent event; XAllowEvents(display, SyncPointer, CurrentTime); XWindowEvent(display, rootWin, ButtonPressMask|KeyPressMask, &event); switch (event.type) { case (ButtonPress): target_window = event.xbutton.subwindow; if (target_window == None) { target_window = event.xbutton.window; } //qDebug() << QString::number(target_window, 16); break; case (KeyPress): { escaped = true; break; } } XUngrabKey(display, XKeysymToKeycode(display, x11KeyMapper.returnVirtualKey(Qt::Key_Escape)), 0, rootWin); XUngrabPointer(display, CurrentTime); XFlush(display); } if (target_window != None) { targetWindow = target_window; } else if (!escaped) { failed = true; } XCloseDisplay(display); emit captureFinished(); } /** * @brief Get the saved path for a window * @return Program path */ QString UnixCaptureWindowUtility::getTargetPath() { return targetPath; } /** * @brief Check if attemptWindowCapture failed to obtain an application * @return Error status */ bool UnixCaptureWindowUtility::hasFailed() { return failed; } unsigned long UnixCaptureWindowUtility::getTargetWindow() { return targetWindow; } antimicro-2.23/src/unixcapturewindowutility.h000066400000000000000000000023761300750276700216270ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UNIXCAPTUREWINDOWUTILITY_H #define UNIXCAPTUREWINDOWUTILITY_H #include class UnixCaptureWindowUtility : public QObject { Q_OBJECT public: explicit UnixCaptureWindowUtility(QObject *parent = 0); QString getTargetPath(); bool hasFailed(); unsigned long getTargetWindow(); protected: QString targetPath; bool failed; unsigned long targetWindow; signals: void captureFinished(); public slots: void attemptWindowCapture(); }; #endif // UNIXCAPTUREWINDOWUTILITY_H antimicro-2.23/src/unixwindowinfodialog.cpp000066400000000000000000000070241300750276700212010ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "unixwindowinfodialog.h" #include "ui_unixwindowinfodialog.h" #include "x11info.h" UnixWindowInfoDialog::UnixWindowInfoDialog(unsigned long window, QWidget *parent) : QDialog(parent), ui(new Ui::UnixWindowInfoDialog) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); X11Info *info = X11Info::getInstance(); bool setRadioDefault = false; winClass = info->getWindowClass(window); ui->winClassLabel->setText(winClass); if (winClass.isEmpty()) { ui->winClassCheckBox->setEnabled(false); ui->winClassCheckBox->setChecked(false); } else { ui->winClassCheckBox->setChecked(true); setRadioDefault = true; } winName = info->getWindowTitle(window); ui->winTitleLabel->setText(winName); if (winName.isEmpty()) { ui->winTitleCheckBox->setEnabled(false); ui->winTitleCheckBox->setChecked(false); } else if (!setRadioDefault) { ui->winTitleCheckBox->setChecked(true); setRadioDefault = true; } ui->winPathLabel->clear(); int pid = info->getApplicationPid(window); if (pid > 0) { QString exepath = X11Info::getInstance()->getApplicationLocation(pid); if (!exepath.isEmpty()) { ui->winPathLabel->setText(exepath); winPath = exepath; if (!setRadioDefault) { ui->winTitleCheckBox->setChecked(true); setRadioDefault = true; } } else { ui->winPathCheckBox->setEnabled(false); ui->winPathCheckBox->setChecked(false); } } else { ui->winPathCheckBox->setEnabled(false); ui->winPathCheckBox->setChecked(false); } if (winClass.isEmpty() && winName.isEmpty() && winPath.isEmpty()) { QPushButton *button = ui->buttonBox->button(QDialogButtonBox::Ok); button->setEnabled(false); } connect(this, SIGNAL(accepted()), this, SLOT(populateOption())); } void UnixWindowInfoDialog::populateOption() { if (ui->winClassCheckBox->isChecked()) { selectedMatch = selectedMatch | WindowClass; } if (ui->winTitleCheckBox->isChecked()) { selectedMatch = selectedMatch | WindowName; } if (ui->winPathCheckBox->isChecked()) { selectedMatch = selectedMatch | WindowPath; } } UnixWindowInfoDialog::DialogWindowOption UnixWindowInfoDialog::getSelectedOptions() { return selectedMatch; } QString UnixWindowInfoDialog::getWindowClass() { return winClass; } QString UnixWindowInfoDialog::getWindowName() { return winName; } QString UnixWindowInfoDialog::getWindowPath() { return winPath; } UnixWindowInfoDialog::~UnixWindowInfoDialog() { delete ui; } antimicro-2.23/src/unixwindowinfodialog.h000066400000000000000000000031111300750276700206370ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UNIXWINDOWINFODIALOG_H #define UNIXWINDOWINFODIALOG_H #include #include namespace Ui { class UnixWindowInfoDialog; } class UnixWindowInfoDialog : public QDialog { Q_OBJECT public: explicit UnixWindowInfoDialog(unsigned long window, QWidget *parent = 0); ~UnixWindowInfoDialog(); enum { WindowClass = (1 << 0), WindowName = (1 << 1), WindowPath = (1 << 2) }; typedef unsigned int DialogWindowOption; QString getWindowClass(); QString getWindowName(); QString getWindowPath(); DialogWindowOption getSelectedOptions(); private: Ui::UnixWindowInfoDialog *ui; protected: DialogWindowOption selectedMatch; QString winClass; QString winName; QString winPath; private slots: void populateOption(); }; #endif // UNIXWINDOWINFODIALOG_H antimicro-2.23/src/unixwindowinfodialog.ui000066400000000000000000000123141300750276700210320ustar00rootroot00000000000000 UnixWindowInfoDialog 0 0 533 333 Captured Window Properties 20 50 false Information About Window true 20 Class: true TextLabel Title: true TextLabel Path: true TextLabel Match By Properties true false false Class Title Path Qt::Vertical 20 40 Qt::Horizontal Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok buttonBox accepted() UnixWindowInfoDialog accept() 248 254 157 274 buttonBox rejected() UnixWindowInfoDialog reject() 316 260 286 274 antimicro-2.23/src/vdpad.cpp000066400000000000000000000147351300750276700160370ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "vdpad.h" const QString VDPad::xmlName = "vdpad"; VDPad::VDPad(int index, int originset, SetJoystick *parentSet, QObject *parent) : JoyDPad(index, originset, parentSet, parent) { this->upButton = 0; this->downButton = 0; this->leftButton = 0; this->rightButton = 0; pendingVDPadEvent = false; } VDPad::VDPad(JoyButton *upButton, JoyButton *downButton, JoyButton *leftButton, JoyButton *rightButton, int index, int originset, SetJoystick *parentSet, QObject *parent) : JoyDPad(index, originset, parentSet, parent) { this->upButton = upButton; upButton->setVDPad(this); this->downButton = downButton; downButton->setVDPad(this); this->leftButton = leftButton; leftButton->setVDPad(this); this->rightButton = rightButton; rightButton->setVDPad(this); pendingVDPadEvent = false; } VDPad::~VDPad() { if (upButton) { upButton->removeVDPad(); upButton = 0; } if (downButton) { downButton->removeVDPad(); downButton = 0; } if (leftButton) { leftButton->removeVDPad(); leftButton = 0; } if (rightButton) { rightButton->removeVDPad(); rightButton = 0; } } QString VDPad::getXmlName() { return this->xmlName; } QString VDPad::getName(bool forceFullFormat, bool displayName) { QString label; if (!dpadName.isEmpty() && displayName) { if (forceFullFormat) { label.append(tr("VDPad")).append(" "); } label.append(dpadName); } else if (!defaultDPadName.isEmpty()) { if (forceFullFormat) { label.append(tr("VDPad")).append(" "); } label.append(defaultDPadName); } else { label.append(tr("VDPad")).append(" "); label.append(QString::number(getRealJoyNumber())); } return label; } void VDPad::joyEvent(bool pressed, bool ignoresets) { Q_UNUSED(pressed); int tempDirection = static_cast(JoyDPadButton::DpadCentered); /* * Check which buttons are currently active */ if (upButton && upButton->getButtonState()) { tempDirection |= JoyDPadButton::DpadUp; } if (downButton && downButton->getButtonState()) { tempDirection |= JoyDPadButton::DpadDown; } if (leftButton && leftButton->getButtonState()) { tempDirection |= JoyDPadButton::DpadLeft; } if (rightButton && rightButton->getButtonState()) { tempDirection |= JoyDPadButton::DpadRight; } JoyDPad::joyEvent(tempDirection, ignoresets); pendingVDPadEvent = false; } void VDPad::addVButton(JoyDPadButton::JoyDPadDirections direction, JoyButton *button) { if (direction == JoyDPadButton::DpadUp) { if (upButton) { upButton->removeVDPad(); } upButton = button; upButton->setVDPad(this); } else if (direction == JoyDPadButton::DpadDown) { if (downButton) { downButton->removeVDPad(); } downButton = button; downButton->setVDPad(this); } else if (direction == JoyDPadButton::DpadLeft) { if (leftButton) { leftButton->removeVDPad(); } leftButton = button; leftButton->setVDPad(this); } else if (direction == JoyDPadButton::DpadRight) { if (rightButton) { rightButton->removeVDPad(); } rightButton = button; rightButton->setVDPad(this); } } void VDPad::removeVButton(JoyDPadButton::JoyDPadDirections direction) { if (direction == JoyDPadButton::DpadUp && upButton) { upButton->removeVDPad(); upButton = 0; } else if (direction == JoyDPadButton::DpadDown && downButton) { downButton->removeVDPad(); downButton = 0; } else if (direction == JoyDPadButton::DpadLeft && leftButton) { leftButton->removeVDPad(); leftButton = 0; } else if (direction == JoyDPadButton::DpadRight && rightButton) { rightButton->removeVDPad(); rightButton = 0; } } void VDPad::removeVButton(JoyButton *button) { if (button && button == upButton) { upButton->removeVDPad(); upButton = 0; } else if (button && button == downButton) { downButton->removeVDPad(); downButton = 0; } else if (button && button == leftButton) { leftButton->removeVDPad(); leftButton = 0; } else if (button && button == rightButton) { rightButton->removeVDPad(); rightButton = 0; } } bool VDPad::isEmpty() { bool empty = true; if (upButton || downButton || leftButton || rightButton) { empty = false; } return empty; } JoyButton* VDPad::getVButton(JoyDPadButton::JoyDPadDirections direction) { JoyButton *button = 0; if (direction == JoyDPadButton::DpadUp) { button = upButton; } else if (direction == JoyDPadButton::DpadDown) { button = downButton; } else if (direction == JoyDPadButton::DpadLeft) { button = leftButton; } else if (direction == JoyDPadButton::DpadRight) { button = rightButton; } return button; } bool VDPad::hasPendingEvent() { return pendingVDPadEvent; } void VDPad::queueJoyEvent(bool ignoresets) { Q_UNUSED(ignoresets); pendingVDPadEvent = true; } void VDPad::activatePendingEvent() { if (pendingVDPadEvent) { // Always use true. The proper direction value will be determined // in the joyEvent method. joyEvent(true); pendingVDPadEvent = false; } } void VDPad::clearPendingEvent() { pendingVDPadEvent = false; } antimicro-2.23/src/vdpad.h000066400000000000000000000037421300750276700155000ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef VDPAD_H #define VDPAD_H #include "joydpad.h" #include "joybutton.h" class VDPad : public JoyDPad { Q_OBJECT public: explicit VDPad(int index, int originset, SetJoystick *parentSet, QObject *parent = 0); explicit VDPad(JoyButton *upButton, JoyButton *downButton, JoyButton *leftButton, JoyButton *rightButton, int index, int originset, SetJoystick *parentSet, QObject *parent = 0); ~VDPad(); void joyEvent(bool pressed, bool ignoresets=false); void addVButton(JoyDPadButton::JoyDPadDirections direction, JoyButton *button); void removeVButton(JoyDPadButton::JoyDPadDirections direction); void removeVButton(JoyButton *button); JoyButton* getVButton(JoyDPadButton::JoyDPadDirections direction); bool isEmpty(); virtual QString getName(bool forceFullFormat=false, bool displayName=false); virtual QString getXmlName(); void queueJoyEvent(bool ignoresets=false); bool hasPendingEvent(); void clearPendingEvent(); static const QString xmlName; protected: JoyButton *upButton; JoyButton *downButton; JoyButton *leftButton; JoyButton *rightButton; bool pendingVDPadEvent; signals: public slots: void activatePendingEvent(); }; #endif // VDPAD_H antimicro-2.23/src/winappprofiletimerdialog.cpp000066400000000000000000000013061300750276700220270ustar00rootroot00000000000000#include "winappprofiletimerdialog.h" #include "ui_winappprofiletimerdialog.h" WinAppProfileTimerDialog::WinAppProfileTimerDialog(QWidget *parent) : QDialog(parent), ui(new Ui::WinAppProfileTimerDialog) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); connect(&appTimer, SIGNAL(timeout()), this, SLOT(accept())); connect(ui->capturePushButton, SIGNAL(clicked()), this, SLOT(startTimer())); connect(ui->cancelPushButton, SIGNAL(clicked()), this, SLOT(close())); } WinAppProfileTimerDialog::~WinAppProfileTimerDialog() { delete ui; } void WinAppProfileTimerDialog::startTimer() { appTimer.start(ui->intervalSpinBox->value() * 1000); this->setEnabled(false); } antimicro-2.23/src/winappprofiletimerdialog.h000066400000000000000000000007721300750276700215020ustar00rootroot00000000000000#ifndef WINAPPPROFILETIMERDIALOG_H #define WINAPPPROFILETIMERDIALOG_H #include #include namespace Ui { class WinAppProfileTimerDialog; } class WinAppProfileTimerDialog : public QDialog { Q_OBJECT public: explicit WinAppProfileTimerDialog(QWidget *parent = 0); ~WinAppProfileTimerDialog(); protected: QTimer appTimer; //slots: // void private: Ui::WinAppProfileTimerDialog *ui; private slots: void startTimer(); }; #endif // WINAPPPROFILETIMERDIALOG_H antimicro-2.23/src/winappprofiletimerdialog.ui000066400000000000000000000047651300750276700216760ustar00rootroot00000000000000 WinAppProfileTimerDialog 0 0 420 178 Capture Application true After pressing the "Capture Application" button, please select the application window that you want to have a profile associated with. The active application will be captured after the selected number of seconds. false true Timer: 1 60 Seconds Qt::Horizontal 40 20 Capture Application Cancel antimicro-2.23/src/winextras.cpp000066400000000000000000000407461300750276700167660ustar00rootroot00000000000000#define _WIN32_WINNT 0x0600 #include #include //#include #include #include #include #include #include "winextras.h" #include typedef DWORD(WINAPI *MYPROC)(HANDLE, DWORD, LPTSTR, PDWORD); // Check if QueryFullProcessImageNameW function exists in kernel32.dll. // Function does not exist in Windows XP. static MYPROC pQueryFullProcessImageNameW = (MYPROC) GetProcAddress( GetModuleHandle(TEXT("kernel32.dll")), "QueryFullProcessImageNameW"); /*static bool isWindowsVistaOrHigher() { OSVERSIONINFO osvi; memset(&osvi, 0, sizeof(osvi)); osvi.dwOSVersionInfoSize = sizeof(osvi); GetVersionEx(&osvi); return (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion >= 6); } */ const unsigned int WinExtras::EXTENDED_FLAG = 0x100; int WinExtras::originalMouseAccel = 0; static const QString ROOTASSOCIATIONKEY("HKEY_CURRENT_USER\\Software\\Classes"); static const QString FILEASSOCIATIONKEY(QString("%1\\%2").arg(ROOTASSOCIATIONKEY).arg(".amgp")); static const QString PROGRAMASSOCIATIONKEY(QString("%1\\%2").arg(ROOTASSOCIATIONKEY).arg("AntiMicro.amgp")); WinExtras WinExtras::_instance; WinExtras::WinExtras(QObject *parent) : QObject(parent) { populateKnownAliases(); } QString WinExtras::getDisplayString(unsigned int virtualkey) { QString temp; if (virtualkey <= 0) { temp = tr("[NO KEY]"); } else if (_instance.knownAliasesVKStrings.contains(virtualkey)) { temp = _instance.knownAliasesVKStrings.value(virtualkey); } return temp; } unsigned int WinExtras::getVirtualKey(QString codestring) { int temp = 0; if (_instance.knownAliasesX11SymVK.contains(codestring)) { temp = _instance.knownAliasesX11SymVK.value(codestring); } return temp; } void WinExtras::populateKnownAliases() { // These aliases are needed for xstrings that would // return empty space characters from XLookupString if (knownAliasesX11SymVK.isEmpty()) { knownAliasesX11SymVK.insert("Escape", VK_ESCAPE); knownAliasesX11SymVK.insert("Tab", VK_TAB); knownAliasesX11SymVK.insert("space", VK_SPACE); knownAliasesX11SymVK.insert("Delete", VK_DELETE); knownAliasesX11SymVK.insert("Return", VK_RETURN); knownAliasesX11SymVK.insert("KP_Enter", VK_RETURN); knownAliasesX11SymVK.insert("BackSpace", VK_BACK); knownAliasesX11SymVK.insert("F1", VK_F1); knownAliasesX11SymVK.insert("F2", VK_F2); knownAliasesX11SymVK.insert("F3", VK_F3); knownAliasesX11SymVK.insert("F4", VK_F4); knownAliasesX11SymVK.insert("F5", VK_F5); knownAliasesX11SymVK.insert("F6", VK_F6); knownAliasesX11SymVK.insert("F7", VK_F7); knownAliasesX11SymVK.insert("F8", VK_F8); knownAliasesX11SymVK.insert("F9", VK_F9); knownAliasesX11SymVK.insert("F10", VK_F10); knownAliasesX11SymVK.insert("F11", VK_F11); knownAliasesX11SymVK.insert("F12", VK_F12); knownAliasesX11SymVK.insert("Shift_L", VK_LSHIFT); knownAliasesX11SymVK.insert("Shift_R", VK_RSHIFT); knownAliasesX11SymVK.insert("Insert", VK_INSERT); knownAliasesX11SymVK.insert("Pause", VK_PAUSE); knownAliasesX11SymVK.insert("grave", VK_OEM_3); knownAliasesX11SymVK.insert("minus", VK_OEM_MINUS); knownAliasesX11SymVK.insert("equal", VK_OEM_PLUS); knownAliasesX11SymVK.insert("Caps_Lock", VK_CAPITAL); knownAliasesX11SymVK.insert("Control_L", VK_CONTROL); knownAliasesX11SymVK.insert("Control_R", VK_RCONTROL); knownAliasesX11SymVK.insert("Alt_L", VK_MENU); knownAliasesX11SymVK.insert("Alt_R", VK_RMENU); knownAliasesX11SymVK.insert("Super_L", VK_LWIN); knownAliasesX11SymVK.insert("Menu", VK_APPS); knownAliasesX11SymVK.insert("Prior", VK_PRIOR); knownAliasesX11SymVK.insert("Next", VK_NEXT); knownAliasesX11SymVK.insert("Home", VK_HOME); knownAliasesX11SymVK.insert("End", VK_END); knownAliasesX11SymVK.insert("Up", VK_UP); knownAliasesX11SymVK.insert("Down", VK_DOWN); knownAliasesX11SymVK.insert("Left", VK_LEFT); knownAliasesX11SymVK.insert("Right", VK_RIGHT); knownAliasesX11SymVK.insert("bracketleft", VK_OEM_4); knownAliasesX11SymVK.insert("bracketright", VK_OEM_6); knownAliasesX11SymVK.insert("backslash", VK_OEM_5); knownAliasesX11SymVK.insert("slash", VK_OEM_2); knownAliasesX11SymVK.insert("semicolon", VK_OEM_1); knownAliasesX11SymVK.insert("apostrophe", VK_OEM_7); knownAliasesX11SymVK.insert("comma", VK_OEM_COMMA); knownAliasesX11SymVK.insert("period", VK_OEM_PERIOD); knownAliasesX11SymVK.insert("KP_0", VK_NUMPAD0); knownAliasesX11SymVK.insert("KP_1", VK_NUMPAD1); knownAliasesX11SymVK.insert("KP_2", VK_NUMPAD2); knownAliasesX11SymVK.insert("KP_3", VK_NUMPAD3); knownAliasesX11SymVK.insert("KP_4", VK_NUMPAD4); knownAliasesX11SymVK.insert("KP_5", VK_NUMPAD5); knownAliasesX11SymVK.insert("KP_6", VK_NUMPAD6); knownAliasesX11SymVK.insert("KP_7", VK_NUMPAD7); knownAliasesX11SymVK.insert("KP_8", VK_NUMPAD8); knownAliasesX11SymVK.insert("KP_9", VK_NUMPAD9); knownAliasesX11SymVK.insert("Num_Lock", VK_NUMLOCK); knownAliasesX11SymVK.insert("KP_Divide", VK_DIVIDE); knownAliasesX11SymVK.insert("KP_Multiply", VK_MULTIPLY); knownAliasesX11SymVK.insert("KP_Subtract", VK_SUBTRACT); knownAliasesX11SymVK.insert("KP_Add", VK_ADD); knownAliasesX11SymVK.insert("KP_Decimal", VK_DECIMAL); knownAliasesX11SymVK.insert("Scroll_Lock", VK_SCROLL); knownAliasesX11SymVK.insert("Print", VK_SNAPSHOT); knownAliasesX11SymVK.insert("Multi_key", VK_RMENU); } if (knownAliasesVKStrings.isEmpty()) { knownAliasesVKStrings.insert(VK_LWIN, QObject::tr("Super")); knownAliasesVKStrings.insert(VK_APPS, QObject::tr("Menu")); knownAliasesVKStrings.insert(VK_VOLUME_MUTE, QObject::tr("Mute")); knownAliasesVKStrings.insert(VK_VOLUME_UP, QObject::tr("Vol+")); knownAliasesVKStrings.insert(VK_VOLUME_DOWN, QObject::tr("Vol-")); knownAliasesVKStrings.insert(VK_MEDIA_PLAY_PAUSE, QObject::tr("Play/Pause")); knownAliasesVKStrings.insert(VK_PLAY, QObject::tr("Play")); knownAliasesVKStrings.insert(VK_PAUSE, QObject::tr("Pause")); knownAliasesVKStrings.insert(VK_MEDIA_PREV_TRACK, QObject::tr("Prev")); knownAliasesVKStrings.insert(VK_MEDIA_NEXT_TRACK, QObject::tr("Next")); knownAliasesVKStrings.insert(VK_LAUNCH_MAIL, QObject::tr("Mail")); knownAliasesVKStrings.insert(VK_HOME, QObject::tr("Home")); knownAliasesVKStrings.insert(VK_LAUNCH_MEDIA_SELECT, QObject::tr("Media")); knownAliasesVKStrings.insert(VK_BROWSER_SEARCH, QObject::tr("Search")); } } /** * @brief Obtain a more specific virtual key (unsigned int) for a key grab event. * @param Scan code obtained from a key grab event * @param Virtual key obtained from a key grab event * @return Corrected virtual key as an unsigned int */ unsigned int WinExtras::correctVirtualKey(unsigned int scancode, unsigned int virtualkey) { int mapvirtual = MapVirtualKey(scancode, MAPVK_VSC_TO_VK_EX); int extended = (scancode & EXTENDED_FLAG) != 0; int finalvirtual = 0; switch (virtualkey) { case VK_CONTROL: finalvirtual = extended ? VK_RCONTROL : VK_LCONTROL; break; case VK_SHIFT: finalvirtual = mapvirtual; break; case VK_MENU: finalvirtual = extended ? VK_RMENU : VK_LMENU; break; case 0x5E: // Ignore System Reserved VK finalvirtual = 0; break; default: finalvirtual = virtualkey; } return finalvirtual; } /** * @brief Convert a virtual key into the corresponding keyboard scan code. * @param Windows virtual key * @param Qt key alias * @return Keyboard scan code as an unsigned int */ unsigned int WinExtras::scancodeFromVirtualKey(unsigned int virtualkey, unsigned int alias) { int scancode = 0; if (virtualkey == VK_PAUSE) { // MapVirtualKey does not work with VK_PAUSE scancode = 0x45; } else { scancode = MapVirtualKey(virtualkey, MAPVK_VK_TO_VSC); } switch (virtualkey) { case VK_LEFT: case VK_UP: case VK_RIGHT: case VK_DOWN: // arrow keys case VK_PRIOR: case VK_NEXT: // page up and page down case VK_END: case VK_HOME: case VK_INSERT: case VK_DELETE: case VK_DIVIDE: // numpad slash case VK_NUMLOCK: case VK_RCONTROL: case VK_RMENU: { scancode |= EXTENDED_FLAG; // set extended bit break; } case VK_RETURN: { // Remove ambiguity between Enter and Numpad Enter. // In Windows, VK_RETURN is used for both. if (alias == Qt::Key_Enter) { scancode |= EXTENDED_FLAG; // set extended bit break; } } } return scancode; } /** * @brief Check foreground window (window in focus) and obtain the * corresponding exe file path. * @return File path of executable */ QString WinExtras::getForegroundWindowExePath() { QString exePath; HWND foreground = GetForegroundWindow(); HANDLE windowProcess = NULL; if (foreground) { DWORD processId; GetWindowThreadProcessId(foreground, &processId); windowProcess = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, true, processId); } if (windowProcess != NULL) { TCHAR filename[MAX_PATH]; memset(filename, 0, sizeof(filename)); //qDebug() << QString::number(sizeof(filename)/sizeof(TCHAR)); if (pQueryFullProcessImageNameW) { // Windows Vista and later DWORD pathLength = MAX_PATH * sizeof(TCHAR); pQueryFullProcessImageNameW(windowProcess, 0, filename, &pathLength); //qDebug() << pathLength; } else { // Windows XP GetModuleFileNameEx(windowProcess, NULL, filename, MAX_PATH * sizeof(TCHAR)); //qDebug() << pathLength; } exePath = QString::fromWCharArray(filename); //qDebug() << QString::fromWCharArray(filename); CloseHandle(windowProcess); } return exePath; } bool WinExtras::containsFileAssociationinRegistry() { bool result = false; QSettings associationReg(FILEASSOCIATIONKEY, QSettings::NativeFormat); QString temp = associationReg.value("Default", "").toString(); if (!temp.isEmpty()) { result = true; } return result; } void WinExtras::writeFileAssocationToRegistry() { QSettings fileAssociationReg(FILEASSOCIATIONKEY, QSettings::NativeFormat); fileAssociationReg.setValue("Default", "AntiMicro.amgp"); fileAssociationReg.sync(); QSettings programAssociationReg(PROGRAMASSOCIATIONKEY, QSettings::NativeFormat); programAssociationReg.setValue("Default", tr("AntiMicro Profile")); programAssociationReg.setValue("shell/open/command/Default", QString("\"%1\" \"%2\"").arg(QDir::toNativeSeparators(qApp->applicationFilePath())).arg("%1")); programAssociationReg.setValue("DefaultIcon/Default", QString("%1,%2").arg(QDir::toNativeSeparators(qApp->applicationFilePath())).arg("0")); programAssociationReg.sync(); // Required to refresh settings used in Windows Explorer SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0); } void WinExtras::removeFileAssociationFromRegistry() { QSettings fileAssociationReg(FILEASSOCIATIONKEY, QSettings::NativeFormat); QString currentValue = fileAssociationReg.value("Default", "").toString(); if (currentValue == "AntiMicro.amgp") { fileAssociationReg.remove("Default"); fileAssociationReg.sync(); } QSettings programAssociationReg(PROGRAMASSOCIATIONKEY, QSettings::NativeFormat); programAssociationReg.remove(""); programAssociationReg.sync(); // Required to refresh settings used in Windows Explorer SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, 0, 0); } /** * @brief Attempt to elevate process using runas * @return Execution status */ bool WinExtras::elevateAntiMicro() { QString antiProgramLocation = QDir::toNativeSeparators(qApp->applicationFilePath()); QByteArray temp = antiProgramLocation.toUtf8(); SHELLEXECUTEINFO sei = { sizeof(sei) }; wchar_t tempverb[6]; wchar_t tempfile[antiProgramLocation.length() + 1]; QString("runas").toWCharArray(tempverb); antiProgramLocation.toWCharArray(tempfile); tempverb[5] = '\0'; tempfile[antiProgramLocation.length()] = '\0'; sei.lpVerb = tempverb; sei.lpFile = tempfile; sei.hwnd = NULL; sei.nShow = SW_NORMAL; BOOL result = ShellExecuteEx(&sei); return result; } /** * @brief Check if the application is running with administrative privileges. * @return Status indicating administrative privileges */ bool WinExtras::IsRunningAsAdmin() { BOOL isAdmin = FALSE; PSID administratorsGroup; SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY; isAdmin = AllocateAndInitializeSid(&ntAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &administratorsGroup); if (isAdmin) { if (!CheckTokenMembership(NULL, administratorsGroup, &isAdmin)) { isAdmin = FALSE; } FreeSid(administratorsGroup); } return isAdmin; } /** * @brief Temporarily disable "Enhanced Pointer Precision". */ void WinExtras::disablePointerPrecision() { int mouseInfo[3]; SystemParametersInfo(SPI_GETMOUSE, 0, &mouseInfo, 0); if (mouseInfo[2] == 1 && mouseInfo[2] == originalMouseAccel) { mouseInfo[2] = 0; SystemParametersInfo(SPI_SETMOUSE, 0, &mouseInfo, 0); } } /** * @brief If "Enhanced Pointer Precision" is currently disabled and * the setting has not been changed explicitly by the user while * the program has been running, re-enable "Enhanced Pointer Precision". * Return the mouse behavior to normal. */ void WinExtras::enablePointerPrecision() { int mouseInfo[3]; SystemParametersInfo(SPI_GETMOUSE, 0, &mouseInfo, 0); if (mouseInfo[2] == 0 && mouseInfo[2] != originalMouseAccel) { mouseInfo[2] = originalMouseAccel; SystemParametersInfo(SPI_SETMOUSE, 0, &mouseInfo, 0); } } /** * @brief Used to check if the "Enhance Pointer Precision" Windows * option is currently enabled. * @return Status of "Enhanced Pointer Precision" */ bool WinExtras::isUsingEnhancedPointerPrecision() { bool result = false; int mouseInfo[3]; SystemParametersInfo(SPI_GETMOUSE, 0, &mouseInfo, 0); if (mouseInfo[2] > 0) { result = true; } return result; } /** * @brief Get the value of "Enhanced Pointer Precision" when the program * first starts. Needed to not override setting if the option has * been disabled in Windows by the user. */ void WinExtras::grabCurrentPointerPrecision() { int mouseInfo[3]; SystemParametersInfo(SPI_GETMOUSE, 0, &mouseInfo, 0); originalMouseAccel = mouseInfo[2]; } /** * @brief Get the window text of the window currently in focus. * @return Window title of application in focus. */ QString WinExtras::getCurrentWindowText() { QString windowText; HWND foreground = GetForegroundWindow(); if (foreground != NULL) { TCHAR foundWindowTitle[256]; memset(foundWindowTitle, 0, sizeof(foundWindowTitle)); GetWindowTextW(foreground, foundWindowTitle, 255); QString temp = QString::fromWCharArray(foundWindowTitle); if (temp.isEmpty()) { memset(foundWindowTitle, 0, sizeof(foundWindowTitle)); SendMessageA(foreground, WM_GETTEXT, 255, (LPARAM)foundWindowTitle); temp = QString::fromWCharArray(foundWindowTitle); } if (!temp.isEmpty()) { windowText = temp; } } return windowText; } bool WinExtras::raiseProcessPriority() { bool result = false; result = SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); /*if (!result) { qDebug() << "COULD NOT RAISE PROCESS PRIORITY"; } */ return result; } QPoint WinExtras::getCursorPos() { POINT cursorPoint; GetCursorPos(&cursorPoint); QPoint temp(cursorPoint.x, cursorPoint.y); return temp; } antimicro-2.23/src/winextras.h000066400000000000000000000026671300750276700164330ustar00rootroot00000000000000#ifndef WINEXTRAS_H #define WINEXTRAS_H #include #include #include #include class WinExtras : public QObject { Q_OBJECT public: static QString getDisplayString(unsigned int virtualkey); static unsigned int getVirtualKey(QString codestring); static unsigned int correctVirtualKey(unsigned int scancode, unsigned int virtualkey); static unsigned int scancodeFromVirtualKey(unsigned int virtualkey, unsigned int alias=0); static const unsigned int EXTENDED_FLAG; static QString getForegroundWindowExePath(); static bool containsFileAssociationinRegistry(); static void writeFileAssocationToRegistry(); static void removeFileAssociationFromRegistry(); static bool IsRunningAsAdmin(); static bool elevateAntiMicro(); static void disablePointerPrecision(); static void enablePointerPrecision(); static bool isUsingEnhancedPointerPrecision(); static void grabCurrentPointerPrecision(); static QString getCurrentWindowText(); static bool raiseProcessPriority(); static QPoint getCursorPos(); protected: explicit WinExtras(QObject *parent = 0); void populateKnownAliases(); static WinExtras _instance; QHash knownAliasesX11SymVK; QHash knownAliasesVKStrings; static int originalMouseAccel; signals: public slots: }; #endif // WINEXTRAS_H antimicro-2.23/src/x11extras.cpp000066400000000000000000000550311300750276700165730ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include //#include #include #include #include "common.h" #include #include #include #include #include "x11extras.h" const QString X11Extras::mouseDeviceName = PadderCommon::mouseDeviceName; const QString X11Extras::keyboardDeviceName = PadderCommon::keyboardDeviceName; const QString X11Extras::xtestMouseDeviceName = QString("Virtual core XTEST pointer"); QString X11Extras::_customDisplayString = QString(""); static QThreadStorage displays; X11Extras* X11Extras::_instance = 0; X11Extras::X11Extras(QObject *parent) : QObject(parent), knownAliases() { //knownAliases = QHash (); _display = XOpenDisplay(NULL); populateKnownAliases(); } /** * @brief Close display connection if one exists */ X11Extras::~X11Extras() { if (_display) { XCloseDisplay(display()); _display = 0; //_customDisplayString = ""; } } X11Extras *X11Extras::getInstance() { /*if (!_instance) { _instance = new X11Extras(); } return _instance; */ X11Extras *temp = 0; if (!displays.hasLocalData()) { temp = new X11Extras(); displays.setLocalData(temp); } else { temp = displays.localData(); } return temp; } void X11Extras::deleteInstance() { /*if (_instance) { delete _instance; _instance = 0; } */ if (displays.hasLocalData()) { X11Extras *temp = displays.localData(); delete temp; displays.setLocalData(0); } } /** * @brief Get display instance * @return Display struct */ Display* X11Extras::display() { return _display; } bool X11Extras::hasValidDisplay() { bool result = _display != NULL; return result; } /** * @brief CURRENTLY NOT USED */ void X11Extras::closeDisplay() { if (_display) { XCloseDisplay(display()); _display = 0; //_customDisplayString = ""; } } /** * @brief Grab instance of active display. */ void X11Extras::syncDisplay() { _display = XOpenDisplay(NULL); //_customDisplayString = ""; } /** * @brief Grab instance of specified display. Useful for having the GUI * on one display while generating events on another during ssh tunneling. * @param Valid display string that X can use */ void X11Extras::syncDisplay(QString displayString) { QByteArray tempByteArray = displayString.toLocal8Bit(); _display = XOpenDisplay(tempByteArray.constData()); /*if (_display) { _customDisplayString = displayString; } else { _customDisplayString = ""; } */ } void X11Extras::setCustomDisplay(QString displayString) { _customDisplayString = displayString; } /** * @brief Return root window for a given X display * @param Screen number. If no value is passed, uses screen 1. * @return XID of the window */ unsigned long X11Extras::appRootWindow(int screen) { return screen == -1 ? XDefaultRootWindow(display()) : XRootWindowOfScreen(XScreenOfDisplay(display(), screen)); } /** * @brief Get appropriate alias for a known KeySym string that might be blank * or contain invalid characters when returned from X. * @param QString representation of a KeySym string * @return Alias string or a blank QString if no alias was found */ QString X11Extras::getDisplayString(QString xcodestring) { QString temp; if (knownAliases.contains(xcodestring)) { temp = knownAliases.value(xcodestring); } return temp; } void X11Extras::populateKnownAliases() { // These aliases are needed for xstrings that would // return empty space characters from XLookupString if (knownAliases.isEmpty()) { knownAliases.insert("Escape", tr("ESC")); knownAliases.insert("Tab", tr("Tab")); knownAliases.insert("space", tr("Space")); knownAliases.insert("Delete", tr("DEL")); knownAliases.insert("Return", tr("Return")); knownAliases.insert("KP_Enter", tr("KP_Enter")); knownAliases.insert("BackSpace", tr("Backspace")); } } Window X11Extras::findParentClient(Window window) { Window parent = 0; Window root = 0; Window *children = 0; unsigned int num_children = 0; Window finalwindow = 0; Display *display = this->display(); if (windowIsViewable(display, window) && isWindowRelevant(display, window)) { finalwindow = window; } else { bool quitTraversal = false; while (!quitTraversal) { children = 0; if (XQueryTree(display, window, &root, &parent, &children, &num_children)) { if (children) { // must test for NULL XFree(children); } if (parent) { if (windowIsViewable(display, parent) && isWindowRelevant(display, parent)) { quitTraversal = true; finalwindow = parent; } else if (parent == 0) { quitTraversal = true; } else if (parent == root) { quitTraversal = true; } else { window = parent; } } else { quitTraversal = true; } } else { quitTraversal = true; } } } return finalwindow; } /** * @brief Check window and any parents for the window property "_NET_WM_PID" * @param Window XID for window of interest * @return PID of the application instance corresponding to the window */ int X11Extras::getApplicationPid(Window window) { Atom atom, actual_type; int actual_format = 0; unsigned long nitems = 0; unsigned long bytes_after = 0; unsigned char *prop = 0; int status = 0; int pid = 0; Window finalwindow = 0; Display *display = this->display(); atom = XInternAtom(display, "_NET_WM_PID", True); if (windowHasProperty(display, window, atom)) { finalwindow = window; } else { Window parent = 0; Window root = 0; Window *children; unsigned int num_children; bool quitTraversal = false; while (!quitTraversal) { children = 0; if (XQueryTree(display, window, &root, &parent, &children, &num_children)) { if (children) { // must test for NULL XFree(children); } if (parent) { if (windowHasProperty(display, parent, atom)) { quitTraversal = true; finalwindow = parent; } else if (parent == 0) { quitTraversal = true; } else if (parent == root) { quitTraversal = true; } else { window = parent; } } else { quitTraversal = true; } } else { quitTraversal = true; } } } if (finalwindow) { status = XGetWindowProperty(display, finalwindow, atom, 0, 1024, false, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop); if (status == 0 && prop) { pid = prop[1] << 8; pid += prop[0]; XFree(prop); } } return pid; } /** * @brief Find the application file location for a given PID * @param PID of window * @return File location of application */ QString X11Extras::getApplicationLocation(int pid) { QString exepath; if (pid > 0) { QString procString = QString("/proc/%1/exe").arg(pid); QFileInfo procFileInfo(procString); if (procFileInfo.exists()) { char buf[1024]; QByteArray tempByteArray = procString.toLocal8Bit(); ssize_t len = readlink(tempByteArray.constData(), buf, sizeof(buf)-1); if (len != -1) { buf[len] = '\0'; } if (len > 0) { QString temp = QString::fromUtf8(buf); if (!temp.isEmpty()) { exepath = temp; } } } } return exepath; } /** * @brief Find the proper client window within a hierarchy. This check is needed * in some environments where the window that has been selected is actually * a child to a transparent parent window which was the one that was * actually grabbed * @param Top window to check * @return Client window XID or 0 if no appropriate window was found */ Window X11Extras::findClientWindow(Window window) { Window parent = 1; Window root = 0; Window *children = 0; unsigned int num_children = 0; Window finalwindow = 0; Display *display = this->display(); if (windowIsViewable(display, window) && isWindowRelevant(display, window)) { finalwindow = window; } else { XQueryTree(display, window, &root, &parent, &children, &num_children); if (children) { for (unsigned int i = 0; i < num_children && !finalwindow; i++) { if (windowIsViewable(display, children[i]) && isWindowRelevant(display, window)) { finalwindow = children[i]; } } } if (!finalwindow && children) { for (unsigned int i = 0; i < num_children && !finalwindow; i++) { finalwindow = findClientWindow(children[i]); } } if (children) { XFree(children); children = 0; } } return finalwindow; } bool X11Extras::windowHasProperty(Display *display, Window window, Atom atom) { bool result = false; Atom actual_type; int actual_format = 0; unsigned long nitems = 0; unsigned long bytes_after = 0; unsigned char *prop = 0; int status = 0; status = XGetWindowProperty(display, window, atom, 0, 1024, false, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop); if (status == Success && prop) { result = true; } if (prop) { XFree(prop); prop = 0; } return result; } bool X11Extras::windowIsViewable(Display *display, Window window) { bool result = false; XWindowAttributes xwa; XGetWindowAttributes(display, window, &xwa); if (xwa.c_class == InputOutput && xwa.map_state == IsViewable) { result = true; } return result; } /** * @brief Go through a window's properties and search for an Atom * from a defined list. If an Atom is found in a window's properties, * that window should be considered relevant and one that should be grabbed. * @param Display* * @param Window * @return If a window has a relevant Atom in its properties. */ bool X11Extras::isWindowRelevant(Display *display, Window window) { bool result = false; QList temp; temp.append(XInternAtom(display, "WM_STATE", True)); temp.append(XInternAtom(display, "_NW_WM_STATE", True)); temp.append(XInternAtom(display, "_NW_WM_NAME", True)); QListIterator iter(temp); while (iter.hasNext()) { Atom current_atom = iter.next(); if (windowHasProperty(display, window, current_atom)) { iter.toBack(); result = true; } } return result; } QString X11Extras::getWindowTitle(Window window) { QString temp; Atom atom, actual_type; int actual_format = 0; unsigned long nitems = 0; unsigned long bytes_after = 0; unsigned char *prop = 0; int status = 0; //qDebug() << "WIN: 0x" << QString::number(window, 16); Display *display = this->display(); Atom wm_name = XInternAtom(display, "WM_NAME", True); Atom net_wm_name = XInternAtom(display, "_NET_WM_NAME", True); atom = wm_name; QList tempList; tempList.append(wm_name); tempList.append(net_wm_name); QListIterator iter(tempList); while (iter.hasNext()) { Atom temp_atom = iter.next(); if (windowHasProperty(display, window, temp_atom)) { iter.toBack(); atom = temp_atom; } } status = XGetWindowProperty(display, window, atom, 0, 1024, false, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop); if (status == Success && prop) { char *tempprop = (char*)prop; temp.append(QString::fromUtf8(tempprop)); //qDebug() << temp; } if (prop) { XFree(prop); prop = 0; } return temp; } QString X11Extras::getWindowClass(Window window) { QString temp; Atom atom, actual_type; int actual_format = 0; unsigned long nitems = 0; unsigned long bytes_after = 0; unsigned char *prop = 0; int status = 0; Display *display = this->display(); atom = XInternAtom(display, "WM_CLASS", True); status = XGetWindowProperty(display, window, atom, 0, 1024, false, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop); if (status == Success && prop) { //qDebug() << nitems; char *null_char = strchr((char*)prop, '\0'); if ((char*)prop + nitems - 1 > null_char) { *(null_char) = ' '; } char *tempprop = (char*)prop; temp.append(QString::fromUtf8(tempprop)); //qDebug() << temp; //qDebug() << (char*)prop; } if (prop) { XFree(prop); prop = 0; } return temp; } unsigned long X11Extras::getWindowInFocus() { unsigned long result = 0; Window currentWindow = 0; int focusState = 0; Display *display = this->display(); XGetInputFocus(display, ¤tWindow, &focusState); if (currentWindow > 0) { result = static_cast(currentWindow); } return result; } /** * @brief Get QString representation of currently utilized X display. * @return */ QString X11Extras::getXDisplayString() { return _customDisplayString; } unsigned int X11Extras::getGroup1KeySym(unsigned int virtualkey) { unsigned int result = 0; Display *display = this->display(); unsigned int temp = XKeysymToKeycode(display, virtualkey); result = XkbKeycodeToKeysym(display, temp, 0, 0); return result; } void X11Extras::x11ResetMouseAccelerationChange(QString pointerName) { int xi_opcode, event, error; xi_opcode = event = error = 0; Display *display = this->display(); bool result = XQueryExtension(display, "XInputExtension", &xi_opcode, &event, &error); if (!result) { Logger::LogInfo(tr("xinput extension was not found. No mouse acceleration changes will occur.")); } else { int ximajor = 2, ximinor = 0; if (XIQueryVersion(display, &ximajor, &ximinor) != Success) { Logger::LogInfo(tr("xinput version must be at least 2.0. No mouse acceleration changes will occur.")); result = false; } } if (result) { XIDeviceInfo *all_devices = 0; XIDeviceInfo *current_devices = 0; XIDeviceInfo *mouse_device = 0; int num_devices = 0; all_devices = XIQueryDevice(display, XIAllDevices, &num_devices); for (int i=0; i < num_devices; i++) { current_devices = &all_devices[i]; if (current_devices->use == XISlavePointer && QString::fromUtf8(current_devices->name) == pointerName) { Logger::LogInfo(tr("Virtual pointer found with id=%1.").arg(current_devices->deviceid)); mouse_device = current_devices; } } if (mouse_device) { XDevice *device = XOpenDevice(display, mouse_device->deviceid); int num_feedbacks = 0; int feedback_id = -1; XFeedbackState *feedbacks = XGetFeedbackControl(display, device, &num_feedbacks); XFeedbackState *temp = feedbacks; for (int i=0; (i < num_feedbacks) && (feedback_id == -1); i++) { if (temp->c_class == PtrFeedbackClass) { feedback_id = temp->id; } if (i+1 < num_feedbacks) { temp = (XFeedbackState*) ((char*) temp + temp->length); } } XFree(feedbacks); feedbacks = temp = 0; if (feedback_id <= -1) { Logger::LogInfo(tr("PtrFeedbackClass was not found for virtual pointer." "No change to mouse acceleration will occur for device with id=%1").arg(device->device_id)); result = false; } else { Logger::LogInfo(tr("Changing mouse acceleration for device with id=%1").arg(device->device_id)); XPtrFeedbackControl feedback; feedback.c_class = PtrFeedbackClass; feedback.length = sizeof(XPtrFeedbackControl); feedback.id = feedback_id; feedback.threshold = 0; feedback.accelNum = 1; feedback.accelDenom = 1; XChangeFeedbackControl(display, device, DvAccelNum|DvAccelDenom|DvThreshold, (XFeedbackControl*) &feedback); XSync(display, false); } XCloseDevice(display, device); } if (all_devices) { XIFreeDeviceInfo(all_devices); } } } void X11Extras::x11ResetMouseAccelerationChange() { x11ResetMouseAccelerationChange(mouseDeviceName); } struct X11Extras::ptrInformation X11Extras::getPointInformation(QString pointerName) { struct ptrInformation tempInfo; int xi_opcode, event, error; xi_opcode = event = error = 0; Display *display = this->display(); bool result = XQueryExtension(display, "XInputExtension", &xi_opcode, &event, &error); if (result) { int ximajor = 2, ximinor = 0; if (XIQueryVersion(display, &ximajor, &ximinor) != Success) { Logger::LogInfo(tr("xinput version must be at least 2.0. No mouse acceleration changes will occur.")); result = false; } } if (result) { XIDeviceInfo *all_devices = 0; XIDeviceInfo *current_devices = 0; XIDeviceInfo *mouse_device = 0; int num_devices = 0; all_devices = XIQueryDevice(display, XIAllDevices, &num_devices); for (int i=0; i < num_devices; i++) { current_devices = &all_devices[i]; if (current_devices->use == XISlavePointer && QString::fromUtf8(current_devices->name) == pointerName) { mouse_device = current_devices; } } if (mouse_device) { XDevice *device = XOpenDevice(display, mouse_device->deviceid); int num_feedbacks = 0; int feedback_id = -1; XFeedbackState *feedbacks = XGetFeedbackControl(display, device, &num_feedbacks); XFeedbackState *temp = feedbacks; for (int i=0; (i < num_feedbacks) && (feedback_id == -1); i++) { if (temp->c_class == PtrFeedbackClass) { feedback_id = temp->id; } if (feedback_id == -1 && (i+1 < num_feedbacks)) { temp = (XFeedbackState*) ((char*) temp + temp->length); } } if (feedback_id <= -1) { result = false; } else { XPtrFeedbackState *tempPtrFeedback = reinterpret_cast(temp); tempInfo.id = feedback_id; tempInfo.accelNum = tempPtrFeedback->accelNum; tempInfo.accelDenom = tempPtrFeedback->accelDenom; tempInfo.threshold = tempPtrFeedback->threshold; } XFree(feedbacks); feedbacks = temp = 0; XCloseDevice(display, device); } if (all_devices) { XIFreeDeviceInfo(all_devices); } } return tempInfo; } struct X11Extras::ptrInformation X11Extras::getPointInformation() { return getPointInformation(mouseDeviceName); } QPoint X11Extras::getPos() { XEvent mouseEvent; Window wid = DefaultRootWindow(display()); XWindowAttributes xwAttr; XQueryPointer(display(), wid, &mouseEvent.xbutton.root, &mouseEvent.xbutton.window, &mouseEvent.xbutton.x_root, &mouseEvent.xbutton.y_root, &mouseEvent.xbutton.x, &mouseEvent.xbutton.y, &mouseEvent.xbutton.state); XGetWindowAttributes(display(), wid, &xwAttr); QPoint currentPoint(mouseEvent.xbutton.x_root, mouseEvent.xbutton.y_root); return currentPoint; } antimicro-2.23/src/x11extras.h000066400000000000000000000054711300750276700162430ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef X11EXTRAS_H #define X11EXTRAS_H #include #include #include #include #include class X11Extras : public QObject { Q_OBJECT public: struct ptrInformation { long id; int threshold; int accelNum; int accelDenom; ptrInformation() { id = -1; threshold = 0; accelNum = 0; accelDenom = 1; } }; ~X11Extras(); unsigned long appRootWindow(int screen = -1); Display* display(); bool hasValidDisplay(); QString getDisplayString(QString xcodestring); int getApplicationPid(Window window); QString getApplicationLocation(int pid); Window findClientWindow(Window window); Window findParentClient(Window window); void closeDisplay(); void syncDisplay(); void syncDisplay(QString displayString); static QString getXDisplayString(); QString getWindowTitle(Window window); QString getWindowClass(Window window); unsigned long getWindowInFocus(); unsigned int getGroup1KeySym(unsigned int virtualkey); void x11ResetMouseAccelerationChange(); void x11ResetMouseAccelerationChange(QString pointerName); struct ptrInformation getPointInformation(); struct ptrInformation getPointInformation(QString pointerName); static void setCustomDisplay(QString displayString); static X11Extras* getInstance(); static void deleteInstance(); static const QString mouseDeviceName; static const QString keyboardDeviceName; static const QString xtestMouseDeviceName; protected: explicit X11Extras(QObject *parent = 0); void populateKnownAliases(); bool windowHasProperty(Display *display, Window window, Atom atom); bool windowIsViewable(Display *display, Window window); bool isWindowRelevant(Display *display, Window window); Display *_display; static X11Extras *_instance; QHash knownAliases; static QString _customDisplayString; signals: public slots: QPoint getPos(); }; #endif // X11EXTRAS_H antimicro-2.23/src/xmlconfigmigration.cpp000066400000000000000000000124271300750276700206350ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "event.h" #include "antkeymapper.h" #ifdef Q_OS_UNIX #include "eventhandlerfactory.h" #endif #include "xmlconfigmigration.h" XMLConfigMigration::XMLConfigMigration(QXmlStreamReader *reader, QObject *parent) : QObject(parent) { this->reader = reader; if (reader->device() && reader->device()->isOpen()) { this->fileVersion = reader->attributes().value("configversion").toString().toInt(); } else { this->fileVersion = 0; } } bool XMLConfigMigration::requiresMigration() { bool toMigrate = false; if (fileVersion == 0) { toMigrate = false; } else if (fileVersion >= 2 && fileVersion <= PadderCommon::LATESTCONFIGMIGRATIONVERSION) { toMigrate = true; } return toMigrate; } QString XMLConfigMigration::migrate() { QString tempXmlString; if (requiresMigration()) { int tempFileVersion = fileVersion; QString initialData = readConfigToString(); reader->clear(); reader->addData(initialData); if (tempFileVersion >= 2 && tempFileVersion <= 5) { tempXmlString = version0006Migration(); tempFileVersion = PadderCommon::LATESTCONFIGFILEVERSION; } } return tempXmlString; } QString XMLConfigMigration::readConfigToString() { QString tempXmlString; QXmlStreamWriter writer(&tempXmlString); writer.setAutoFormatting(true); while (!reader->atEnd()) { writer.writeCurrentToken(*reader); reader->readNext(); } return tempXmlString; } QString XMLConfigMigration::version0006Migration() { QString tempXmlString; QXmlStreamWriter writer(&tempXmlString); writer.setAutoFormatting(true); reader->readNextStartElement(); reader->readNextStartElement(); writer.writeStartDocument(); writer.writeStartElement("joystick"); writer.writeAttribute("configversion", QString::number(6)); writer.writeAttribute("appversion", PadderCommon::programVersion); while (!reader->atEnd()) { if (reader->name() == "slot" && reader->isStartElement()) { unsigned int slotcode = 0; QString slotmode; writer.writeCurrentToken(*reader); reader->readNext(); // Grab current slot code and slot mode while (!reader->atEnd() && (!reader->isEndElement() && reader->name() != "slot")) { if (reader->name() == "code" && reader->isStartElement()) { QString tempcode = reader->readElementText(); slotcode = tempcode.toInt(); } else if (reader->name() == "mode" && reader->isStartElement()) { slotmode = reader->readElementText(); } else { writer.writeCurrentToken(*reader); } reader->readNext(); } // Reformat slot code if associated with the keyboard if (slotcode && !slotmode.isEmpty()) { if (slotmode == "keyboard") { unsigned int tempcode = slotcode; #ifdef Q_OS_WIN slotcode = AntKeyMapper::getInstance()->returnQtKey(slotcode); #else BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); if (handler->getIdentifier() == "xtest") { slotcode = AntKeyMapper::getInstance()->returnQtKey(X11KeyCodeToX11KeySym(slotcode)); } else { slotcode = 0; tempcode = 0; } #endif if (slotcode > 0) { writer.writeTextElement("code", QString("0x%1").arg(slotcode, 0, 16)); } else if (tempcode > 0) { writer.writeTextElement("code", QString("0x%1").arg(tempcode | QtKeyMapperBase::nativeKeyPrefix, 0, 16)); } } else { writer.writeTextElement("code", QString::number(slotcode)); } writer.writeTextElement("mode", slotmode); } writer.writeCurrentToken(*reader); } else { writer.writeCurrentToken(*reader); } reader->readNext(); } return tempXmlString; } antimicro-2.23/src/xmlconfigmigration.h000066400000000000000000000024431300750276700202770ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef XMLCONFIGMIGRATION_H #define XMLCONFIGMIGRATION_H #include #include #include #include "common.h" class XMLConfigMigration : public QObject { Q_OBJECT public: explicit XMLConfigMigration(QXmlStreamReader *reader, QObject *parent = 0); bool requiresMigration(); QString migrate(); protected: QXmlStreamReader *reader; int fileVersion; private: QString readConfigToString(); QString version0006Migration(); signals: public slots: }; #endif // XMLCONFIGMIGRATION_H antimicro-2.23/src/xmlconfigreader.cpp000066400000000000000000000112141300750276700200770ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ //#include #include #include #include "xmlconfigreader.h" #include "xmlconfigmigration.h" #include "xmlconfigwriter.h" #include "common.h" XMLConfigReader::XMLConfigReader(QObject *parent) : QObject(parent) { xml = new QXmlStreamReader(); configFile = 0; joystick = 0; initDeviceTypes(); } XMLConfigReader::~XMLConfigReader() { if (configFile) { if (configFile->isOpen()) { configFile->close(); } delete configFile; configFile = 0; } if (xml) { delete xml; xml = 0; } } void XMLConfigReader::setJoystick(InputDevice *joystick) { this->joystick = joystick; } void XMLConfigReader::setFileName(QString filename) { QFile *temp = new QFile(filename); if (temp->exists()) { configFile = temp; } else { delete temp; temp = 0; } } void XMLConfigReader::configJoystick(InputDevice *joystick) { this->joystick = joystick; read(); } bool XMLConfigReader::read() { bool error = false; if (configFile && configFile->exists() && joystick) { xml->clear(); if (!configFile->isOpen()) { configFile->open(QFile::ReadOnly | QFile::Text); xml->setDevice(configFile); } xml->readNextStartElement(); if (!deviceTypes.contains(xml->name().toString())) { xml->raiseError("Root node is not a joystick or controller"); } else if (xml->name() == Joystick::xmlName) { XMLConfigMigration migration(xml); if (migration.requiresMigration()) { QString migrationString = migration.migrate(); if (migrationString.length() > 0) { // Remove QFile from reader and clear state xml->clear(); // Add converted XML string to reader xml->addData(migrationString); // Skip joystick root node xml->readNextStartElement(); // Close current config file configFile->close(); // Write converted XML to file configFile->open(QFile::WriteOnly | QFile::Text); if (configFile->isOpen()) { configFile->write(migrationString.toLocal8Bit()); configFile->close(); } else { xml->raiseError(tr("Could not write updated profile XML to file %1.").arg(configFile->fileName())); } } } } while (!xml->atEnd()) { if (xml->isStartElement() && deviceTypes.contains(xml->name().toString())) { joystick->readConfig(xml); } else { // If none of the above, skip the element xml->skipCurrentElement(); } xml->readNextStartElement(); } if (configFile->isOpen()) { configFile->close(); } if (xml->hasError() && xml->error() != QXmlStreamReader::PrematureEndOfDocumentError) { error = true; } else if (xml->hasError() && xml->error() == QXmlStreamReader::PrematureEndOfDocumentError) { xml->clear(); } } return error; } QString XMLConfigReader::getErrorString() { QString temp; if (xml->hasError()) { temp = xml->errorString(); } return temp; } bool XMLConfigReader::hasError() { return xml->hasError(); } void XMLConfigReader::initDeviceTypes() { deviceTypes.clear(); deviceTypes.append(Joystick::xmlName); #ifdef USE_SDL_2 deviceTypes.append(GameController::xmlName); #endif } antimicro-2.23/src/xmlconfigreader.h000066400000000000000000000030541300750276700175470ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef XMLCONFIGREADER_H #define XMLCONFIGREADER_H #include #include #include #include "inputdevice.h" #include "joystick.h" #ifdef USE_SDL_2 #include "gamecontroller/gamecontroller.h" #endif #include "common.h" class XMLConfigReader : public QObject { Q_OBJECT public: explicit XMLConfigReader(QObject *parent = 0); ~XMLConfigReader(); void setJoystick(InputDevice *joystick); void setFileName(QString filename); QString getErrorString(); bool hasError(); bool read(); protected: void initDeviceTypes(); QXmlStreamReader *xml; QString fileName; QFile *configFile; InputDevice* joystick; QStringList deviceTypes; signals: public slots: void configJoystick(InputDevice *joystick); }; #endif // XMLCONFIGREADER_H antimicro-2.23/src/xmlconfigwriter.cpp000066400000000000000000000041401300750276700201510ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "xmlconfigwriter.h" XMLConfigWriter::XMLConfigWriter(QObject *parent) : QObject(parent) { xml = new QXmlStreamWriter(); xml->setAutoFormatting(true); configFile = 0; joystick = 0; writerError = false; } XMLConfigWriter::~XMLConfigWriter() { if (configFile) { if (configFile->isOpen()) { configFile->close(); } delete configFile; configFile = 0; } if (xml) { delete xml; xml = 0; } } void XMLConfigWriter::write(InputDevice *joystick) { writerError = false; if (!configFile->isOpen()) { configFile->open(QFile::WriteOnly | QFile::Text); xml->setDevice(configFile); } else { writerError = true; writerErrorString = tr("Could not write to profile at %1.").arg(configFile->fileName()); } if (!writerError) { xml->writeStartDocument(); joystick->writeConfig(xml); xml->writeEndDocument(); } if (configFile->isOpen()) { configFile->close(); } } void XMLConfigWriter::setFileName(QString filename) { QFile *temp = new QFile(filename); fileName = filename; configFile = temp; } bool XMLConfigWriter::hasError() { return writerError; } QString XMLConfigWriter::getErrorString() { return writerErrorString; } antimicro-2.23/src/xmlconfigwriter.h000066400000000000000000000026051300750276700176220ustar00rootroot00000000000000/* antimicro Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef XMLCONFIGWRITER_H #define XMLCONFIGWRITER_H #include #include #include #include "inputdevice.h" #include "common.h" class XMLConfigWriter : public QObject { Q_OBJECT public: explicit XMLConfigWriter(QObject *parent = 0); ~XMLConfigWriter(); void setFileName(QString filename); bool hasError(); QString getErrorString(); protected: QXmlStreamWriter *xml; QString fileName; QFile *configFile; InputDevice* joystick; bool writerError; QString writerErrorString; signals: public slots: void write(InputDevice* joystick); }; #endif // XMLCONFIGWRITER_H antimicro-2.23/windows/000077500000000000000000000000001300750276700151265ustar00rootroot00000000000000antimicro-2.23/windows/AntiMicro.wxs000066400000000000000000000404651300750276700175670ustar00rootroot00000000000000 antimicro-2.23/windows/AntiMicro_64.wxs000066400000000000000000000404671300750276700201020ustar00rootroot00000000000000