diff --git a/.gitignore b/.gitignore index 0c420c07..4fac0931 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.o .*.swp .directory +.vscode *.qm *.diff *.mo diff --git a/CMakeLists.txt b/CMakeLists.txt index 63ef851d..5c44b920 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,10 @@ 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) + if(APPLE) + message("Using cocoa.") + option(WITH_COCOA "Compile with support for Cocoa." ON) + endif(APPLE) option(APPDATA "Build project with AppData file support." OFF) endif(UNIX) @@ -115,9 +119,9 @@ if(UNIX) message("uinput support allowed for simulating events.") endif(WITH_UINPUT) - if(NOT WITH_XTEST AND NOT WITH_UINPUT) + if(NOT WITH_XTEST AND NOT WITH_UINPUT AND NOT WITH_COCOA) message(FATAL_ERROR "No system is defined for simulating events.") - endif(NOT WITH_XTEST AND NOT WITH_UINPUT) + endif(NOT WITH_XTEST AND NOT WITH_UINPUT AND NOT WITH_COCOA) endif(UNIX) set(antimicro_SOURCES src/main.cpp @@ -375,6 +379,21 @@ if(UNIX) endif(WITH_XTEST) endif(WITH_X11) + if(WITH_COCOA) + LIST(APPEND antimicro_SOURCES src/qtcocoakeymapper.cpp + src/cocoahelper.cpp + src/eventhandlers/cocoaeventhandler.mm + src/cocoaappdelegateadapter.mm + src/cocoaappdelegate.m + src/capturedwindowinfodialog.cpp + ) + LIST(APPEND antimicro_HEADERS src/qtcocoakeymapper.h + src/cocoahelper.h + src/eventhandlers/cocoaeventhandler.h + src/capturedwindowinfodialog.h + ) + endif(WITH_COCOA) + if(WITH_UINPUT) LIST(APPEND antimicro_SOURCES src/qtuinputkeymapper.cpp src/uinputhelper.cpp @@ -484,6 +503,10 @@ if(UNIX) if(WITH_UINPUT) add_definitions(-DWITH_UINPUT) endif(WITH_UINPUT) + + if(WITH_COCOA) + add_definitions(-DWITH_COCOA) + endif(WITH_COCOA) endif(UNIX) if (UNIX) @@ -577,6 +600,11 @@ elseif(WIN32) endif(UNIX) if(UNIX) + if(WITH_COCOA) + FIND_LIBRARY(COCOA_LIBRARY Cocoa) + LIST(APPEND LIBS ${COCOA_LIBRARY}) + endif(WITH_COCOA) + if(WITH_X11) LIST(APPEND LIBS ${X11_X11_LIB}) LIST(APPEND LIBS ${X11_Xi_LIB}) @@ -588,6 +616,7 @@ if(UNIX) if(USE_SDL_2) list(APPEND LIBS ${SDL2_LIBRARIES}) + link_directories(${SDL2_LIBRARY_DIRS}) else() list(APPEND LIBS ${SDL_LIBRARIES}) endif(USE_SDL_2) @@ -668,10 +697,25 @@ endif(UNIX) if(USE_QT5) if(UNIX) - add_executable(antimicro ${antimicro_SOURCES} - ${antimicro_FORMS_HEADERS} - ${antimicro_RESOURCES_RCC} - ) + if(APPLE) + + set (ICON_NAME antimicro.icns) + set (ICON_PATH ${PROJECT_SOURCE_DIR}/src/images/${ICON_NAME}) + set (BUILD_FLAGS MACOSX_BUNDLE) + set (MACOSX_BUNDLE_ICON_FILE ${ICON_NAME}) + set_source_files_properties (${ICON_PATH} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) + add_executable(antimicro ${BUILD_FLAGS} + ${antimicro_SOURCES} + ${antimicro_FORMS_HEADERS} + ${antimicro_RESOURCES_RCC} + ${ICON_PATH} + ) + else() + add_executable(antimicro ${antimicro_SOURCES} + ${antimicro_FORMS_HEADERS} + ${antimicro_RESOURCES_RCC} + ) + endif(APPLE) elseif(WIN32) # The WIN32 is required to specify a GUI application. add_executable(antimicro WIN32 ${antimicro_SOURCES} @@ -696,9 +740,11 @@ target_link_libraries(antimicro ${LIBS}) # Specify out directory for final executable. if(UNIX) - install(TARGETS antimicro RUNTIME DESTINATION "bin") + if(NOT APPLE) + install(TARGETS antimicro RUNTIME DESTINATION "bin") + endif(NOT APPLE) elseif(WIN32) - install(TARGETS antimicro RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}) + install(TARGETS antimicro RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}) endif(UNIX) if(UNIX) diff --git a/README.md b/README.md index be9fc422..c98a850d 100644 --- a/README.md +++ b/README.md @@ -291,6 +291,20 @@ Notes about the WXS file and the building process : * built MSI package will be placed in /windows +## Building under macOS + +* Install Qt 5 and SDL2 using [Homebrew](https://brew.sh): `brew install qt sdl2` + +* Create a build directory and invoke CMake: + +```bash +cd antimicro +mkdir build && cd build +CMAKE_PREFIX_PATH=/usr/local/Cellar/qt/YOUR_QT_VERSION cmake .. -DWITH_XTEST=OFF -DWITH_X11=OFF -DWITH_COCOA=ON +make +``` + + ## Testing under Linux If you are having problems with antimicro detecting a controller or diff --git a/src/addeditautoprofiledialog.cpp b/src/addeditautoprofiledialog.cpp index 5d656ba8..6120a9f7 100644 --- a/src/addeditautoprofiledialog.cpp +++ b/src/addeditautoprofiledialog.cpp @@ -39,6 +39,10 @@ #include #endif + #ifdef WITH_COCOA +#include "capturedwindowinfodialog.h" + #endif + #elif defined(Q_OS_WIN) #include "winappprofiletimerdialog.h" #include "capturedwindowinfodialog.h" diff --git a/src/advancebuttondialog.cpp b/src/advancebuttondialog.cpp index 4196981b..8ca351c6 100644 --- a/src/advancebuttondialog.cpp +++ b/src/advancebuttondialog.cpp @@ -227,6 +227,12 @@ AdvanceButtonDialog::AdvanceButtonDialog(JoyButton *button, QWidget *parent) : 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))); + +#ifdef WITH_COCOA + // Not inplemented + ui->slotTypeComboBox->removeItem(TextEntry); +#endif + } AdvanceButtonDialog::~AdvanceButtonDialog() diff --git a/src/antkeymapper.cpp b/src/antkeymapper.cpp index 39d4e739..b656f1bd 100644 --- a/src/antkeymapper.cpp +++ b/src/antkeymapper.cpp @@ -41,6 +41,9 @@ static QStringList buildEventGeneratorList() #ifdef WITH_UINPUT temp.append("uinput"); #endif + #ifdef WITH_COCOA + temp.append("cocoa"); + #endif #endif return temp; @@ -75,6 +78,14 @@ AntKeyMapper::AntKeyMapper(QString handler, QObject *parent) : } #endif + #ifdef WITH_COCOA + if (handler == "cocoa") + { + internalMapper = &cocoaMapper; + nativeKeyMapper = 0; + } + #endif + #ifdef WITH_UINPUT if (handler == "uinput") { diff --git a/src/antkeymapper.h b/src/antkeymapper.h index c27bb7be..d7945e42 100644 --- a/src/antkeymapper.h +++ b/src/antkeymapper.h @@ -35,6 +35,10 @@ #if defined(WITH_UINPUT) #include "qtuinputkeymapper.h" #endif + + #if defined(WITH_COCOA) + #include "qtcocoakeymapper.h" + #endif #endif class AntKeyMapper : public QObject @@ -74,6 +78,10 @@ class AntKeyMapper : public QObject QtUInputKeyMapper uinputMapper; #endif + #if defined(WITH_COCOA) + QtCocoaKeyMapper cocoaMapper; + #endif + #endif signals: diff --git a/src/buttoneditdialog.cpp b/src/buttoneditdialog.cpp index 6f60b293..b2583c30 100644 --- a/src/buttoneditdialog.cpp +++ b/src/buttoneditdialog.cpp @@ -207,6 +207,10 @@ void ButtonEditDialog::keyReleaseEvent(QKeyEvent *event) checkalias = AntKeyMapper::getInstance()->returnQtKey(finalvirtual, controlcode); } +#elif defined(WITH_COCOA) + int finalvirtual = 0; + int checkalias = 0; + virtualactual = event->key(); #else #if defined(WITH_X11) diff --git a/src/capturedwindowinfodialog.cpp b/src/capturedwindowinfodialog.cpp index 66e9e550..450dce96 100644 --- a/src/capturedwindowinfodialog.cpp +++ b/src/capturedwindowinfodialog.cpp @@ -22,7 +22,7 @@ #ifdef Q_OS_WIN #include "winextras.h" -#else +#elif defined(WITH_X11) #include "x11extras.h" #endif @@ -39,7 +39,7 @@ CapturedWindowInfoDialog::CapturedWindowInfoDialog(unsigned long window, QWidget selectedMatch = WindowNone; -#ifdef Q_OS_UNIX +#if defined(Q_OS_UNIX) && defined(WITH_X11) X11Extras *info = X11Extras::getInstance(); ui->winPathChoiceComboBox->setVisible(false); #endif @@ -51,7 +51,7 @@ CapturedWindowInfoDialog::CapturedWindowInfoDialog(unsigned long window, QWidget ui->winClassCheckBox->setVisible(false); ui->winClassLabel->setVisible(false); ui->winClassHeadLabel->setVisible(false); -#else +#elif defined(Q_OS_UNIX) && defined(WITH_X11) winClass = info->getWindowClass(window); ui->winClassLabel->setText(winClass); if (winClass.isEmpty()) @@ -71,7 +71,7 @@ CapturedWindowInfoDialog::CapturedWindowInfoDialog(unsigned long window, QWidget #ifdef Q_OS_WIN winName = WinExtras::getCurrentWindowText(); -#else +#elif defined(Q_OS_UNIX) && defined(WITH_X11) winName = info->getWindowTitle(window); #endif diff --git a/src/cocoaappdelegate.h b/src/cocoaappdelegate.h new file mode 100644 index 00000000..e69efb12 --- /dev/null +++ b/src/cocoaappdelegate.h @@ -0,0 +1,22 @@ +/* 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 . + */ + +#import + +@interface CocoaAppDelegate : NSObject + +@end diff --git a/src/cocoaappdelegate.m b/src/cocoaappdelegate.m new file mode 100644 index 00000000..1392d664 --- /dev/null +++ b/src/cocoaappdelegate.m @@ -0,0 +1,59 @@ +/* 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 . + */ + +#import "cocoaappdelegate.h" + +@interface CocoaAppDelegate () + +@property(nonatomic) id activityToken; + +- (void)disableAppNap; + +@end + +@implementation CocoaAppDelegate + +- (void)dealloc +{ + [super dealloc]; +} + +- (void)disableAppNap +{ + NSActivityOptions options = NSActivityUserInitiatedAllowingIdleSystemSleep; + id activity = [[NSProcessInfo processInfo] beginActivityWithOptions:options reason:@"Disabled AppNap"]; + [self setActivityToken:activity]; + [[self activityToken] retain]; + NSLog(@"Disabled AppNap"); +} + +- (void)applicationDidFinishLaunching:(NSNotification*)notification +{ + [self disableAppNap]; +} + +- (void)applicationWillTerminate:(NSNotification*)notification +{ + [[NSProcessInfo processInfo] endActivity:[self activityToken]]; + if ([self activityToken] != nil) { + [[self activityToken] release]; + [self setActivityToken:nil]; + } + NSLog(@"Terminating application!"); +} + +@end diff --git a/src/cocoaappdelegateadapter.h b/src/cocoaappdelegateadapter.h new file mode 100644 index 00000000..597f6251 --- /dev/null +++ b/src/cocoaappdelegateadapter.h @@ -0,0 +1,35 @@ +/* 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 COCOAAPPDELEGATEINTERFACE_H +#define COCOAAPPDELEGATEINTERFACE_H + +#import + +class CocoaAppDelegateAdapter : public QObject +{ + Q_OBJECT +public: + explicit CocoaAppDelegateAdapter(QObject *parent = 0); + virtual ~CocoaAppDelegateAdapter(); + + void registerDelegate(); +private: + void *delegate; +}; + +#endif // COCOAAPPDELEGATEINTERFACE_H diff --git a/src/cocoaappdelegateadapter.mm b/src/cocoaappdelegateadapter.mm new file mode 100644 index 00000000..83a90993 --- /dev/null +++ b/src/cocoaappdelegateadapter.mm @@ -0,0 +1,36 @@ +/* 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 "cocoaappdelegateadapter.h" + +#import +#import "cocoaappdelegate.h" + +CocoaAppDelegateAdapter::CocoaAppDelegateAdapter(QObject *parent) : QObject(parent) +{ + delegate = [[CocoaAppDelegate alloc] init]; +} + +CocoaAppDelegateAdapter::~CocoaAppDelegateAdapter() +{ +} + +void CocoaAppDelegateAdapter::registerDelegate() +{ + [[NSApplication sharedApplication] setDelegate:(id) delegate]; + NSLog(@"Registered AppDelegate!"); +} diff --git a/src/cocoahelper.cpp b/src/cocoahelper.cpp new file mode 100644 index 00000000..cac36347 --- /dev/null +++ b/src/cocoahelper.cpp @@ -0,0 +1,341 @@ +/* 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 "cocoahelper.h" +#include + +struct T3{ + const unsigned int code; + const QString displaystring; + const QString codestring; +}; + +struct T2{ + const unsigned int qtcode; + const unsigned int cocoacode; +}; + +static const T2 qt_cocoa_map[] = { + {Qt::Key_1, kVK_ANSI_Keypad1}, + {Qt::Key_2, kVK_ANSI_Keypad2}, + {Qt::Key_3, kVK_ANSI_Keypad3}, + {Qt::Key_4, kVK_ANSI_Keypad4}, + {Qt::Key_5, kVK_ANSI_Keypad5}, + {Qt::Key_6, kVK_ANSI_Keypad6}, + {Qt::Key_7, kVK_ANSI_Keypad7}, + {Qt::Key_8, kVK_ANSI_Keypad8}, + {Qt::Key_9, kVK_ANSI_Keypad9}, + {Qt::Key_0, kVK_ANSI_Keypad0}, + {Qt::Key_Slash, kVK_ANSI_KeypadDivide}, + {Qt::Key_Minus, kVK_ANSI_KeypadMinus}, + {Qt::Key_Period, kVK_ANSI_KeypadDecimal}, + {Qt::Key_Shift, kVK_RightShift}, + {Qt::Key_Meta, kVK_RightControl}, + {Qt::Key_Control, kVK_Command}, + {Qt::Key_Option, kVK_RightOption}, + {Qt::Key_1, kVK_ANSI_1}, + {Qt::Key_2, kVK_ANSI_2}, + {Qt::Key_3, kVK_ANSI_3}, + {Qt::Key_4, kVK_ANSI_4}, + {Qt::Key_5, kVK_ANSI_5}, + {Qt::Key_6, kVK_ANSI_6}, + {Qt::Key_7, kVK_ANSI_7}, + {Qt::Key_8, kVK_ANSI_8}, + {Qt::Key_9, kVK_ANSI_9}, + {Qt::Key_0, kVK_ANSI_0}, + {Qt::Key_A, kVK_ANSI_A}, + {Qt::Key_B, kVK_ANSI_B}, + {Qt::Key_C, kVK_ANSI_C}, + {Qt::Key_D, kVK_ANSI_D}, + {Qt::Key_E, kVK_ANSI_E}, + {Qt::Key_F, kVK_ANSI_F}, + {Qt::Key_G, kVK_ANSI_G}, + {Qt::Key_H, kVK_ANSI_H}, + {Qt::Key_I, kVK_ANSI_I}, + {Qt::Key_J, kVK_ANSI_J}, + {Qt::Key_K, kVK_ANSI_K}, + {Qt::Key_L, kVK_ANSI_L}, + {Qt::Key_M, kVK_ANSI_M}, + {Qt::Key_N, kVK_ANSI_N}, + {Qt::Key_O, kVK_ANSI_O}, + {Qt::Key_P, kVK_ANSI_P}, + {Qt::Key_Q, kVK_ANSI_Q}, + {Qt::Key_R, kVK_ANSI_R}, + {Qt::Key_S, kVK_ANSI_S}, + {Qt::Key_T, kVK_ANSI_T}, + {Qt::Key_U, kVK_ANSI_U}, + {Qt::Key_V, kVK_ANSI_V}, + {Qt::Key_W, kVK_ANSI_W}, + {Qt::Key_X, kVK_ANSI_X}, + {Qt::Key_Y, kVK_ANSI_Y}, + {Qt::Key_Z, kVK_ANSI_Z}, + {Qt::Key_F1, kVK_F1}, + {Qt::Key_F2, kVK_F2}, + {Qt::Key_F3, kVK_F3}, + {Qt::Key_F4, kVK_F4}, + {Qt::Key_F5, kVK_F5}, + {Qt::Key_F6, kVK_F6}, + {Qt::Key_F7, kVK_F7}, + {Qt::Key_F8, kVK_F8}, + {Qt::Key_F9, kVK_F9}, + {Qt::Key_F10, kVK_F10}, + {Qt::Key_F11, kVK_F11}, + {Qt::Key_F12, kVK_F12}, + {Qt::Key_F14, kVK_F14}, + {Qt::Key_F15, kVK_F15}, + {Qt::Key_F16, kVK_F16}, + {Qt::Key_Escape, kVK_Escape}, + {Qt::Key_Dead_Grave, kVK_ANSI_Grave}, + {Qt::Key_Minus, kVK_ANSI_Minus}, + {Qt::Key_Equal, kVK_ANSI_Equal}, + {Qt::Key_Backspace, kVK_Delete}, + {Qt::Key_Tab, kVK_Tab}, + {Qt::Key_BracketLeft, kVK_ANSI_LeftBracket}, + {Qt::Key_BracketRight, kVK_ANSI_RightBracket}, + {Qt::Key_Backslash, kVK_ANSI_Backslash}, + {Qt::Key_CapsLock, kVK_CapsLock}, + {Qt::Key_Semicolon, kVK_ANSI_Semicolon}, + {Qt::Key_QuoteDbl, kVK_ANSI_Quote}, + {Qt::Key_Return, kVK_Return}, + {Qt::Key_Shift, kVK_Shift}, + {Qt::Key_Comma, kVK_ANSI_Comma}, + {Qt::Key_Period, kVK_ANSI_Period}, + {Qt::Key_Slash, kVK_ANSI_Slash}, + {Qt::Key_Meta, kVK_Control}, + {Qt::Key_Control, kVK_Command}, + {Qt::Key_Menu, kVK_Command}, + {Qt::Key_Option, kVK_Option}, + {Qt::Key_Space, kVK_Space}, + {Qt::Key_Up, kVK_UpArrow}, + {Qt::Key_Left, kVK_LeftArrow}, + {Qt::Key_Down, kVK_DownArrow}, + {Qt::Key_Right, kVK_RightArrow}, + {Qt::Key_Help, kVK_Help}, + {Qt::Key_Delete, kVK_ForwardDelete}, + {Qt::Key_Home, kVK_Home}, + {Qt::Key_End, kVK_End}, + {Qt::Key_PageUp, kVK_PageUp}, + {Qt::Key_PageDown, kVK_PageDown}, + {Qt::Key_Enter, kVK_ANSI_KeypadEnter}, + {Qt::Key_Clear, kVK_ANSI_KeypadClear}, + {Qt::Key_Asterisk, kVK_ANSI_KeypadMultiply}, + {Qt::Key_Plus, kVK_ANSI_KeypadPlus}, +}; + +static const T3 keys[] = { + {Qt::Key_1, "KP_1", "KP_1"}, + {Qt::Key_2, "KP_2", "KP_2"}, + {Qt::Key_3, "KP_3", "KP_3"}, + {Qt::Key_4, "KP_4", "KP_4"}, + {Qt::Key_5, "KP_5", "KP_5"}, + {Qt::Key_6, "KP_6", "KP_6"}, + {Qt::Key_7, "KP_7", "KP_7"}, + {Qt::Key_8, "KP_8", "KP_8"}, + {Qt::Key_9, "KP_9", "KP_9"}, + {Qt::Key_0, "KP_0", "KP_0"}, + {Qt::Key_Slash, "/", "KP_Divide"}, + {Qt::Key_Minus, "-", "KP_Subtract"}, + {Qt::Key_Period, ".", "KP_Decimal"}, + {Qt::Key_Shift, "Shift_R", "Shift_R"}, + {Qt::Key_Meta, "Ctrl_R", "Control_R"}, + {Qt::Key_Control, "Super_R", "Super_R"}, + {Qt::Key_Option, "Alt_R", "Alt_R"}, + {Qt::Key_1, "1", "1"}, + {Qt::Key_2, "2", "2"}, + {Qt::Key_3, "3", "3"}, + {Qt::Key_4, "4", "4"}, + {Qt::Key_5, "5", "5"}, + {Qt::Key_6, "6", "6"}, + {Qt::Key_7, "7", "7"}, + {Qt::Key_8, "8", "8"}, + {Qt::Key_9, "9", "9"}, + {Qt::Key_0, "0", "0"}, + {Qt::Key_A, "a", "a"}, + {Qt::Key_B, "b", "b"}, + {Qt::Key_C, "c", "c"}, + {Qt::Key_D, "d", "d"}, + {Qt::Key_E, "e", "e"}, + {Qt::Key_F, "f", "f"}, + {Qt::Key_G, "g", "g"}, + {Qt::Key_H, "h", "h"}, + {Qt::Key_I, "i", "i"}, + {Qt::Key_J, "j", "j"}, + {Qt::Key_K, "k", "k"}, + {Qt::Key_L, "l", "l"}, + {Qt::Key_M, "m", "m"}, + {Qt::Key_N, "n", "n"}, + {Qt::Key_O, "o", "o"}, + {Qt::Key_P, "p", "p"}, + {Qt::Key_Q, "q", "q"}, + {Qt::Key_R, "r", "r"}, + {Qt::Key_S, "s", "s"}, + {Qt::Key_T, "t", "t"}, + {Qt::Key_U, "u", "u"}, + {Qt::Key_V, "v", "v"}, + {Qt::Key_W, "w", "w"}, + {Qt::Key_X, "x", "x"}, + {Qt::Key_Y, "y", "y"}, + {Qt::Key_Z, "z", "z"}, + {Qt::Key_F1, "F1", "F1"}, + {Qt::Key_F2, "F2", "F2"}, + {Qt::Key_F3, "F3", "F3"}, + {Qt::Key_F4, "F4", "F4"}, + {Qt::Key_F5, "F5", "F5"}, + {Qt::Key_F6, "F6", "F6"}, + {Qt::Key_F7, "F7", "F7"}, + {Qt::Key_F8, "F8", "F8"}, + {Qt::Key_F9, "F9", "F9"}, + {Qt::Key_F10, "F10", "F10"}, + {Qt::Key_F11, "F11", "F11"}, + {Qt::Key_F12, "F12", "F12"}, + {Qt::Key_F14, "PrtSc", "Print"}, + {Qt::Key_F15, "SCLK", "Scroll_Lock"}, + {Qt::Key_F16, "Pause", "Pause"}, + {Qt::Key_Escape, "Esc", "Escape"}, + {Qt::Key_Dead_Grave, "`", "grave"}, + {Qt::Key_Minus, "-", "minus"}, + {Qt::Key_Equal, "=", "equal"}, + {Qt::Key_Backspace, "BackSpace", "BackSpace"}, + {Qt::Key_Tab, "Tab", "Tab"}, + {Qt::Key_BracketLeft, "[", "bracketleft"}, + {Qt::Key_BracketRight, "]", "bracketright"}, + {Qt::Key_Backslash, "\\", "backslash"}, + {Qt::Key_CapsLock, "CapsLock", "Caps_Lock"}, + {Qt::Key_Semicolon, ";", "semicolon"}, + {Qt::Key_QuoteDbl, "'", "apostrophe"}, + {Qt::Key_Return, "Enter", "Return"}, + {Qt::Key_Shift, "Shift_L", "Shift_L"}, + {Qt::Key_Comma, ",", "comma"}, + {Qt::Key_Period, ".", "period"}, + {Qt::Key_Slash, "/", "slash"}, + {Qt::Key_Meta, "Ctrl_L", "Control_L"}, + {Qt::Key_Control, "Super_L", "Super_L"}, + {Qt::Key_Menu, "Menu", "Menu"}, + {Qt::Key_Option, "Alt_L", "Alt_L"}, + {Qt::Key_Space, "Space", "space"}, + {Qt::Key_Up, "Up", "Up"}, + {Qt::Key_Left, "Left", "Left"}, + {Qt::Key_Down, "Down", "Down"}, + {Qt::Key_Right, "Right", "Right"}, + {Qt::Key_Help, "Ins", "Insert"}, + {Qt::Key_Delete, "Del", "Delete"}, + {Qt::Key_Home, "Home", "Home"}, + {Qt::Key_End, "End", "End"}, + {Qt::Key_PageUp, "PgUp", "Prior"}, + {Qt::Key_PageDown, "PgDn", "Next"}, + {Qt::Key_Enter, "KP_Enter", "KP_Enter"}, + {Qt::Key_Clear, "NumLock", "Num_Lock"}, + {Qt::Key_Asterisk, "*", "KP_Multiply"}, + {Qt::Key_Plus, "+", "KP_Add"}, +}; + +CocoaHelper* CocoaHelper::_instance = 0; + +CocoaHelper::CocoaHelper(QObject *parent) : + QObject(parent) +{ + populateKnownAliases(); + connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(deleteLater())); +} + +CocoaHelper::~CocoaHelper() +{ + _instance = 0; +} + +void CocoaHelper::populateKnownAliases() +{ + if (knownAliasesX11SymVK.isEmpty()) + { + for (int i = 0; i < sizeof(keys)/sizeof(T3); i++){ + knownAliasesX11SymVK.insert(keys[i].codestring, keys[i].code); + } + } + + if (knownAliasesVKStrings.isEmpty()) + { + for (int i = 0; i < sizeof(keys)/sizeof(T3); i++){ + knownAliasesVKStrings.insert(keys[i].code, tr(keys[i].displaystring.toStdString().c_str())); + } + } + + if (knownCocoaCode.isEmpty()) + { + for (int i = 0; i < sizeof(qt_cocoa_map)/sizeof(T2); i++){ + knownCocoaCode.insert(qt_cocoa_map[i].qtcode, qt_cocoa_map[i].cocoacode); + } + } +} + +CocoaHelper* CocoaHelper::getInstance() +{ + if (!_instance) + { + _instance = new CocoaHelper(); + } + + return _instance; +} + +void CocoaHelper::deleteInstance() +{ + if (_instance) + { + delete _instance; + _instance = 0; + } +} + +QString CocoaHelper::getDisplayString(unsigned int virtualkey) +{ + QString temp; + + if (knownAliasesVKStrings.contains(virtualkey)) + { + temp = knownAliasesVKStrings.value(virtualkey); + } + else + { + temp = tr("[NO KEY]"); + } + + return temp; +} + +unsigned int CocoaHelper::getVirtualKey(QString codestring) +{ + int temp = 0; + if (knownAliasesX11SymVK.contains(codestring)) + { + temp = knownAliasesX11SymVK.value(codestring); + } + + return temp; +} + +unsigned int CocoaHelper::getCocoaVirtualKey(int qtcode) +{ + unsigned int temp = -1; + if (knownCocoaCode.contains(qtcode)) + { + temp = knownCocoaCode.value(qtcode); + } + + return temp; +} diff --git a/src/cocoahelper.h b/src/cocoahelper.h new file mode 100644 index 00000000..96b985f9 --- /dev/null +++ b/src/cocoahelper.h @@ -0,0 +1,48 @@ +/* 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 COCOAHELPER_H +#define COCOAHELPER_H + +#include +#include +#include + +class CocoaHelper : public QObject +{ + Q_OBJECT +public: + static CocoaHelper* getInstance(); + void deleteInstance(); + + QString getDisplayString(unsigned int virtualkey); + unsigned int getVirtualKey(QString codestring); + unsigned int getCocoaVirtualKey(int qtcode); + +protected: + explicit CocoaHelper(QObject *parent = 0); + ~CocoaHelper(); + + void populateKnownAliases(); + + static CocoaHelper *_instance; + QHash knownAliasesX11SymVK; + QHash knownAliasesVKStrings; + QHash knownCocoaCode; +}; + +#endif // COCOAHELPER_H diff --git a/src/event.cpp b/src/event.cpp index 56f1ff58..0ced3fb4 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -48,6 +48,10 @@ #include "uinputhelper.h" #endif + #if defined(WITH_COCOA) +#include "cocoahelper.h" + #endif + #elif defined (Q_OS_WIN) #include #include "winextras.h" @@ -671,6 +675,13 @@ int X11KeySymToKeycode(QString key) tempcode = UInputHelper::getInstance()->getVirtualKey(key); } #endif + +#ifdef WITH_COCOA + if (handler->getIdentifier() == "cocoa") + { + tempcode = CocoaHelper::getInstance()->getVirtualKey(key); + } +#endif } #elif defined (Q_OS_WIN) @@ -706,7 +717,7 @@ QString keycodeToKeyString(int keycode, unsigned int alias) #if defined (Q_OS_UNIX) Q_UNUSED(alias); - if (keycode <= 0) + if (keycode < 0) { newkey = "[NO KEY]"; } @@ -766,6 +777,22 @@ QString keycodeToKeyString(int keycode, unsigned int alias) } } #endif + +#ifdef WITH_COCOA + if (handler->getIdentifier() == "cocoa") + { + QString tempalias = CocoaHelper::getInstance()->getDisplayString(keycode); + if (!tempalias.isEmpty()) + { + newkey = tempalias; + } + else + { + newkey = QString("0x%1").arg(keycode, 0, 16); + } + } +#endif + } #elif defined (Q_OS_WIN) @@ -825,7 +852,7 @@ QString keysymToKeyString(int keysym, unsigned int alias) { QString newkey; -#if defined (Q_OS_UNIX) +#if defined (Q_OS_UNIX) && defined(WITH_XTEST) Q_UNUSED(alias); BaseEventHandler *handler = EventHandlerFactory::getInstance()->handler(); diff --git a/src/eventhandlerfactory.cpp b/src/eventhandlerfactory.cpp index b0232be2..6d662b4d 100644 --- a/src/eventhandlerfactory.cpp +++ b/src/eventhandlerfactory.cpp @@ -30,6 +30,7 @@ static QHash buildDisplayNames() #else temp.insert("xtest", "Xtest"); temp.insert("uinput", "uinput"); + temp.insert("cocoa", "Cocoa"); #endif return temp; } @@ -55,6 +56,13 @@ EventHandlerFactory::EventHandlerFactory(QString handler, QObject *parent) : eventHandler = new XTestEventHandler(this); } #endif + + #ifdef WITH_COCOA + if (handler == "cocoa") + { + eventHandler = new CocoaEventHandler(this); + } + #endif #elif defined(Q_OS_WIN) if (handler == "sendinput") { @@ -118,6 +126,8 @@ QString EventHandlerFactory::fallBackIdentifier() temp = "xtest"; #elif defined(WITH_UINPUT) temp = "uinput"; + #elif defined(WITH_COCOA) + temp = "cocoa"; #else temp = "xtest"; #endif @@ -140,6 +150,9 @@ QStringList EventHandlerFactory::buildEventGeneratorList() #else temp.append("xtest"); temp.append("uinput"); + #ifdef WITH_COCOA + temp.append("cocoa"); + #endif #endif return temp; } diff --git a/src/eventhandlerfactory.h b/src/eventhandlerfactory.h index 69f7a07d..a9f41448 100644 --- a/src/eventhandlerfactory.h +++ b/src/eventhandlerfactory.h @@ -29,6 +29,12 @@ #ifdef WITH_XTEST #include "eventhandlers/xtesteventhandler.h" #endif + + #ifdef WITH_COCOA + #include "eventhandlers/cocoaeventhandler.h" + #endif + + #elif defined(Q_OS_WIN) #include "eventhandlers/winsendinputeventhandler.h" diff --git a/src/eventhandlers/cocoaeventhandler.h b/src/eventhandlers/cocoaeventhandler.h new file mode 100644 index 00000000..9c39e5ec --- /dev/null +++ b/src/eventhandlers/cocoaeventhandler.h @@ -0,0 +1,32 @@ +#ifndef COCOAEVENTHANDLER_H +#define COCOAEVENTHANDLER_H + +#include "baseeventhandler.h" + +#include + +class CocoaEventHandler : public BaseEventHandler +{ + Q_OBJECT +public: + explicit CocoaEventHandler(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 // COCOAEVENTHANDLER_H diff --git a/src/eventhandlers/cocoaeventhandler.mm b/src/eventhandlers/cocoaeventhandler.mm new file mode 100644 index 00000000..acfa87f8 --- /dev/null +++ b/src/eventhandlers/cocoaeventhandler.mm @@ -0,0 +1,118 @@ +#include "cocoaeventhandler.h" + +#include +#include +#include + +#include +#include + +CocoaEventHandler::CocoaEventHandler(QObject *parent) : BaseEventHandler(parent) +{ +} + +bool CocoaEventHandler::init() +{ + return true; +} + +bool CocoaEventHandler::cleanup() +{ + return true; +} + +void CocoaEventHandler::sendKeyboardEvent(JoyButtonSlot *slot, bool pressed) +{ + int code = CocoaHelper::getInstance()->getCocoaVirtualKey(slot->getSlotCode()); + CGEventRef keyEvent = CGEventCreateKeyboardEvent(NULL, code, pressed); + CGEventPost(kCGHIDEventTap, keyEvent); + CFRelease(keyEvent); +} + +void CocoaEventHandler::sendMouseButtonEvent(JoyButtonSlot *slot, bool pressed) +{ + JoyButtonSlot::JoySlotInputAction device = slot->getSlotMode(); + int code = slot->getSlotCode(); + if (code == 4 || code == 5){ // wheel + CGEventRef wheel = CGEventCreateScrollWheelEvent( + NULL, + kCGScrollEventUnitPixel, // kCGScrollEventUnitLine, + (CGWheelCount) 1, + code==4?15:-15); + + CGEventPost(kCGHIDEventTap, wheel); + CFRelease(wheel); + }else{ + NSRect screenRect = [[NSScreen mainScreen] frame]; + NSInteger height = screenRect.size.height; + NSPoint mouseLoc = [NSEvent mouseLocation]; + CGEventType eventType; + CGMouseButton buttonType; + if (code == 1) + { + eventType = pressed ? kCGEventLeftMouseDown : kCGEventLeftMouseUp; + buttonType = kCGMouseButtonLeft; + } + else if (code == 2) + { + eventType = pressed ? kCGEventOtherMouseDown : kCGEventOtherMouseUp; + buttonType = kCGMouseButtonCenter; + } + else if (code == 3) + { + eventType = pressed ? kCGEventRightMouseDown : kCGEventRightMouseUp; + buttonType = kCGMouseButtonRight; + } + + /* CGEventType eventType = pressed ? kCGEventLeftMouseDown : kCGEventLeftMouseUp; */ + CGEventRef click = CGEventCreateMouseEvent( + NULL, + eventType, + CGPointMake(mouseLoc.x, height - mouseLoc.y), + buttonType); + CGEventPost(kCGHIDEventTap, click); + CFRelease(click); + } +} + +void CocoaEventHandler::sendMouseEvent(int xDis, int yDis) +{ + NSRect screenRect = [[NSScreen mainScreen] frame]; + NSInteger height = screenRect.size.height; + NSPoint mouseLoc = [NSEvent mouseLocation]; + + mouseLoc.x += xDis; + mouseLoc.y -= yDis; + + CGEventRef move = CGEventCreateMouseEvent( + NULL, + kCGEventMouseMoved, + CGPointMake(mouseLoc.x, height - mouseLoc.y), + kCGMouseButtonLeft); + CGEventSetType(move, kCGEventMouseMoved); + CGEventSetIntegerValueField(move, kCGMouseEventDeltaX, xDis); + CGEventSetIntegerValueField(move, kCGMouseEventDeltaY, yDis); + + CGEventPost(kCGHIDEventTap, move); + CFRelease(move); +} + +void CocoaEventHandler::sendMouseAbsEvent(int xDis, int yDis, int screen) +{ + // Not implemented +} + +QString CocoaEventHandler::getName() +{ + return QString("Cocoa"); +} + +QString CocoaEventHandler::getIdentifier() +{ + return QString("cocoa"); +} + +void CocoaEventHandler::sendTextEntryEvent(QString maintext) +{ + // Not implemented +} diff --git a/src/images/antimicro.icns b/src/images/antimicro.icns new file mode 100644 index 00000000..17f5d4de Binary files /dev/null and b/src/images/antimicro.icns differ diff --git a/src/main.cpp b/src/main.cpp index 2bba1279..8040acba 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -43,7 +43,12 @@ #include #include #include "winextras.h" +#endif +#ifdef WITH_COCOA +#include +#include +#include "cocoaappdelegateadapter.h" #endif #include "inputdevice.h" @@ -139,7 +144,7 @@ int main(int argc, char *argv[]) // 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 +#if defined(Q_OS_WIN) || defined(WITH_COCOA) bool styleChangeFound = false; for (int i=0; i < argc && !styleChangeFound; i++) { @@ -199,6 +204,11 @@ int main(int argc, char *argv[]) QDir::setCurrent( PadderCommon::configPath() ); #endif +#ifdef WITH_COCOA + CocoaAppDelegateAdapter cocoaAdapter; + cocoaAdapter.registerDelegate(); +#endif + QDir configDir(PadderCommon::configPath()); if (!configDir.exists()) { @@ -459,7 +469,7 @@ int main(int argc, char *argv[]) // 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 defined(Q_OS_WIN) || defined(WITH_COCOA) if (!styleChangeFound) { qApp->setStyle(QStyleFactory::create("Fusion")); diff --git a/src/mainsettingsdialog.cpp b/src/mainsettingsdialog.cpp index 9c773ae4..d4109b47 100644 --- a/src/mainsettingsdialog.cpp +++ b/src/mainsettingsdialog.cpp @@ -56,7 +56,7 @@ #ifdef Q_OS_WIN #include "eventhandlerfactory.h" #include "winextras.h" -#elif defined(Q_OS_UNIX) +#elif defined(Q_OS_UNIX) && defined(WITH_X11) #include "x11extras.h" #endif @@ -1997,7 +1997,7 @@ void MainSettingsDialog::refreshExtraMouseInfo() { #endif struct X11Extras::ptrInformation temp; - if (handler == "uinput") + if (handler == "uinput" || handler == "cocoa") { temp = X11Extras::getInstance()->getPointInformation(); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 848f57f1..99bcad8e 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -113,6 +113,11 @@ MainWindow::MainWindow(QMap *joysticks, showTrayIcon = !cmdutility->isTrayHidden() && graphical && !cmdutility->shouldListControllers() && !cmdutility->shouldMapController(); +#ifdef WITH_COCOA + showTrayIcon = 0; + ui->menuBar->removeAction(ui->menuQuit->menuAction()); +#endif + this->joysticks = joysticks; if (showTrayIcon) @@ -214,7 +219,6 @@ void MainWindow::alterConfigFromSettings() if (cmdutility->shouldListControllers()) { graphical = false; - this->graphical = graphical; } else if (cmdutility->hasProfile()) { @@ -300,7 +304,6 @@ void MainWindow::controllerMapOpening() if (cmdutility->shouldMapController()) { graphical = false; - this->graphical = graphical; QList *tempList = cmdutility->getControllerOptionsList(); ControllerOptionsInfo temp = tempList->at(0); @@ -366,7 +369,7 @@ void MainWindow::makeJoystickTabs() ui->tabWidget->addTab(tabwidget, joytabName); } - if (joysticks > 0) + if (joysticks != 0) { ui->tabWidget->setCurrentIndex(0); ui->stackedWidget->setCurrentIndex(1); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 2f3f8d50..75be584e 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -2,9 +2,6 @@ MainWindow - - Qt::WindowModal - 0 diff --git a/src/qtcocoakeymapper.cpp b/src/qtcocoakeymapper.cpp new file mode 100644 index 00000000..b4ae5d7f --- /dev/null +++ b/src/qtcocoakeymapper.cpp @@ -0,0 +1,48 @@ +/* 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 "qtcocoakeymapper.h" + +QtCocoaKeyMapper::QtCocoaKeyMapper(QObject *parent) : + QtKeyMapperBase(parent) +{ + identifier = "cocoa"; + populateMappingHashes(); +} + +unsigned int QtCocoaKeyMapper::returnQtKey(unsigned int key, unsigned int scancode) +{ + Q_UNUSED(scancode); + + return key; +} + +unsigned int QtCocoaKeyMapper::returnVirtualKey(unsigned int qkey) +{ + return qkey; +} + + +void QtCocoaKeyMapper::populateMappingHashes() +{ +} + +void QtCocoaKeyMapper::populateCharKeyInformation() +{ +} diff --git a/src/qtcocoakeymapper.h b/src/qtcocoakeymapper.h new file mode 100644 index 00000000..c532de69 --- /dev/null +++ b/src/qtcocoakeymapper.h @@ -0,0 +1,43 @@ +/* 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 QTCOCOAKEYMAPPER_H +#define QTCOCOAKEYMAPPER_H + +#include +#include +#include + +#include "qtkeymapperbase.h" + +class QtCocoaKeyMapper : public QtKeyMapperBase +{ + Q_OBJECT +public: + explicit QtCocoaKeyMapper(QObject *parent = 0); + + static const unsigned int consumerUsagePagePrefix = 0x12000; + + unsigned int returnQtKey(unsigned int key, unsigned int scancode); + unsigned int returnVirtualKey(unsigned int qkey); + +protected: + void populateMappingHashes(); + void populateCharKeyInformation(); +}; + +#endif // QTCOCOAKEYMAPPER_H