diff --git a/CMakeLists.txt b/CMakeLists.txt index 45c4b45b0..83b152fb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -401,6 +401,24 @@ if(UNIX) src/eventhandlers/uinputeventhandler.h ) endif(WITH_UINPUT) + +elseif(WIN32) + LIST(APPEND antimicrox_SOURCES + src/winextras.cpp + src/qtwinkeymapper.cpp + # src/winappprofiletimerdialog.cpp + # src/capturedwindowinfodialog.cpp + src/eventhandlers/winsendinputeventhandler.cpp + src/joykeyrepeathelper.cpp + ) + LIST(APPEND antimicrox_HEADERS + src/winextras.h + src/qtwinkeymapper.h + # src/winappprofiletimerdialog.h + # src/capturedwindowinfodialog.h + src/eventhandlers/winsendinputeventhandler.h + src/joykeyrepeathelper.h + ) endif(UNIX) ############################### @@ -465,9 +483,11 @@ if(UNIX) endif(WITH_XTEST) # necessary ifwe use find_package for SDL2 -# if(NOT DEFINED SDL2_LIBRARIES) + # if(NOT DEFINED SDL2_LIBRARIES) # set(SDL2_LIBRARIES SDL2::SDL2) # endif() +elseif (WIN32) + list(APPEND WIN_LIBS "psapi") endif(UNIX) @@ -488,14 +508,29 @@ endif(UNIX) ############################### # COMPILE & LINK ############################### - -add_executable(antimicrox +if(UNIX) + add_executable(antimicrox ${antimicrox_MAIN} ${antimicrox_HEADERS_MOC} ${antimicrox_SOURCES} ${antimicrox_FORMS_HEADERS} ${antimicrox_RESOURCES_RCC} ) +elseif(WIN32) + # The WIN32 is required to specify a GUI application. + add_executable(antimicrox WIN32 + ${antimicrox_MAIN} + ${antimicrox_HEADERS_MOC} + ${antimicrox_SOURCES} + ${antimicrox_FORMS_HEADERS} + ${antimicrox_RESOURCES_RCC} + # TODO create this with windows .ico icon + # src/antimicrox.rc + ) + target_link_libraries(antimicrox + ${WIN_LIBS} + ) +endif(UNIX) target_link_libraries(antimicrox ${QT_LIBS} diff --git a/cmake/modules/FindSDL2.cmake b/cmake/modules/FindSDL2.cmake new file mode 100644 index 000000000..0be1fd6b0 --- /dev/null +++ b/cmake/modules/FindSDL2.cmake @@ -0,0 +1,391 @@ +# https://github.com/aminosbh/sdl2-cmake-modules/blob/master/FindSDL2.cmake + +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +# Copyright 2019 Amine Ben Hassouna +# Copyright 2000-2019 Kitware, Inc. and Contributors +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: + +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. + +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. + +# * Neither the name of Kitware, Inc. nor the names of Contributors +# may be used to endorse or promote products derived from this +# software without specific prior written permission. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#[=======================================================================[.rst: +FindSDL2 +-------- + +Locate SDL2 library + +This module defines the following 'IMPORTED' targets: + +:: + + SDL2::Core + The SDL2 library, if found. + Libraries should link to SDL2::Core + + SDL2::Main + The SDL2main library, if found. + Applications should link to SDL2::Main instead of SDL2::Core + + + +This module will set the following variables in your project: + +:: + + SDL2_LIBRARIES, the name of the library to link against + SDL2_INCLUDE_DIRS, where to find SDL.h + SDL2_FOUND, if false, do not try to link to SDL2 + SDL2MAIN_FOUND, if false, do not try to link to SDL2main + SDL2_VERSION_STRING, human-readable string containing the version of SDL2 + + + +This module responds to the following cache variables: + +:: + + SDL2_PATH + Set a custom SDL2 Library path (default: empty) + + SDL2_NO_DEFAULT_PATH + Disable search SDL2 Library in default path. + If SDL2_PATH (default: ON) + Else (default: OFF) + + SDL2_INCLUDE_DIR + SDL2 headers path. + + SDL2_LIBRARY + SDL2 Library (.dll, .so, .a, etc) path. + + SDL2MAIN_LIBRAY + SDL2main Library (.a) path. + + SDL2_BUILDING_LIBRARY + This flag is useful only when linking to SDL2_LIBRARIES insead of + SDL2::Main. It is required only when building a library that links to + SDL2_LIBRARIES, because only applications need main() (No need to also + link to SDL2main). + If this flag is defined, then no SDL2main will be added to SDL2_LIBRARIES + and no SDL2::Main target will be created. + + +Don't forget to include SDLmain.h and SDLmain.m in your project for the +OS X framework based version. (Other versions link to -lSDL2main which +this module will try to find on your behalf.) Also for OS X, this +module will automatically add the -framework Cocoa on your behalf. + + +Additional Note: If you see an empty SDL2_LIBRARY in your project +configuration, it means CMake did not find your SDL2 library +(SDL2.dll, libsdl2.so, SDL2.framework, etc). Set SDL2_LIBRARY to point +to your SDL2 library, and configure again. Similarly, if you see an +empty SDL2MAIN_LIBRARY, you should set this value as appropriate. These +values are used to generate the final SDL2_LIBRARIES variable and the +SDL2::Core and SDL2::Main targets, but when these values are unset, +SDL2_LIBRARIES, SDL2::Core and SDL2::Main does not get created. + + +$SDL2DIR is an environment variable that would correspond to the +./configure --prefix=$SDL2DIR used in building SDL2. l.e.galup 9-20-02 + + + +Created by Amine Ben Hassouna: + Adapt FindSDL.cmake to SDL2 (FindSDL2.cmake). + Add cache variables for more flexibility: + SDL2_PATH, SDL2_NO_DEFAULT_PATH (for details, see doc above). + Mark 'Threads' as a required dependency for non-OSX systems. + Modernize the FindSDL2.cmake module by creating specific targets: + SDL2::Core and SDL2::Main (for details, see doc above). + + +Original FindSDL.cmake module: + Modified by Eric Wing. Added code to assist with automated building + by using environmental variables and providing a more + controlled/consistent search behavior. Added new modifications to + recognize OS X frameworks and additional Unix paths (FreeBSD, etc). + Also corrected the header search path to follow "proper" SDL + guidelines. Added a search for SDLmain which is needed by some + platforms. Added a search for threads which is needed by some + platforms. Added needed compile switches for MinGW. + +On OSX, this will prefer the Framework version (if found) over others. +People will have to manually change the cache value of SDL2_LIBRARY to +override this selection or set the SDL2_PATH variable or the CMake +environment CMAKE_INCLUDE_PATH to modify the search paths. + +Note that the header path has changed from SDL/SDL.h to just SDL.h +This needed to change because "proper" SDL convention is #include +"SDL.h", not . This is done for portability reasons +because not all systems place things in SDL/ (see FreeBSD). +#]=======================================================================] + +# Define options for searching SDL2 Library in a custom path + +set(SDL2_PATH "" CACHE STRING "Custom SDL2 Library path") + +set(_SDL2_NO_DEFAULT_PATH OFF) +if(SDL2_PATH) + set(_SDL2_NO_DEFAULT_PATH ON) +endif() + +set(SDL2_NO_DEFAULT_PATH ${_SDL2_NO_DEFAULT_PATH} + CACHE BOOL "Disable search SDL2 Library in default path") +unset(_SDL2_NO_DEFAULT_PATH) + +set(SDL2_NO_DEFAULT_PATH_CMD) +if(SDL2_NO_DEFAULT_PATH) + set(SDL2_NO_DEFAULT_PATH_CMD NO_DEFAULT_PATH) +endif() + +# Search for the SDL2 include directory +# Modified to SDL2/SDL.h for antimicroX +find_path(SDL2_INCLUDE_DIR SDL2/SDL.h + HINTS + ENV SDL2DIR + ${SDL2_NO_DEFAULT_PATH_CMD} + PATH_SUFFIXES SDL2 + # path suffixes to search inside ENV{SDL2DIR} + include/SDL2 include + PATHS ${SDL2_PATH} + DOC "Where the SDL2 headers can be found" +) + +set(SDL2_INCLUDE_DIRS "${SDL2_INCLUDE_DIR}") + +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(VC_LIB_PATH_SUFFIX lib/x64) +else() + set(VC_LIB_PATH_SUFFIX lib/x86) +endif() + +# SDL-2.0 is the name used by FreeBSD ports... +# don't confuse it for the version number. +find_library(SDL2_LIBRARY + NAMES SDL2 SDL-2.0 + HINTS + ENV SDL2DIR + ${SDL2_NO_DEFAULT_PATH_CMD} + PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX} + PATHS ${SDL2_PATH} + DOC "Where the SDL2 Library can be found" +) + +set(SDL2_LIBRARIES "${SDL2_LIBRARY}") + +if(NOT SDL2_BUILDING_LIBRARY) + if(NOT SDL2_INCLUDE_DIR MATCHES ".framework") + # Non-OS X framework versions expect you to also dynamically link to + # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms + # seem to provide SDL2main for compatibility even though they don't + # necessarily need it. + + if(SDL2_PATH) + set(SDL2MAIN_LIBRARY_PATHS "${SDL2_PATH}") + endif() + + if(NOT SDL2_NO_DEFAULT_PATH) + set(SDL2MAIN_LIBRARY_PATHS + /sw + /opt/local + /opt/csw + /opt + "${SDL2MAIN_LIBRARY_PATHS}" + ) + endif() + + find_library(SDL2MAIN_LIBRARY + NAMES SDL2main + HINTS + ENV SDL2DIR + ${SDL2_NO_DEFAULT_PATH_CMD} + PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX} + PATHS ${SDL2MAIN_LIBRARY_PATHS} + DOC "Where the SDL2main library can be found" + ) + unset(SDL2MAIN_LIBRARY_PATHS) + endif() +endif() + +# SDL2 may require threads on your system. +# The Apple build may not need an explicit flag because one of the +# frameworks may already provide it. +# But for non-OSX systems, I will use the CMake Threads package. +if(NOT APPLE) + find_package(Threads QUIET) + if(NOT Threads_FOUND) + set(SDL2_THREADS_NOT_FOUND "Could NOT find Threads (Threads is required by SDL2).") + if(SDL2_FIND_REQUIRED) + message(FATAL_ERROR ${SDL2_THREADS_NOT_FOUND}) + else() + if(NOT SDL2_FIND_QUIETLY) + message(STATUS ${SDL2_THREADS_NOT_FOUND}) + endif() + return() + endif() + unset(SDL2_THREADS_NOT_FOUND) + endif() +endif() + +# MinGW needs an additional link flag, -mwindows +# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -mwindows +if(MINGW) + set(MINGW32_LIBRARY mingw32 "-mwindows" CACHE STRING "link flags for MinGW") +endif() + +if(SDL2_LIBRARY) + # For SDL2main + if(SDL2MAIN_LIBRARY AND NOT SDL2_BUILDING_LIBRARY) + list(FIND SDL2_LIBRARIES "${SDL2MAIN_LIBRARY}" _SDL2_MAIN_INDEX) + if(_SDL2_MAIN_INDEX EQUAL -1) + set(SDL2_LIBRARIES "${SDL2MAIN_LIBRARY}" ${SDL2_LIBRARIES}) + endif() + unset(_SDL2_MAIN_INDEX) + endif() + + # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. + # CMake doesn't display the -framework Cocoa string in the UI even + # though it actually is there if I modify a pre-used variable. + # I think it has something to do with the CACHE STRING. + # So I use a temporary variable until the end so I can set the + # "real" variable in one-shot. + if(APPLE) + set(SDL2_LIBRARIES ${SDL2_LIBRARIES} -framework Cocoa) + endif() + + # For threads, as mentioned Apple doesn't need this. + # In fact, there seems to be a problem if I used the Threads package + # and try using this line, so I'm just skipping it entirely for OS X. + if(NOT APPLE) + set(SDL2_LIBRARIES ${SDL2_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + endif() + + # For MinGW library + if(MINGW) + set(SDL2_LIBRARIES ${MINGW32_LIBRARY} ${SDL2_LIBRARIES}) + endif() + +endif() + +# Read SDL2 version +if(SDL2_INCLUDE_DIR AND EXISTS "${SDL2_INCLUDE_DIR}/SDL_version.h") + file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+[0-9]+$") + file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_MINOR_VERSION[ \t]+[0-9]+$") + file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_PATCHLEVEL[ \t]+[0-9]+$") + string(REGEX REPLACE "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_MAJOR "${SDL2_VERSION_MAJOR_LINE}") + string(REGEX REPLACE "^#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_MINOR "${SDL2_VERSION_MINOR_LINE}") + string(REGEX REPLACE "^#define[ \t]+SDL_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_PATCH "${SDL2_VERSION_PATCH_LINE}") + set(SDL2_VERSION_STRING ${SDL2_VERSION_MAJOR}.${SDL2_VERSION_MINOR}.${SDL2_VERSION_PATCH}) + unset(SDL2_VERSION_MAJOR_LINE) + unset(SDL2_VERSION_MINOR_LINE) + unset(SDL2_VERSION_PATCH_LINE) + unset(SDL2_VERSION_MAJOR) + unset(SDL2_VERSION_MINOR) + unset(SDL2_VERSION_PATCH) +endif() + +include(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 + REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR + VERSION_VAR SDL2_VERSION_STRING) + +if(SDL2MAIN_LIBRARY) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2main + REQUIRED_VARS SDL2MAIN_LIBRARY SDL2_INCLUDE_DIR + VERSION_VAR SDL2_VERSION_STRING) +endif() + + +mark_as_advanced(SDL2_PATH + SDL2_NO_DEFAULT_PATH + SDL2_LIBRARY + SDL2MAIN_LIBRARY + SDL2_INCLUDE_DIR + SDL2_BUILDING_LIBRARY) + + +# SDL2:: targets (SDL2::Core and SDL2::Main) +if(SDL2_FOUND) + + # SDL2::Core target + if(SDL2_LIBRARY AND NOT TARGET SDL2::Core) + add_library(SDL2::Core UNKNOWN IMPORTED) + set_target_properties(SDL2::Core PROPERTIES + IMPORTED_LOCATION "${SDL2_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIR}") + + if(APPLE) + # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. + # For more details, please see above. + set_property(TARGET SDL2::Core APPEND PROPERTY + INTERFACE_LINK_OPTIONS -framework Cocoa) + else() + # For threads, as mentioned Apple doesn't need this. + # For more details, please see above. + set_property(TARGET SDL2::Core APPEND PROPERTY + INTERFACE_LINK_LIBRARIES Threads::Threads) + endif() + endif() + + # SDL2::Main target + # Applications should link to SDL2::Main instead of SDL2::Core + # For more details, please see above. + if(NOT SDL2_BUILDING_LIBRARY AND NOT TARGET SDL2::Main) + + if(SDL2_INCLUDE_DIR MATCHES ".framework" OR NOT SDL2MAIN_LIBRARY) + add_library(SDL2::Main INTERFACE IMPORTED) + set_property(TARGET SDL2::Main PROPERTY + INTERFACE_LINK_LIBRARIES SDL2::Core) + elseif(SDL2MAIN_LIBRARY) + # MinGW requires that the mingw32 library is specified before the + # libSDL2main.a static library when linking. + # The SDL2::MainInternal target is used internally to make sure that + # CMake respects this condition. + add_library(SDL2::MainInternal UNKNOWN IMPORTED) + set_property(TARGET SDL2::MainInternal PROPERTY + IMPORTED_LOCATION "${SDL2MAIN_LIBRARY}") + set_property(TARGET SDL2::MainInternal PROPERTY + INTERFACE_LINK_LIBRARIES SDL2::Core) + + add_library(SDL2::Main INTERFACE IMPORTED) + + if(MINGW) + # MinGW needs an additional link flag '-mwindows' and link to mingw32 + set_property(TARGET SDL2::Main PROPERTY + INTERFACE_LINK_LIBRARIES "mingw32" "-mwindows") + endif() + + set_property(TARGET SDL2::Main APPEND PROPERTY + INTERFACE_LINK_LIBRARIES SDL2::MainInternal) + endif() + + endif() +endif() diff --git a/src/antkeymapper.cpp b/src/antkeymapper.cpp index 57cce03da..d0a6e1dc1 100644 --- a/src/antkeymapper.cpp +++ b/src/antkeymapper.cpp @@ -30,6 +30,9 @@ static QStringList buildEventGeneratorList() { QStringList temp = QStringList(); +#ifdef Q_OS_WIN + temp.append("sendinput"); +#endif #ifdef WITH_XTEST temp.append("xtest"); #endif @@ -65,7 +68,12 @@ AntKeyMapper::AntKeyMapper(QString handler, QObject *parent) #endif } #endif - +#elif defined Q_OS_WIN + BACKEND_ELSE_IF(handler == "sendinput") + { + internalMapper = &winMapper; + nativeKeyMapper = 0; + } #endif } diff --git a/src/antkeymapper.h b/src/antkeymapper.h index 51e28044c..81168975b 100644 --- a/src/antkeymapper.h +++ b/src/antkeymapper.h @@ -21,12 +21,16 @@ #include -#if defined(WITH_XTEST) - #include "qtx11keymapper.h" -#endif +#ifdef Q_OS_WIN + #include "qtwinkeymapper.h" +#else + #ifdef WITH_XTEST + #include "qtx11keymapper.h" + #endif -#if defined(WITH_UINPUT) - #include "qtuinputkeymapper.h" + #ifdef WITH_UINPUT + #include "qtuinputkeymapper.h" + #endif #endif class AntKeyMapper : public QObject @@ -53,12 +57,16 @@ class AntKeyMapper : public QObject QtKeyMapperBase *internalMapper; QtKeyMapperBase *nativeKeyMapper; -#if defined(WITH_XTEST) +#ifdef Q_OS_WIN + QtWinKeyMapper winMapper; +#else + #if defined(WITH_XTEST) QtX11KeyMapper x11Mapper; -#endif + #endif -#if defined(WITH_UINPUT) + #if defined(WITH_UINPUT) QtUInputKeyMapper uinputMapper; + #endif #endif }; diff --git a/src/event.cpp b/src/event.cpp index 88a30b768..c0900a60e 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -1,6 +1,7 @@ /* antimicrox Gamepad to KB+M event mapper * Copyright (C) 2015 Travis Nickles * Copyright (C) 2020 Jagoda Górska + * Copyright (C) 2021 Paweł Kotiuk * * 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 @@ -32,20 +33,27 @@ #include "globalvariables.h" #include "joybutton.h" -#if defined(WITH_X11) +#if defined(Q_OS_UNIX) + #if defined(WITH_X11) - #include "x11extras.h" - #include - #include - #include + #include "x11extras.h" + #include + #include + #include - #ifdef WITH_XTEST - #include + #ifdef WITH_XTEST + #include + #endif #endif -#endif -#if defined(WITH_UINPUT) - #include "uinputhelper.h" + #if defined(WITH_UINPUT) + #include "uinputhelper.h" + #endif + +#elif defined(Q_OS_WIN) + #include "winextras.h" + #include + #endif // TODO: Implement function for determining final mouse pointer position @@ -289,16 +297,18 @@ void sendSpringEvent(PadderCommon::springModeInfo *fullSpring, PadderCommon::spr width = deskRect.width(); height = deskRect.height(); -#if defined(WITH_X11) QPoint currentPoint; if (QApplication::platformName() == QStringLiteral("xcb")) { +#if defined(WITH_X11) currentPoint = X11Extras::getInstance()->getPos(); +#else + qCritical() << "Platform name returned 'xcb', but X11 support is disabled"; +#endif } else { currentPoint = QCursor::pos(); } -#endif currentMouseX = currentPoint.x(); currentMouseY = currentPoint.y(); @@ -389,6 +399,7 @@ void sendSpringEvent(PadderCommon::springModeInfo *fullSpring, PadderCommon::spr // 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) { @@ -405,13 +416,25 @@ void sendSpringEvent(PadderCommon::springModeInfo *fullSpring, PadderCommon::spr 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") @@ -428,14 +451,25 @@ void sendSpringEvent(PadderCommon::springModeInfo *fullSpring, PadderCommon::spr 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(GlobalVariables::JoyButton::mouseRefreshRate, GlobalVariables::JoyButton::gamepadRefreshRate) + 1); } else if (!PadderCommon::mouseHelperObj.springMouseMoving && ((diffx >= (destSpringWidth * .013)) || (diffy >= (destSpringHeight * .013)))) { PadderCommon::mouseHelperObj.springMouseMoving = true; - BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); +#if defined(Q_OS_UNIX) + BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); if (fullSpring->screen <= -1) { if (handler->getIdentifier() == "xtest") @@ -452,6 +486,17 @@ void sendSpringEvent(PadderCommon::springModeInfo *fullSpring, PadderCommon::spr 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(GlobalVariables::JoyButton::mouseRefreshRate, GlobalVariables::JoyButton::gamepadRefreshRate) + 1); } @@ -463,8 +508,8 @@ void sendSpringEvent(PadderCommon::springModeInfo *fullSpring, PadderCommon::spr else if (PadderCommon::mouseHelperObj.springMouseMoving) { +#if defined(Q_OS_UNIX) BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); - if (fullSpring->screen <= -1) { if (handler->getIdentifier() == "xtest") @@ -481,6 +526,17 @@ void sendSpringEvent(PadderCommon::springModeInfo *fullSpring, PadderCommon::spr 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(GlobalVariables::JoyButton::mouseRefreshRate, GlobalVariables::JoyButton::gamepadRefreshRate) + 1); } @@ -515,26 +571,50 @@ int X11KeySymToKeycode(QString key) { int tempcode = 0; +#if defined(Q_OS_UNIX) BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); - if (key.length() > 0) { -#ifdef WITH_XTEST + #ifdef WITH_XTEST if (handler->getIdentifier() == "xtest") { Display *display = X11Extras::getInstance()->display(); tempcode = XKeysymToKeycode(display, XStringToKeysym(key.toUtf8().data())); } -#endif + #endif -#ifdef WITH_UINPUT + #ifdef WITH_UINPUT if (handler->getIdentifier() == "uinput") { tempcode = UInputHelper::getInstance()->getVirtualKey(key); } -#endif + #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; } @@ -544,7 +624,8 @@ QString keycodeToKeyString(int keycode, int alias) Q_UNUSED(alias) - qDebug() << "keycode is: " << keycode; +#if defined(Q_OS_UNIX) + Q_UNUSED(alias); if (keycode <= 0) { @@ -553,7 +634,7 @@ QString keycodeToKeyString(int keycode, int alias) { BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); -#ifdef WITH_XTEST + #ifdef WITH_XTEST if (handler->getIdentifier() == "xtest") { Display *display = X11Extras::getInstance()->display(); @@ -590,9 +671,9 @@ QString keycodeToKeyString(int keycode, int alias) } } } -#endif + #endif -#ifdef WITH_UINPUT + #ifdef WITH_UINPUT if (handler->getIdentifier() == "uinput") { QString tempalias = UInputHelper::getInstance()->getDisplayString(keycode); @@ -602,24 +683,56 @@ QString keycodeToKeyString(int keycode, int alias) else newkey = QString("0x%1").arg(keycode, 0, 16); } -#endif + #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; } int X11KeyCodeToX11KeySym(int keycode) { -#ifdef WITH_X11 - - Display *display = X11Extras::getInstance()->display(); - return XkbKeycodeToKeysym(display, static_cast(keycode), 0, 0); - +#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) + Q_UNUSED(keycode); return 0; - + #endif #endif } diff --git a/src/eventhandlerfactory.cpp b/src/eventhandlerfactory.cpp index 3d5f3c268..2ae1498f3 100644 --- a/src/eventhandlerfactory.cpp +++ b/src/eventhandlerfactory.cpp @@ -27,10 +27,15 @@ 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; } @@ -54,6 +59,13 @@ EventHandlerFactory::EventHandlerFactory(QString handler, QObject *parent) eventHandler = new XTestEventHandler(this); #endif + +#if defined(Q_OS_WIN) + if (handler == "sendinput") + { + eventHandler = new WinSendInputEventHandler(this); + } +#endif } EventHandlerFactory *EventHandlerFactory::getInstance(QString handler) @@ -84,6 +96,7 @@ BaseEventHandler *EventHandlerFactory::handler() { return eventHandler; } QString EventHandlerFactory::fallBackIdentifier() { +#if defined(Q_OS_UNIX) static QString temp = "xtest"; static bool identifier_obtained = false; if (identifier_obtained) @@ -92,12 +105,12 @@ QString EventHandlerFactory::fallBackIdentifier() bool compiled_with_x11 = false; bool compiled_with_uinput = false; -#if defined(WITH_XTEST) + #if defined(WITH_XTEST) compiled_with_x11 = true; -#endif -#if defined(WITH_UINPUT) + #endif + #if defined(WITH_UINPUT) compiled_with_uinput = true; -#endif + #endif if (detected_xdg_session == "wayland") { @@ -116,15 +129,21 @@ QString EventHandlerFactory::fallBackIdentifier() qWarning() << "Neither uinput nor xtest support is detected."; identifier_obtained = true; return temp; +#elif defined(Q_OS_WIN) + return "sendinput"; +#endif } QStringList EventHandlerFactory::buildEventGeneratorList() { QStringList temp = QStringList(); +#ifdef Q_OS_WIN + temp.append("sendinput"); +#else temp.append("xtest"); temp.append("uinput"); - +#endif return temp; } diff --git a/src/eventhandlerfactory.h b/src/eventhandlerfactory.h index b20e9a67f..8091402c4 100644 --- a/src/eventhandlerfactory.h +++ b/src/eventhandlerfactory.h @@ -30,20 +30,39 @@ #include "eventhandlers/xtesteventhandler.h" #endif -#ifdef WITH_XTEST - #define ADD_XTEST 1 -#else - #define ADD_XTEST 0 +#ifdef Q_OS_WIN + #include "eventhandlers/winsendinputeventhandler.h" + + #ifdef WITH_VMULTI + #include "eventhandlers/winvmultieventhandler.h" + #endif #endif -#ifdef WITH_UINPUT - #define ADD_UINPUT 1 +#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 - #define ADD_UINPUT 0 + #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 -#define NUM_BACKENDS (ADD_XTEST + ADD_UINPUT) - #if (NUM_BACKENDS > 1) #define BACKEND_ELSE_IF else if #else diff --git a/src/eventhandlers/winsendinputeventhandler.cpp b/src/eventhandlers/winsendinputeventhandler.cpp new file mode 100644 index 000000000..f969e0a90 --- /dev/null +++ b/src/eventhandlers/winsendinputeventhandler.cpp @@ -0,0 +1,219 @@ +/* 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)); + } + } + } +} diff --git a/src/eventhandlers/winsendinputeventhandler.h b/src/eventhandlers/winsendinputeventhandler.h new file mode 100644 index 000000000..536814c85 --- /dev/null +++ b/src/eventhandlers/winsendinputeventhandler.h @@ -0,0 +1,49 @@ +/* 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 diff --git a/src/eventhandlers/winvmultieventhandler.cpp b/src/eventhandlers/winvmultieventhandler.cpp new file mode 100644 index 000000000..3e900b5d7 --- /dev/null +++ b/src/eventhandlers/winvmultieventhandler.cpp @@ -0,0 +1,371 @@ +/* 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"); } diff --git a/src/eventhandlers/winvmultieventhandler.h b/src/eventhandlers/winvmultieventhandler.h new file mode 100644 index 000000000..e236e26a8 --- /dev/null +++ b/src/eventhandlers/winvmultieventhandler.h @@ -0,0 +1,69 @@ +/* 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 "winsendinputeventhandler.h" +#include + +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 diff --git a/src/joycontrolstick.cpp b/src/joycontrolstick.cpp index c7a3c470f..f2e8606b9 100644 --- a/src/joycontrolstick.cpp +++ b/src/joycontrolstick.cpp @@ -33,6 +33,8 @@ #include //#include +#include + const JoyControlStick::JoyMode JoyControlStick::DEFAULTMODE = JoyControlStick::StandardMode; JoyControlStick::JoyControlStick(JoyAxis *axis1, JoyAxis *axis2, int index, int originset, QObject *parent) diff --git a/src/main.cpp b/src/main.cpp index 6cf16df0b..ececb5c2f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -479,6 +479,22 @@ int main(int argc, char *argv[]) QTranslator qtTranslator; #if defined(Q_OS_UNIX) + // Have program handle SIGTERM + struct sigaction termaction; + termaction.sa_handler = &termSignalTermHandler; + sigemptyset(&termaction.sa_mask); + termaction.sa_flags = 0; + + sigaction(SIGTERM, &termaction, nullptr); + + // Have program handle SIGINT + struct sigaction termint; + termint.sa_handler = &termSignalIntHandler; + sigemptyset(&termint.sa_mask); + termint.sa_flags = 0; + + sigaction(SIGINT, &termint, nullptr); + QString transPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath); if (QDir(transPath).entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries).count() == 0) @@ -505,22 +521,6 @@ int main(int argc, char *argv[]) antimicrox.installTranslator(&myappTranslator); - // Have program handle SIGTERM - struct sigaction termaction; - termaction.sa_handler = &termSignalTermHandler; - sigemptyset(&termaction.sa_mask); - termaction.sa_flags = 0; - - sigaction(SIGTERM, &termaction, nullptr); - - // Have program handle SIGINT - struct sigaction termint; - termint.sa_handler = &termSignalIntHandler; - sigemptyset(&termint.sa_mask); - termint.sa_flags = 0; - - sigaction(SIGINT, &termint, nullptr); - if (cmdutility.shouldListControllers()) { QPointer joypad_worker = new InputDaemon(joysticks, &settings, false); diff --git a/src/qtwinkeymapper.cpp b/src/qtwinkeymapper.cpp index 179e51782..c43ffaa8e 100644 --- a/src/qtwinkeymapper.cpp +++ b/src/qtwinkeymapper.cpp @@ -21,6 +21,7 @@ #include "qtwinkeymapper.h" #include "winextras.h" +#include static QHash initDynamicKeyMapping() { @@ -120,131 +121,131 @@ QtWinKeyMapper::QtWinKeyMapper(QObject *parent) void QtWinKeyMapper::populateMappingHashes() { - if (qtKeyToVirtualKey.isEmpty()) + if (qtKeyToVirtKeyHash.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; + qtKeyToVirtKeyHash[Qt::Key_Cancel] = VK_CANCEL; + qtKeyToVirtKeyHash[Qt::Key_Backspace] = VK_BACK; + qtKeyToVirtKeyHash[Qt::Key_Tab] = VK_TAB; + qtKeyToVirtKeyHash[Qt::Key_Clear] = VK_CLEAR; + qtKeyToVirtKeyHash[Qt::Key_Return] = VK_RETURN; + qtKeyToVirtKeyHash[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; + qtKeyToVirtKeyHash[Qt::Key_Pause] = VK_PAUSE; + qtKeyToVirtKeyHash[Qt::Key_CapsLock] = VK_CAPITAL; + qtKeyToVirtKeyHash[Qt::Key_Escape] = VK_ESCAPE; + qtKeyToVirtKeyHash[Qt::Key_Mode_switch] = VK_MODECHANGE; + qtKeyToVirtKeyHash[Qt::Key_Space] = VK_SPACE; + qtKeyToVirtKeyHash[Qt::Key_PageUp] = VK_PRIOR; + qtKeyToVirtKeyHash[Qt::Key_PageDown] = VK_NEXT; + qtKeyToVirtKeyHash[Qt::Key_End] = VK_END; + qtKeyToVirtKeyHash[Qt::Key_Home] = VK_HOME; + qtKeyToVirtKeyHash[Qt::Key_Left] = VK_LEFT; + qtKeyToVirtKeyHash[Qt::Key_Up] = VK_UP; + qtKeyToVirtKeyHash[Qt::Key_Right] = VK_RIGHT; + qtKeyToVirtKeyHash[Qt::Key_Down] = VK_DOWN; + qtKeyToVirtKeyHash[Qt::Key_Select] = VK_SELECT; + qtKeyToVirtKeyHash[Qt::Key_Printer] = VK_PRINT; + qtKeyToVirtKeyHash[Qt::Key_Execute] = VK_EXECUTE; + qtKeyToVirtKeyHash[Qt::Key_Print] = VK_SNAPSHOT; + qtKeyToVirtKeyHash[Qt::Key_Insert] = VK_INSERT; + qtKeyToVirtKeyHash[Qt::Key_Delete] = VK_DELETE; + qtKeyToVirtKeyHash[Qt::Key_Help] = VK_HELP; + qtKeyToVirtKeyHash[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; + qtKeyToVirtKeyHash[Qt::Key_Menu] = VK_APPS; + qtKeyToVirtKeyHash[Qt::Key_Sleep] = VK_SLEEP; + + qtKeyToVirtKeyHash[AntKey_KP_Multiply] = VK_MULTIPLY; + // qtKeyToVirtKeyHash[Qt::Key_Asterisk] = VK_MULTIPLY; + qtKeyToVirtKeyHash[AntKey_KP_Add] = VK_ADD; + // qtKeyToVirtKeyHash[Qt::Key_Comma] = VK_SEPARATOR; + qtKeyToVirtKeyHash[AntKey_KP_Subtract] = VK_SUBTRACT; + qtKeyToVirtKeyHash[AntKey_KP_Decimal] = VK_DECIMAL; + qtKeyToVirtKeyHash[AntKey_KP_Divide] = VK_DIVIDE; + + qtKeyToVirtKeyHash[Qt::Key_NumLock] = VK_NUMLOCK; + qtKeyToVirtKeyHash[Qt::Key_ScrollLock] = VK_SCROLL; + qtKeyToVirtKeyHash[Qt::Key_Massyo] = VK_OEM_FJ_MASSHOU; + qtKeyToVirtKeyHash[Qt::Key_Touroku] = VK_OEM_FJ_TOUROKU; + + qtKeyToVirtKeyHash[Qt::Key_Shift] = VK_LSHIFT; // qtKeyToWinVirtualKey[Qt::Key_Shift] = VK_RSHIFT; - qtKeyToVirtualKey[Qt::Key_Control] = VK_LCONTROL; + qtKeyToVirtKeyHash[Qt::Key_Control] = VK_LCONTROL; // qtKeyToWinVirtualKey[Qt::Key_Control] = VK_RCONTROL; - qtKeyToVirtualKey[Qt::Key_Alt] = VK_LMENU; + qtKeyToVirtKeyHash[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; + qtKeyToVirtKeyHash[Qt::Key_Back] = VK_BROWSER_BACK; + qtKeyToVirtKeyHash[Qt::Key_Forward] = VK_BROWSER_FORWARD; + qtKeyToVirtKeyHash[Qt::Key_Refresh] = VK_BROWSER_REFRESH; + qtKeyToVirtKeyHash[Qt::Key_Stop] = VK_BROWSER_STOP; + qtKeyToVirtKeyHash[Qt::Key_Search] = VK_BROWSER_SEARCH; + qtKeyToVirtKeyHash[Qt::Key_Favorites] = VK_BROWSER_FAVORITES; + qtKeyToVirtKeyHash[Qt::Key_HomePage] = VK_BROWSER_HOME; + qtKeyToVirtKeyHash[Qt::Key_VolumeMute] = VK_VOLUME_MUTE; + qtKeyToVirtKeyHash[Qt::Key_VolumeDown] = VK_VOLUME_DOWN; + qtKeyToVirtKeyHash[Qt::Key_VolumeUp] = VK_VOLUME_UP; + qtKeyToVirtKeyHash[Qt::Key_MediaNext] = VK_MEDIA_NEXT_TRACK; + qtKeyToVirtKeyHash[Qt::Key_MediaPrevious] = VK_MEDIA_PREV_TRACK; + qtKeyToVirtKeyHash[Qt::Key_MediaStop] = VK_MEDIA_STOP; + qtKeyToVirtKeyHash[Qt::Key_MediaPlay] = VK_MEDIA_PLAY_PAUSE; + qtKeyToVirtKeyHash[Qt::Key_LaunchMail] = VK_LAUNCH_MAIL; + qtKeyToVirtKeyHash[Qt::Key_LaunchMedia] = VK_LAUNCH_MEDIA_SELECT; + qtKeyToVirtKeyHash[Qt::Key_Launch0] = VK_LAUNCH_APP1; + qtKeyToVirtKeyHash[Qt::Key_Launch1] = VK_LAUNCH_APP2; + qtKeyToVirtKeyHash[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; + qtKeyToVirtKeyHash[Qt::Key_Equal] = VK_OEM_PLUS; + qtKeyToVirtKeyHash[Qt::Key_Minus] = VK_OEM_MINUS; + qtKeyToVirtKeyHash[Qt::Key_Period] = VK_OEM_PERIOD; + qtKeyToVirtKeyHash[Qt::Key_Comma] = VK_OEM_COMMA; + /*qtKeyToVirtKeyHash[Qt::Key_Semicolon] = VK_OEM_1; + qtKeyToVirtKeyHash[Qt::Key_Slash] = VK_OEM_2; + qtKeyToVirtKeyHash[Qt::Key_Equal] = VK_OEM_PLUS; + qtKeyToVirtKeyHash[Qt::Key_Minus] = VK_OEM_MINUS; + qtKeyToVirtKeyHash[Qt::Key_Period] = VK_OEM_PERIOD; + qtKeyToVirtKeyHash[Qt::Key_QuoteLeft] = VK_OEM_3; + qtKeyToVirtKeyHash[Qt::Key_BracketLeft] = VK_OEM_4; + qtKeyToVirtKeyHash[Qt::Key_Backslash] = VK_OEM_5; + qtKeyToVirtKeyHash[Qt::Key_BracketRight] = VK_OEM_6; + qtKeyToVirtKeyHash[Qt::Key_Apostrophe] = VK_OEM_7;*/ + + qtKeyToVirtKeyHash[Qt::Key_Play] = VK_PLAY; + qtKeyToVirtKeyHash[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; + qtKeyToVirtKeyHash[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; + qtKeyToVirtKeyHash[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; + qtKeyToVirtKeyHash[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; + qtKeyToVirtKeyHash[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; + qtKeyToVirtKeyHash[AntKey_Alt_R] = VK_RMENU; + qtKeyToVirtKeyHash[AntKey_Meta_R] = VK_RWIN; + qtKeyToVirtKeyHash[AntKey_Shift_R] = VK_RSHIFT; + qtKeyToVirtKeyHash[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 @@ -303,35 +304,35 @@ void QtWinKeyMapper::populateMappingHashes() { iterDynamic.next(); unsigned int tempvalue = iterDynamic.value(); - if (tempvalue != 0 && !qtKeyToVirtualKey.contains(tempvalue)) + if (tempvalue != 0 && !qtKeyToVirtKeyHash.contains(tempvalue)) { - qtKeyToVirtualKey.insert(tempvalue, iterDynamic.key()); + qtKeyToVirtKeyHash.insert(tempvalue, iterDynamic.key()); } } // Populate other hash. Flip key and value so mapping // goes VK -> Qt Key. - QHashIterator iter(qtKeyToVirtualKey); + QHashIterator iter(qtKeyToVirtKeyHash); while (iter.hasNext()) { iter.next(); - virtualKeyToQtKey[iter.value()] = iter.key(); + virtKeyToQtKeyHash[iter.value()] = iter.key(); } // Override current item for VK_RETURN - virtualKeyToQtKey[VK_RETURN] = Qt::Key_Return; + virtKeyToQtKeyHash[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; + virtKeyToQtKeyHash[VK_SHIFT] = Qt::Key_Shift; + virtKeyToQtKeyHash[VK_CONTROL] = Qt::Key_Control; + virtKeyToQtKeyHash[VK_MENU] = Qt::Key_Alt; } } int QtWinKeyMapper::returnQtKey(int key, int scancode) { - int tempkey = virtualKeyToQtKey.value(key); + int tempkey = virtKeyToQtKeyHash.value(key); int extended = scancode & WinExtras::EXTENDED_FLAG; if (key == VK_RETURN && extended) { @@ -343,7 +344,7 @@ int QtWinKeyMapper::returnQtKey(int key, int scancode) void QtWinKeyMapper::populateCharKeyInformation() { - virtualkeyToCharKeyInformation.clear(); + virtkeyToCharKeyInfo.clear(); unsigned int total = 0; // BYTE ks[256]; @@ -394,9 +395,9 @@ void QtWinKeyMapper::populateCharKeyInformation() charKeyInformation tempinfo; tempinfo.modifiers = dicis; tempinfo.virtualkey = i; - if (!virtualkeyToCharKeyInformation.contains(tempchar.unicode())) + if (!virtkeyToCharKeyInfo.contains(tempchar.unicode())) { - virtualkeyToCharKeyInformation.insert(tempchar.unicode(), tempinfo); + virtkeyToCharKeyInfo.insert(tempchar.unicode(), tempinfo); total++; } } diff --git a/src/winextras.cpp b/src/winextras.cpp new file mode 100644 index 000000000..4e6c5be4b --- /dev/null +++ b/src/winextras.cpp @@ -0,0 +1,410 @@ +#define _WIN32_WINNT 0x0600 + +#include + +#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; +} + +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 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]; +} + +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; +} diff --git a/src/winextras.h b/src/winextras.h new file mode 100644 index 000000000..ef127c77a --- /dev/null +++ b/src/winextras.h @@ -0,0 +1,44 @@ +#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 bool containsFileAssociationinRegistry(); + static void writeFileAssocationToRegistry(); + static void removeFileAssociationFromRegistry(); + static bool IsRunningAsAdmin(); + static void disablePointerPrecision(); + static void enablePointerPrecision(); + static bool isUsingEnhancedPointerPrecision(); + static void grabCurrentPointerPrecision(); + 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