Merge pull request #4102 from ligfx/quartz_input

Add Quartz/CoreGraphics controller interface for default k&m events
This commit is contained in:
shuffle2 2016-10-03 03:13:58 -07:00 committed by GitHub
commit 2747fd3a0d
7 changed files with 346 additions and 1 deletions

View file

@ -20,6 +20,8 @@ elseif(APPLE)
ControllerInterface/OSX/OSX.mm
ControllerInterface/OSX/OSXKeyboard.mm
ControllerInterface/OSX/OSXJoystick.mm
ControllerInterface/Quartz/Quartz.mm
ControllerInterface/Quartz/QuartzKeyboardAndMouse.mm
ControllerInterface/ForceFeedback/ForceFeedbackDevice.cpp)
set(LIBS ${LIBS} ${COREFOUNDATION_LIBRARY} ${CARBON_LIBRARY} ${COCOA_LIBRARY})
elseif(X11_FOUND)

View file

@ -18,6 +18,7 @@
#endif
#ifdef CIFACE_USE_OSX
#include "InputCommon/ControllerInterface/OSX/OSX.h"
#include "InputCommon/ControllerInterface/Quartz/Quartz.h"
#endif
#ifdef CIFACE_USE_SDL
#include "InputCommon/ControllerInterface/SDL/SDL.h"
@ -64,6 +65,7 @@ void ControllerInterface::Initialize(void* const hwnd)
#endif
#ifdef CIFACE_USE_OSX
ciface::OSX::Init(hwnd);
ciface::Quartz::Init(hwnd);
#endif
#ifdef CIFACE_USE_SDL
ciface::SDL::Init();
@ -111,6 +113,7 @@ void ControllerInterface::Shutdown()
#endif
#ifdef CIFACE_USE_OSX
ciface::OSX::DeInit();
ciface::Quartz::DeInit();
#endif
#ifdef CIFACE_USE_SDL
// TODO: there seems to be some sort of memory leak with SDL, quit isn't freeing everything up

View file

@ -0,0 +1,14 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
namespace ciface
{
namespace Quartz
{
void Init(void* window);
void DeInit();
}
}

View file

@ -0,0 +1,22 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "InputCommon/ControllerInterface/Quartz/Quartz.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.h"
namespace ciface
{
namespace Quartz
{
void Init(void* window)
{
g_controller_interface.AddDevice(std::make_shared<KeyboardAndMouse>(window));
}
void DeInit()
{
}
} // namespace Quartz
} // namespace ciface

View file

@ -0,0 +1,78 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <QuartzCore/QuartzCore.h>
#include "InputCommon/ControllerInterface/Device.h"
namespace ciface
{
namespace Quartz
{
std::string KeycodeToName(const CGKeyCode keycode);
class KeyboardAndMouse : public Core::Device
{
private:
class Key : public Input
{
public:
explicit Key(CGKeyCode keycode);
std::string GetName() const override;
ControlState GetState() const override;
private:
CGKeyCode m_keycode;
std::string m_name;
};
class Cursor : public Input
{
public:
Cursor(u8 index, const float& axis, const bool positive)
: m_axis(axis), m_index(index), m_positive(positive)
{
}
std::string GetName() const override;
bool IsDetectable() override { return false; }
ControlState GetState() const override;
private:
const float& m_axis;
const u8 m_index;
const bool m_positive;
};
class Button : public Input
{
public:
explicit Button(CGMouseButton button) : m_button(button) {}
std::string GetName() const override;
ControlState GetState() const override;
private:
CGMouseButton m_button;
};
public:
void UpdateInput() override;
explicit KeyboardAndMouse(void* window);
std::string GetName() const override;
std::string GetSource() const override;
private:
struct
{
float x, y;
} m_cursor;
uint32_t m_windowid;
};
} // namespace Quartz
} // namespace ciface

View file

