Merge branch 'osx_improvements' of https://github.com/alexey-lysiuk/gzdoom

This commit is contained in:
Christoph Oelckers 2015-01-06 15:04:28 +01:00
commit 2095f5ddf4
8 changed files with 278 additions and 193 deletions

View file

@ -31,10 +31,23 @@
**
*/
#import <AppKit/NSApplication.h>
#import <AppKit/NSScreen.h>
#import <AppKit/NSView.h>
#import <AppKit/NSWindow.h>
#import <AppKit/AppKit.h>
struct RenderBufferOptions
{
float pixelScale;
float shiftX;
float shiftY;
float width;
float height;
bool dirty;
};
extern RenderBufferOptions rbOpts;
inline bool I_IsHiDPISupported()
@ -115,17 +128,6 @@ enum
kVK_UpArrow = 0x7E
};
@interface NSView(SupportOutdatedOSX)
- (NSPoint)convertPointFromBase:(NSPoint)aPoint;
@end
@implementation NSView(SupportOutdatedOSX)
- (NSPoint)convertPointFromBase:(NSPoint)aPoint
{
return [self convertPoint:aPoint fromView:nil];
}
@end
#endif // prior to 10.5

View file

@ -2,7 +2,7 @@
** i_input.mm
**
**---------------------------------------------------------------------------
** Copyright 2012-2014 Alexey Lysiuk
** Copyright 2012-2015 Alexey Lysiuk
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
@ -31,8 +31,8 @@
**
*/
#import <AppKit/NSCursor.h>
#import <AppKit/NSEvent.h>
#include "i_common.h"
#import <Carbon/Carbon.h>
// Avoid collision between DObject class and Objective-C
@ -48,9 +48,6 @@
#include "doomstat.h"
#include "v_video.h"
#include "i_common.h"
#include "i_rbopts.h"
#undef Class

View file