@ -0,0 +1,225 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <Carbon/Carbon.h>
#include <Cocoa/Cocoa.h>
#include "InputCommon/ControllerInterface/Quartz/QuartzKeyboardAndMouse.h"
namespace ciface
{
namespace Quartz
{
std::string KeycodeToName(const CGKeyCode keycode) {
static const std::map<CGKeyCode, std::string> named_keys = {
{kVK_ANSI_A, "A"},
{kVK_ANSI_B, "B"},
{kVK_ANSI_C, "C"},
{kVK_ANSI_D, "D"},
{kVK_ANSI_E, "E"},
{kVK_ANSI_F, "F"},
{kVK_ANSI_G, "G"},
{kVK_ANSI_H, "H"},
{kVK_ANSI_I, "I"},
{kVK_ANSI_J, "J"},
{kVK_ANSI_K, "K"},
{kVK_ANSI_L, "L"},
{kVK_ANSI_M, "M"},
{kVK_ANSI_N, "N"},
{kVK_ANSI_O, "O"},
{kVK_ANSI_P, "P"},
{kVK_ANSI_Q, "Q"},
{kVK_ANSI_R, "R"},
{kVK_ANSI_S, "S"},
{kVK_ANSI_T, "T"},
{kVK_ANSI_U, "U"},
{kVK_ANSI_V, "V"},
{kVK_ANSI_W, "W"},
{kVK_ANSI_X, "X"},
{kVK_ANSI_Y, "Y"},
{kVK_ANSI_Z, "Z"},
{kVK_ANSI_1, "1"},
{kVK_ANSI_2, "2"},
{kVK_ANSI_3, "3"},
{kVK_ANSI_4, "4"},
{kVK_ANSI_5, "5"},
{kVK_ANSI_6, "6"},
{kVK_ANSI_7, "7"},
{kVK_ANSI_8, "8"},
{kVK_ANSI_9, "9"},
{kVK_ANSI_0, "0"},
{kVK_Return, "Return"},
{kVK_Escape, "Escape"},
{kVK_Delete, "Backspace"},
{kVK_Tab, "Tab"},
{kVK_Space, "Space"},
{kVK_ANSI_Minus, "-"},
{kVK_ANSI_Equal, "="},
{kVK_ANSI_LeftBracket, "["},
{kVK_ANSI_RightBracket, "]"},
{kVK_ANSI_Backslash, "\\"},
{kVK_ANSI_Semicolon, ";"},
{kVK_ANSI_Quote, "'"},
{kVK_ANSI_Grave, "Tilde"},
{kVK_ANSI_Comma, ","},
{kVK_ANSI_Period, "."},
{kVK_ANSI_Slash, "/"},
{kVK_CapsLock, "Caps Lock"},
{kVK_F1, "F1"},
{kVK_F2, "F2"},
{kVK_F3, "F3"},
{kVK_F4, "F4"},
{kVK_F5, "F5"},
{kVK_F6, "F6"},
{kVK_F7, "F7"},
{kVK_F8, "F8"},
{kVK_F9, "F9"},
{kVK_F10, "F10"},
{kVK_F11, "F11"},
{kVK_F12, "F12"},
{kVK_Home, "Home"},
{kVK_PageUp, "Page Up"},
{kVK_ForwardDelete, "Delete"},
{kVK_End, "End"},
{kVK_PageDown, "Page Down"},
{kVK_RightArrow, "Right Arrow"},
{kVK_LeftArrow, "Left Arrow"},
{kVK_DownArrow, "Down Arrow"},
{kVK_UpArrow, "Up Arrow"},
{kVK_ANSI_KeypadDivide, "Keypad /"},
{kVK_ANSI_KeypadMultiply, "Keypad *"},
{kVK_ANSI_KeypadMinus, "Keypad -"},
{kVK_ANSI_KeypadPlus, "Keypad +"},
{kVK_ANSI_KeypadEnter, "Keypad Enter"},
{kVK_ANSI_Keypad1, "Keypad 1"},
{kVK_ANSI_Keypad2, "Keypad 2"},
{kVK_ANSI_Keypad3, "Keypad 3"},
{kVK_ANSI_Keypad4, "Keypad 4"},
{kVK_ANSI_Keypad5, "Keypad 5"},
{kVK_ANSI_Keypad6, "Keypad 6"},
{kVK_ANSI_Keypad7, "Keypad 7"},
{kVK_ANSI_Keypad8, "Keypad 8"},
{kVK_ANSI_Keypad9, "Keypad 9"},
{kVK_ANSI_Keypad0, "Keypad 0"},
{kVK_ANSI_KeypadDecimal, "Keypad ."},
{kVK_ANSI_KeypadEquals, "Keypad ="},
{kVK_Control, "Left Control"},
{kVK_Shift, "Left Shift"},
{kVK_Option, "Left Alt"},
{kVK_Command, "Command"},
{kVK_RightControl, "Right Control"},
{kVK_RightShift, "Right Shift"},
{kVK_RightOption, "Right Alt"},
};
if (named_keys.find(keycode) != named_keys.end())
return named_keys.at(keycode);
else
return "Key " + std::to_string(keycode);
}
KeyboardAndMouse::Key::Key(CGKeyCode keycode) : m_keycode(keycode), m_name(KeycodeToName(keycode))
{
}
ControlState KeyboardAndMouse::Key::GetState() const
{
return CGEventSourceKeyState(kCGEventSourceStateHIDSystemState, m_keycode) != 0;
}
std::string KeyboardAndMouse::Key::GetName() const
{
return m_name;
}
KeyboardAndMouse::KeyboardAndMouse(void* window)
{
// All keycodes in <HIToolbox/Events.h> are 0x7e or lower. If you notice
// keys that aren't being recognized, bump this number up!
for (int keycode = 0; keycode < 0x80; ++keycode)
AddInput(new Key(keycode));
m_windowid = [[reinterpret_cast<NSView*>(window) window] windowNumber];
// cursor, with a hax for-loop
for (unsigned int i = 0; i < 4; ++i)
AddInput(new Cursor(!!(i & 2), (&m_cursor.x)[i / 2], !!(i & 1)));
AddInput(new Button(kCGMouseButtonLeft));
AddInput(new Button(kCGMouseButtonRight));
AddInput(new Button(kCGMouseButtonCenter));
}
void KeyboardAndMouse::UpdateInput()
{
CGRect bounds = CGRectZero;
CGWindowID windowid[1] = {m_windowid};
CFArrayRef windowArray = CFArrayCreate(nullptr, (const void**)windowid, 1, nullptr);
CFArrayRef windowDescriptions = CGWindowListCreateDescriptionFromArray(windowArray);
CFDictionaryRef windowDescription =
static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(windowDescriptions, 0));
if (CFDictionaryContainsKey(windowDescription, kCGWindowBounds))
{
CFDictionaryRef boundsDictionary =
static_cast<CFDictionaryRef>(CFDictionaryGetValue(windowDescription, kCGWindowBounds));
if (boundsDictionary != nullptr)
CGRectMakeWithDictionaryRepresentation(boundsDictionary, &bounds);
}
CFRelease(windowDescriptions);
CFRelease(windowArray);
CGEventRef event = CGEventCreate(nil);
CGPoint loc = CGEventGetLocation(event);
CFRelease(event);
loc.x -= bounds.origin.x;
loc.y -= bounds.origin.y;
m_cursor.x = loc.x / bounds.size.width * 2 - 1.0;
m_cursor.y = loc.y / bounds.size.height * 2 - 1.0;
}
std::string KeyboardAndMouse::GetName() const
{
return "Keyboard & Mouse";
}
std::string KeyboardAndMouse::GetSource() const
{
return "Quartz";
}
ControlState KeyboardAndMouse::Cursor::GetState() const
{
return std::max(0.0, ControlState(m_axis) / (m_positive ? 1.0 : -1.0));
}
ControlState KeyboardAndMouse::Button::GetState() const
{
return CGEventSourceButtonState(kCGEventSourceStateHIDSystemState, m_button) != 0;
}
std::string KeyboardAndMouse::Cursor::GetName() const
{
static char tmpstr[] = "Cursor ..";
tmpstr[7] = (char)('X' + m_index);
tmpstr[8] = (m_positive ? '+' : '-');
return tmpstr;
}
std::string KeyboardAndMouse::Button::GetName() const
{
if (m_button == kCGMouseButtonLeft)
return "Left Click";
if (m_button == kCGMouseButtonCenter)
return "Middle Click";
if (m_button == kCGMouseButtonRight)
return "Right Click";
return std::string("Click ") + char('0' + m_button);
}
} // namespace Quartz
} // namespace ciface

View file

@ -126,7 +126,8 @@ bool InputConfig::IsControllerControlledByGamepadDevice(int index) const
const auto& controller = m_controllers.at(index).get()->default_device;
// Filter out anything which obviously not a gamepad
return !((controller.source == "Keyboard") // OSX Keyboard/Mouse
return !((controller.source == "Keyboard") // OSX IOKit Keyboard/Mouse
|| (controller.source == "Quartz") // OSX Quartz Keyboard/Mouse
|| (controller.source == "XInput2") // Linux and BSD Keyboard/Mouse
|| (controller.source == "Android" &&
controller.name == "Touchscreen") // Android Touchscreen