@ -33,6 +33,7 @@
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOMessage.h>
#include <IOKit/hid/IOHIDLib.h>
#include <IOKit/hid/IOHIDUsageTables.h>
@ -45,6 +46,9 @@
#include "v_text.h"
EXTERN_CVAR(Bool, joy_axespolling)
namespace
{
@ -73,6 +77,9 @@ FString ToFString(const CFStringRef string)
}
// ---------------------------------------------------------------------------
class IOKitJoystick : public IJoystickConfig
{
public:
@ -105,6 +112,10 @@ public:
void Update();
void UseAxesPolling(bool axesPolling);
io_object_t* GetNotificationPtr();
private:
IOHIDDeviceInterface** m_interface;
IOHIDQueueInterface** m_queue;
@ -154,6 +165,10 @@ private:
TArray<DigitalButton> m_buttons;
TArray<DigitalButton> m_POVs;
bool m_useAxesPolling;
io_object_t m_notification;
static const float DEFAULT_DEADZONE;
static const float DEFAULT_SENSITIVITY;
@ -171,7 +186,9 @@ private:
void AddAxis(CFDictionaryRef element);
void AddButton(CFDictionaryRef element);
void AddPOV(CFDictionaryRef element);
void AddToQueue(IOHIDElementCookie cookie);
void RemoveFromQueue(IOHIDElementCookie cookie);
};
@ -212,7 +229,8 @@ IOHIDDeviceInterface** CreateDeviceInterface(const io_object_t device)
}
else
{
Printf(TEXTCOLOR_RED "IOCFPlugInInterface::QueryInterface() failed with code 0x%08X\n", queryResult);
Printf(TEXTCOLOR_RED "IOCFPlugInInterface::QueryInterface() failed with code 0x%08X\n",
static_cast<int>(queryResult));
return NULL;
}
}
@ -261,6 +279,8 @@ IOKitJoystick::IOKitJoystick(const io_object_t device)
: m_interface(CreateDeviceInterface(device))
, m_queue(CreateDeviceQueue(m_interface))
, m_sensitivity(DEFAULT_SENSITIVITY)
, m_useAxesPolling(true)
, m_notification(0)
{
if (NULL == m_interface || NULL == m_queue)
{
@ -282,6 +302,8 @@ IOKitJoystick::IOKitJoystick(const io_object_t device)
CFRelease(properties);
UseAxesPolling(joy_axespolling);
(*m_queue)->start(m_queue);
SetDefaultConfig();
@ -291,6 +313,11 @@ IOKitJoystick::~IOKitJoystick()
{
M_SaveJoystickConfig(this);
if (0 != m_notification)
{
IOObjectRelease(m_notification);
}
if (NULL != m_queue)
{
(*m_queue)->stop(m_queue);
@ -486,6 +513,26 @@ void IOKitJoystick::AddAxes(float axes[NUM_JOYAXIS]) const
}
void IOKitJoystick::UseAxesPolling(const bool axesPolling)
{
m_useAxesPolling = axesPolling;
for (size_t i = 0, count = m_axes.Size(); i < count; ++i)
{
AnalogAxis& axis = m_axes[i];
if (m_useAxesPolling)
{
RemoveFromQueue(axis.cookie);
}
else
{
AddToQueue(axis.cookie);
}
}
}
void IOKitJoystick::Update()
{
if (NULL == m_queue)
@ -509,12 +556,14 @@ void IOKitJoystick::Update()
{
Printf(TEXTCOLOR_RED "IOHIDQueueInterface::getNextEvent() failed with code 0x%08X\n", eventResult);
}
ProcessAxes();
}
void IOKitJoystick::ProcessAxes()
{
if (NULL == m_interface)
if (NULL == m_interface || !m_useAxesPolling)
{
return;
}
@ -546,6 +595,11 @@ void IOKitJoystick::ProcessAxes()
bool IOKitJoystick::ProcessAxis(const IOHIDEventStruct& event)
{
if (m_useAxesPolling)
{
return false;
}
for (size_t i = 0, count = m_axes.Size(); i < count; ++i)
{
if (event.elementCookie != m_axes[i].cookie)
@ -827,8 +881,6 @@ void IOKitJoystick::AddAxis(const CFDictionaryRef element)
}
m_axes.Push(axis);
AddToQueue(axis.cookie);
}
void IOKitJoystick::AddButton(CFDictionaryRef element)
@ -849,9 +901,13 @@ void IOKitJoystick::AddPOV(CFDictionaryRef element)
AddToQueue(pov.cookie);
}
void IOKitJoystick::AddToQueue(const IOHIDElementCookie cookie)
{
assert(NULL != m_queue);
if (NULL == m_queue)
{
return;
}
if (!(*m_queue)->hasElement(m_queue, cookie))
{
@ -859,6 +915,25 @@ void IOKitJoystick::AddToQueue(const IOHIDElementCookie cookie)
}
}
void IOKitJoystick::RemoveFromQueue(const IOHIDElementCookie cookie)
{
if (NULL == m_queue)
{
return;
}
if ((*m_queue)->hasElement(m_queue, cookie))
{
(*m_queue)->removeElement(m_queue, cookie);
}
}
io_object_t* IOKitJoystick::GetNotificationPtr()
{
return &m_notification;
}
// ---------------------------------------------------------------------------
@ -876,26 +951,75 @@ public:
// Updates axes/buttons states
void Update();
// Rebuilds device list
void Rescan();
void UseAxesPolling(bool axesPolling);
private:
TArray<IOKitJoystick*> m_joysticks;
typedef TDeletingArray<IOKitJoystick*> JoystickList;
JoystickList m_joysticks;
void Rescan(int usagePage, int usage);
static const size_t NOTIFICATION_PORT_COUNT = 2;
void ReleaseJoysticks();
IONotificationPortRef m_notificationPorts[NOTIFICATION_PORT_COUNT];
io_iterator_t m_notifications [NOTIFICATION_PORT_COUNT];
// Rebuilds device list
void Rescan(int usagePage, int usage, size_t notificationPortIndex);
void AddDevices(IONotificationPortRef notificationPort, const io_iterator_t iterator);
static void OnDeviceAttached(void* refcon, io_iterator_t iterator);
static void OnDeviceRemoved(void* refcon, io_service_t service,
natural_t messageType, void* messageArgument);
};
IOKitJoystickManager* s_joystickManager;
IOKitJoystickManager::IOKitJoystickManager()
{
Rescan();
memset(m_notifications, 0, sizeof m_notifications);
for (size_t i = 0; i < NOTIFICATION_PORT_COUNT; ++i)
{
m_notificationPorts[i] = IONotificationPortCreate(kIOMasterPortDefault);
if (NULL == m_notificationPorts[i])
{
Printf(TEXTCOLOR_RED "IONotificationPortCreate(%zu) failed\n", i);
return;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(),
IONotificationPortGetRunLoopSource(m_notificationPorts[i]), kCFRunLoopDefaultMode);
}
Rescan(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick, 0);
Rescan(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad, 1);
}
IOKitJoystickManager::~IOKitJoystickManager()
{
ReleaseJoysticks();
for (size_t i = 0; i < NOTIFICATION_PORT_COUNT; ++i)
{
IONotificationPortRef& port = m_notificationPorts[i];
if (NULL != port)
{
CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
IONotificationPortGetRunLoopSource(port), kCFRunLoopDefaultMode);
IONotificationPortDestroy(port);
port = NULL;
}
io_iterator_t& notification = m_notifications[i];
if (0 != notification)
{
IOObjectRelease(notification);
notification = NULL;
}
}
}
@ -931,15 +1055,23 @@ void IOKitJoystickManager::Update()
}
void IOKitJoystickManager::Rescan()
void IOKitJoystickManager::UseAxesPolling(const bool axesPolling)
{
ReleaseJoysticks();
Rescan(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
Rescan(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad);
for (size_t i = 0, count = m_joysticks.Size(); i < count; ++i)
{
m_joysticks[i]->UseAxesPolling(axesPolling);
}
}
void IOKitJoystickManager::Rescan(const int usagePage, const int usage)
void PostDeviceChangeEvent()
{
const event_t event = { EV_DeviceChange };
D_PostEvent(&event);
}
void IOKitJoystickManager::Rescan(const int usagePage, const int usage, const size_t notificationPortIndex)
{
CFMutableDictionaryRef deviceMatching = IOServiceMatching(kIOHIDDeviceKey);
@ -957,44 +1089,85 @@ void IOKitJoystickManager::Rescan(const int usagePage, const int usage)
CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
CFDictionarySetValue(deviceMatching, CFSTR(kIOHIDPrimaryUsageKey), usageRef);
io_iterator_t iterator = 0;
const kern_return_t matchResult =
IOServiceGetMatchingServices(kIOMasterPortDefault, deviceMatching, &iterator);
assert(notificationPortIndex < NOTIFICATION_PORT_COUNT);
io_iterator_t* iteratorPtr = &m_notifications[notificationPortIndex];
const IONotificationPortRef notificationPort = m_notificationPorts[notificationPortIndex];
assert(NULL != notificationPort);
const kern_return_t notificationResult = IOServiceAddMatchingNotification(notificationPort,
kIOFirstMatchNotification, deviceMatching, OnDeviceAttached, notificationPort, iteratorPtr);
// IOServiceAddMatchingNotification() consumes one reference of matching dictionary
// Thus CFRelease(deviceMatching) is not needed
CFRelease(usageRef);
CFRelease(usagePageRef);
if (KERN_SUCCESS != matchResult)
if (KERN_SUCCESS != notificationResult)
{
Printf(TEXTCOLOR_RED "IOServiceGetMatchingServices() failed with code %i\n", matchResult);
return;
Printf(TEXTCOLOR_RED "IOServiceAddMatchingNotification() failed with code %i\n", notificationResult);
}
AddDevices(notificationPort, *iteratorPtr);
}
void IOKitJoystickManager::AddDevices(const IONotificationPortRef notificationPort, const io_iterator_t iterator)
{
while (io_object_t device = IOIteratorNext(iterator))
{
IOKitJoystick* joystick = new IOKitJoystick(device);
m_joysticks.Push(joystick);
const kern_return_t notificationResult = IOServiceAddInterestNotification(notificationPort,
device, kIOGeneralInterest, OnDeviceRemoved, joystick, joystick->GetNotificationPtr());
if (KERN_SUCCESS != notificationResult)
{
Printf(TEXTCOLOR_RED "IOServiceAddInterestNotification() failed with code %i\n", notificationResult);
}
IOObjectRelease(device);
PostDeviceChangeEvent();
}
IOObjectRelease(iterator);
}
void IOKitJoystickManager::ReleaseJoysticks()
void IOKitJoystickManager::OnDeviceAttached(void* const refcon, const io_iterator_t iterator)
{
for (size_t i = 0, count = m_joysticks.Size(); i <count; ++i)
{
delete m_joysticks[i];
}
assert(NULL != refcon);
const IONotificationPortRef notificationPort = static_cast<IONotificationPortRef>(refcon);
m_joysticks.Clear();
assert(NULL != s_joystickManager);
s_joystickManager->AddDevices(notificationPort, iterator);
}
void IOKitJoystickManager::OnDeviceRemoved(void* const refcon, io_service_t, const natural_t messageType, void*)
{
if (messageType != kIOMessageServiceIsTerminated)
{
return;
}
IOKitJoystickManager* s_joystickManager;
assert(NULL != refcon);
IOKitJoystick* const joystick = static_cast<IOKitJoystick*>(refcon);
assert(NULL != s_joystickManager);
JoystickList& joysticks = s_joystickManager->m_joysticks;
for (unsigned int i = 0, count = joysticks.Size(); i < count; ++i)
{
if (joystick == joysticks[i])
{
joysticks.Delete(i);
break;
}
}
delete joystick;
PostDeviceChangeEvent();
}
} // unnamed namespace
@ -1036,7 +1209,7 @@ void I_GetJoysticks(TArray<IJoystickConfig*>& sticks)
void I_GetAxes(float axes[NUM_JOYAXIS])
{
for (size_t i = 0; i <NUM_JOYAXIS; ++i)
for (size_t i = 0; i < NUM_JOYAXIS; ++i)
{
axes[i] = 0.0f;
}
@ -1049,10 +1222,7 @@ void I_GetAxes(float axes[NUM_JOYAXIS])
IJoystickConfig* I_UpdateDeviceList()
{
if (use_joystick && NULL != s_joystickManager)
{
s_joystickManager->Rescan();
}
// Does nothing, device list is always kept up-to-date
return NULL;
}
@ -1068,3 +1238,15 @@ void I_ProcessJoysticks()
s_joystickManager->Update();
}
}
// ---------------------------------------------------------------------------
CUSTOM_CVAR(Bool, joy_axespolling, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
if (NULL != s_joystickManager)
{
s_joystickManager->UseAxesPolling(self);
}
}

View file

@ -31,10 +31,10 @@
**
*/
#include <sys/sysctl.h>
#include "i_common.h"
#import <AppKit/NSMenu.h>
#import <AppKit/NSEvent.h>
#include <sys/sysctl.h>
#include <unistd.h>
// Avoid collision between DObject class and Objective-C
#define Class ObjectClass
@ -49,9 +49,6 @@
#include "s_sound.h"
#include "version.h"
#include "i_common.h"
#include "i_osversion.h"
#undef Class
@ -492,27 +489,6 @@ void CreateMenu()
[NSApp setMainMenu:menuBar];
}
DarwinVersion GetDarwinVersion()
{
DarwinVersion result = {};
int mib[2] = { CTL_KERN, KERN_OSRELEASE };
size_t size = 0;
if (0 == sysctl(mib, 2, NULL, &size, NULL, 0))
{
char* version = static_cast<char*>(alloca(size));
if (0 == sysctl(mib, 2, version, &size, NULL, 0))
{
sscanf(version, "%hu.%hu.%hu",
&result.major, &result.minor, &result.bugfix);
}
}
return result;
}
void ReleaseApplicationController()
{
if (NULL != appCtrl)
@ -528,9 +504,6 @@ void ReleaseApplicationController()
} // unnamed namespace
const DarwinVersion darwinVersion = GetDarwinVersion();
int main(int argc, char** argv)
{
for (int i = 0; i <= argc; ++i)

View file

@ -1,43 +0,0 @@
/*
** i_osversion.h
**
**---------------------------------------------------------------------------
** Copyright 2012-2014 Alexey Lysiuk
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. 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.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
**---------------------------------------------------------------------------
**
*/
#include <stdint.h>
struct DarwinVersion
{
uint16_t major;
uint16_t minor;
uint16_t bugfix;
};
extern const DarwinVersion darwinVersion;

View file

@ -1,52 +0,0 @@
/*
** i_rbopts.h
**
**---------------------------------------------------------------------------
** Copyright 2014 Alexey Lysiuk
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. 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.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
**---------------------------------------------------------------------------
**
*/
#ifndef SRC_COCOA_I_RBOPTS_H_INCLUDED
#define SRC_COCOA_I_RBOPTS_H_INCLUDED
struct RenderBufferOptions
{
float pixelScale;
float shiftX;
float shiftY;
float width;
float height;
bool dirty;
};
extern RenderBufferOptions rbOpts;
#endif // SRC_COCOA_I_RBOPTS_H_INCLUDED

View file

@ -1,3 +1,35 @@
/*
** i_timer.cpp
**
**---------------------------------------------------------------------------
** Copyright 2012-2015 Alexey Lysiuk
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. 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.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
**---------------------------------------------------------------------------
**
*/
#include <assert.h>
#include <sys/time.h>

View file

@ -2,7 +2,7 @@
** i_video.mm
**
**---------------------------------------------------------------------------
** Copyright 2012-2014 Alexey Lysiuk
** Copyright 2012-2015 Alexey Lysiuk
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
@ -31,11 +31,8 @@
**
*/
#import <AppKit/NSButton.h>
#import <AppKit/NSCursor.h>
#import <AppKit/NSImage.h>
#import <AppKit/NSOpenGL.h>
#import <AppKit/NSOpenGLView.h>
#include "i_common.h"
#import <Carbon/Carbon.h>
#import <OpenGL/gl.h>
@ -58,9 +55,6 @@
#include "v_video.h"
#include "version.h"
#include "i_common.h"
#include "i_rbopts.h"
#undef Class