mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-18 02:12:00 +00:00
Merge branch 'master' of https://github.com/rheit/zdoom
This commit is contained in:
commit
c424a1afcb
8 changed files with 2736 additions and 2797 deletions
|
@ -601,9 +601,11 @@ set( PLAT_COCOA_SOURCES
|
||||||
posix/cocoa/hid/IOHIDElement_.c
|
posix/cocoa/hid/IOHIDElement_.c
|
||||||
posix/cocoa/hid/ImmrHIDUtilAddOn.c
|
posix/cocoa/hid/ImmrHIDUtilAddOn.c
|
||||||
posix/cocoa/critsec.cpp
|
posix/cocoa/critsec.cpp
|
||||||
posix/cocoa/i_backend_cocoa.mm
|
posix/cocoa/i_input.mm
|
||||||
posix/cocoa/i_joystick.cpp
|
posix/cocoa/i_joystick.cpp
|
||||||
posix/cocoa/i_timer.cpp )
|
posix/cocoa/i_main.mm
|
||||||
|
posix/cocoa/i_timer.cpp
|
||||||
|
posix/cocoa/i_video.mm )
|
||||||
|
|
||||||
if( WIN32 )
|
if( WIN32 )
|
||||||
set( SYSTEM_SOURCES_DIR win32 )
|
set( SYSTEM_SOURCES_DIR win32 )
|
||||||
|
|
|
@ -185,7 +185,7 @@ static struct TicSpecial
|
||||||
size_t used[BACKUPTICS];
|
size_t used[BACKUPTICS];
|
||||||
BYTE *streamptr;
|
BYTE *streamptr;
|
||||||
size_t streamoffs;
|
size_t streamoffs;
|
||||||
int specialsize;
|
size_t specialsize;
|
||||||
int lastmaketic;
|
int lastmaketic;
|
||||||
bool okay;
|
bool okay;
|
||||||
|
|
||||||
|
@ -224,11 +224,11 @@ static struct TicSpecial
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make more room for special commands.
|
// Make more room for special commands.
|
||||||
void GetMoreSpace ()
|
void GetMoreSpace (size_t needed)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
specialsize <<= 1;
|
specialsize = MAX(specialsize * 2, needed + 30);
|
||||||
|
|
||||||
DPrintf ("Expanding special size to %d\n", specialsize);
|
DPrintf ("Expanding special size to %d\n", specialsize);
|
||||||
|
|
||||||
|
@ -240,8 +240,8 @@ static struct TicSpecial
|
||||||
|
|
||||||
void CheckSpace (size_t needed)
|
void CheckSpace (size_t needed)
|
||||||
{
|
{
|
||||||
if (streamoffs >= specialsize - needed)
|
if (streamoffs + needed >= specialsize)
|
||||||
GetMoreSpace ();
|
GetMoreSpace (streamoffs + needed);
|
||||||
|
|
||||||
streamoffs += needed;
|
streamoffs += needed;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
168
src/posix/cocoa/i_common.h
Normal file
168
src/posix/cocoa/i_common.h
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
/*
|
||||||
|
** i_common.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.
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <AppKit/NSApplication.h>
|
||||||
|
#import <AppKit/NSScreen.h>
|
||||||
|
#import <AppKit/NSView.h>
|
||||||
|
#import <AppKit/NSWindow.h>
|
||||||
|
|
||||||
|
|
||||||
|
inline bool I_IsHiDPISupported()
|
||||||
|
{
|
||||||
|
// The following value shoud be equal to NSAppKitVersionNumber10_7
|
||||||
|
// and it's hard-coded in order to build on earlier SDKs
|
||||||
|
|
||||||
|
return NSAppKitVersionNumber >= 1138;
|
||||||
|
}
|
||||||
|
|
||||||
|
void I_ProcessEvent(NSEvent* event);
|
||||||
|
|
||||||
|
void I_StartupJoysticks();
|
||||||
|
void I_ShutdownJoysticks();
|
||||||
|
void I_ProcessJoysticks();
|
||||||
|
|
||||||
|
NSSize I_GetContentViewSize(const NSWindow* window);
|
||||||
|
void I_SetMainWindowVisible(bool visible);
|
||||||
|
void I_SetNativeMouse(bool wantNative);
|
||||||
|
|
||||||
|
|
||||||
|
// The following definitions are required to build with older OS X SDKs
|
||||||
|
|
||||||
|
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
|
||||||
|
|
||||||
|
typedef unsigned int NSUInteger;
|
||||||
|
typedef int NSInteger;
|
||||||
|
|
||||||
|
typedef float CGFloat;
|
||||||
|
|
||||||
|
// From HIToolbox/Events.h
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
kVK_Return = 0x24,
|
||||||
|
kVK_Tab = 0x30,
|
||||||
|
kVK_Space = 0x31,
|
||||||
|
kVK_Delete = 0x33,
|
||||||
|
kVK_Escape = 0x35,
|
||||||
|
kVK_Command = 0x37,
|
||||||
|
kVK_Shift = 0x38,
|
||||||
|
kVK_CapsLock = 0x39,
|
||||||
|
kVK_Option = 0x3A,
|
||||||
|
kVK_Control = 0x3B,
|
||||||
|
kVK_RightShift = 0x3C,
|
||||||
|
kVK_RightOption = 0x3D,
|
||||||
|
kVK_RightControl = 0x3E,
|
||||||
|
kVK_Function = 0x3F,
|
||||||
|
kVK_F17 = 0x40,
|
||||||
|
kVK_VolumeUp = 0x48,
|
||||||
|
kVK_VolumeDown = 0x49,
|
||||||
|
kVK_Mute = 0x4A,
|
||||||
|
kVK_F18 = 0x4F,
|
||||||
|
kVK_F19 = 0x50,
|
||||||
|
kVK_F20 = 0x5A,
|
||||||
|
kVK_F5 = 0x60,
|
||||||
|
kVK_F6 = 0x61,
|
||||||
|
kVK_F7 = 0x62,
|
||||||
|
kVK_F3 = 0x63,
|
||||||
|
kVK_F8 = 0x64,
|
||||||
|
kVK_F9 = 0x65,
|
||||||
|
kVK_F11 = 0x67,
|
||||||
|
kVK_F13 = 0x69,
|
||||||
|
kVK_F16 = 0x6A,
|
||||||
|
kVK_F14 = 0x6B,
|
||||||
|
kVK_F10 = 0x6D,
|
||||||
|
kVK_F12 = 0x6F,
|
||||||
|
kVK_F15 = 0x71,
|
||||||
|
kVK_Help = 0x72,
|
||||||
|
kVK_Home = 0x73,
|
||||||
|
kVK_PageUp = 0x74,
|
||||||
|
kVK_ForwardDelete = 0x75,
|
||||||
|
kVK_F4 = 0x76,
|
||||||
|
kVK_End = 0x77,
|
||||||
|
kVK_F2 = 0x78,
|
||||||
|
kVK_PageDown = 0x79,
|
||||||
|
kVK_F1 = 0x7A,
|
||||||
|
kVK_LeftArrow = 0x7B,
|
||||||
|
kVK_RightArrow = 0x7C,
|
||||||
|
kVK_DownArrow = 0x7D,
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
NSApplicationActivationPolicyRegular
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef NSInteger NSApplicationActivationPolicy;
|
||||||
|
|
||||||
|
@interface NSApplication(ActivationPolicy)
|
||||||
|
- (BOOL)setActivationPolicy:(NSApplicationActivationPolicy)activationPolicy;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface NSWindow(SetStyleMask)
|
||||||
|
- (void)setStyleMask:(NSUInteger)styleMask;
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif // prior to 10.6
|
||||||
|
|
||||||
|
|
||||||
|
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
|
||||||
|
|
||||||
|
@interface NSView(HiDPIStubs)
|
||||||
|
- (NSPoint)convertPointToBacking:(NSPoint)aPoint;
|
||||||
|
- (NSSize)convertSizeToBacking:(NSSize)aSize;
|
||||||
|
- (NSSize)convertSizeFromBacking:(NSSize)aSize;
|
||||||
|
|
||||||
|
- (void)setWantsBestResolutionOpenGLSurface:(BOOL)flag;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface NSScreen(HiDPIStubs)
|
||||||
|
- (NSRect)convertRectToBacking:(NSRect)aRect;
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif // prior to 10.7
|
743
src/posix/cocoa/i_input.mm
Normal file
743
src/posix/cocoa/i_input.mm
Normal file
|
@ -0,0 +1,743 @@
|
||||||
|
/*
|
||||||
|
** i_input.mm
|
||||||
|
**
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
** 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.
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <AppKit/NSCursor.h>
|
||||||
|
#import <AppKit/NSEvent.h>
|
||||||
|
#import <Carbon/Carbon.h>
|
||||||
|
|
||||||
|
// Avoid collision between DObject class and Objective-C
|
||||||
|
#define Class ObjectClass
|
||||||
|
|
||||||
|
#include "c_console.h"
|
||||||
|
#include "c_cvars.h"
|
||||||
|
#include "c_dispatch.h"
|
||||||
|
#include "d_event.h"
|
||||||
|
#include "d_gui.h"
|
||||||
|
#include "dikeys.h"
|
||||||
|
#include "doomdef.h"
|
||||||
|
#include "doomstat.h"
|
||||||
|
#include "v_video.h"
|
||||||
|
|
||||||
|
#include "i_common.h"
|
||||||
|
#include "i_rbopts.h"
|
||||||
|
|
||||||
|
#undef Class
|
||||||
|
|
||||||
|
|
||||||
|
EXTERN_CVAR(Int, m_use_mouse)
|
||||||
|
|
||||||
|
CVAR(Bool, use_mouse, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||||
|
CVAR(Bool, m_noprescale, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||||
|
CVAR(Bool, m_filter, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
||||||
|
|
||||||
|
CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG | CVAR_ARCHIVE)
|
||||||
|
{
|
||||||
|
if (self < 0)
|
||||||
|
{
|
||||||
|
self = 0;
|
||||||
|
}
|
||||||
|
else if (self > 2)
|
||||||
|
{
|
||||||
|
self = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern int paused, chatmodeon;
|
||||||
|
extern constate_e ConsoleState;
|
||||||
|
|
||||||
|
bool GUICapture;
|
||||||
|
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
// TODO: remove this magic!
|
||||||
|
size_t s_skipMouseMoves;
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
void CheckGUICapture()
|
||||||
|
{
|
||||||
|
const bool wantCapture = (MENU_Off == menuactive)
|
||||||
|
? (c_down == ConsoleState || c_falling == ConsoleState || chatmodeon)
|
||||||
|
: (MENU_On == menuactive || MENU_OnNoPause == menuactive);
|
||||||
|
|
||||||
|
if (wantCapture != GUICapture)
|
||||||
|
{
|
||||||
|
GUICapture = wantCapture;
|
||||||
|
|
||||||
|
ResetButtonStates();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CenterCursor()
|
||||||
|
{
|
||||||
|
NSWindow* window = [NSApp keyWindow];
|
||||||
|
if (nil == window)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NSRect displayRect = [[window screen] frame];
|
||||||
|
const NSRect windowRect = [window frame];
|
||||||
|
const CGPoint centerPoint = CGPointMake(NSMidX(windowRect), displayRect.size.height - NSMidY(windowRect));
|
||||||
|
|
||||||
|
CGEventSourceRef eventSource = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
|
||||||
|
|
||||||
|
if (NULL != eventSource)
|
||||||
|
{
|
||||||
|
CGEventRef mouseMoveEvent = CGEventCreateMouseEvent(eventSource,
|
||||||
|
kCGEventMouseMoved, centerPoint, kCGMouseButtonLeft);
|
||||||
|
|
||||||
|
if (NULL != mouseMoveEvent)
|
||||||
|
{
|
||||||
|
CGEventPost(kCGHIDEventTap, mouseMoveEvent);
|
||||||
|
CFRelease(mouseMoveEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(eventSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: remove this magic!
|
||||||
|
s_skipMouseMoves = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool IsInGame()
|
||||||
|
{
|
||||||
|
switch (mouse_capturemode)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case 0:
|
||||||
|
return gamestate == GS_LEVEL;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
return gamestate == GS_LEVEL
|
||||||
|
|| gamestate == GS_INTERMISSION
|
||||||
|
|| gamestate == GS_FINALE;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckNativeMouse()
|
||||||
|
{
|
||||||
|
const bool windowed = (NULL == screen) || !screen->IsFullscreen();
|
||||||
|
bool wantNative;
|
||||||
|
|
||||||
|
if (windowed)
|
||||||
|
{
|
||||||
|
if (![NSApp isActive] || !use_mouse)
|
||||||
|
{
|
||||||
|
wantNative = true;
|
||||||
|
}
|
||||||
|
else if (MENU_WaitKey == menuactive)
|
||||||
|
{
|
||||||
|
wantNative = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wantNative = (!m_use_mouse || MENU_WaitKey != menuactive)
|
||||||
|
&& (!IsInGame() || GUICapture || paused || demoplayback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// ungrab mouse when in the menu with mouse control on.
|
||||||
|
wantNative = m_use_mouse
|
||||||
|
&& (MENU_On == menuactive || MENU_OnNoPause == menuactive);
|
||||||
|
}
|
||||||
|
|
||||||
|
I_SetNativeMouse(wantNative);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
|
||||||
|
|
||||||
|
void I_GetEvent()
|
||||||
|
{
|
||||||
|
[[NSRunLoop currentRunLoop] limitDateForMode:NSDefaultRunLoopMode];
|
||||||
|
}
|
||||||
|
|
||||||
|
void I_StartTic()
|
||||||
|
{
|
||||||
|
CheckGUICapture();
|
||||||
|
CheckNativeMouse();
|
||||||
|
|
||||||
|
I_ProcessJoysticks();
|
||||||
|
I_GetEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
void I_StartFrame()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void I_SetMouseCapture()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void I_ReleaseMouseCapture()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void I_SetNativeMouse(bool wantNative)
|
||||||
|
{
|
||||||
|
static bool nativeMouse = true;
|
||||||
|
|
||||||
|
if (wantNative != nativeMouse)
|
||||||
|
{
|
||||||
|
nativeMouse = wantNative;
|
||||||
|
|
||||||
|
if (!wantNative)
|
||||||
|
{
|
||||||
|
CenterCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
CGAssociateMouseAndMouseCursorPosition(wantNative);
|
||||||
|
|
||||||
|
if (wantNative)
|
||||||
|
{
|
||||||
|
[NSCursor unhide];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[NSCursor hide];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
const size_t KEY_COUNT = 128;
|
||||||
|
|
||||||
|
|
||||||
|
// See Carbon -> HIToolbox -> Events.h for kVK_ constants
|
||||||
|
|
||||||
|
const uint8_t KEYCODE_TO_DIK[KEY_COUNT] =
|
||||||
|
{
|
||||||
|
DIK_A, DIK_S, DIK_D, DIK_F, DIK_H, DIK_G, DIK_Z, DIK_X, // 0x00 - 0x07
|
||||||
|
DIK_C, DIK_V, 0, DIK_B, DIK_Q, DIK_W, DIK_E, DIK_R, // 0x08 - 0x0F
|
||||||
|
DIK_Y, DIK_T, DIK_1, DIK_2, DIK_3, DIK_4, DIK_6, DIK_5, // 0x10 - 0x17
|
||||||
|
DIK_EQUALS, DIK_9, DIK_7, DIK_MINUS, DIK_8, DIK_0, DIK_RBRACKET, DIK_O, // 0x18 - 0x1F
|
||||||
|
DIK_U, DIK_LBRACKET, DIK_I, DIK_P, DIK_RETURN, DIK_L, DIK_J, DIK_APOSTROPHE, // 0x20 - 0x27
|
||||||
|
DIK_K, DIK_SEMICOLON, DIK_BACKSLASH, DIK_COMMA, DIK_SLASH, DIK_N, DIK_M, DIK_PERIOD, // 0x28 - 0x2F
|
||||||
|
DIK_TAB, DIK_SPACE, DIK_GRAVE, DIK_BACK, 0, DIK_ESCAPE, 0, DIK_LWIN, // 0x30 - 0x37
|
||||||
|
DIK_LSHIFT, DIK_CAPITAL, DIK_LMENU, DIK_LCONTROL, DIK_RSHIFT, DIK_RMENU, DIK_RCONTROL, 0, // 0x38 - 0x3F
|
||||||
|
0, DIK_DECIMAL, 0, DIK_MULTIPLY, 0, DIK_ADD, 0, 0, // 0x40 - 0x47
|
||||||
|
DIK_VOLUMEUP, DIK_VOLUMEDOWN, DIK_MUTE, DIK_SLASH, DIK_NUMPADENTER, 0, DIK_SUBTRACT, 0, // 0x48 - 0x4F
|
||||||
|
0, DIK_NUMPAD_EQUALS, DIK_NUMPAD0, DIK_NUMPAD1, DIK_NUMPAD2, DIK_NUMPAD3, DIK_NUMPAD4, DIK_NUMPAD5, // 0x50 - 0x57
|
||||||
|
DIK_NUMPAD6, DIK_NUMPAD7, 0, DIK_NUMPAD8, DIK_NUMPAD9, 0, 0, 0, // 0x58 - 0x5F
|
||||||
|
DIK_F5, DIK_F6, DIK_F7, DIK_F3, DIK_F8, DIK_F9, 0, DIK_F11, // 0x60 - 0x67
|
||||||
|
0, DIK_F13, 0, DIK_F14, 0, DIK_F10, 0, DIK_F12, // 0x68 - 0x6F
|
||||||
|
0, DIK_F15, 0, DIK_HOME, 0, DIK_DELETE, DIK_F4, DIK_END, // 0x70 - 0x77
|
||||||
|
DIK_F2, 0, DIK_F1, DIK_LEFT, DIK_RIGHT, DIK_DOWN, DIK_UP, 0, // 0x78 - 0x7F
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t KEYCODE_TO_ASCII[KEY_COUNT] =
|
||||||
|
{
|
||||||
|
'a', 's', 'd', 'f', 'h', 'g', 'z', 'x', // 0x00 - 0x07
|
||||||
|
'c', 'v', 0, 'b', 'q', 'w', 'e', 'r', // 0x08 - 0x0F
|
||||||
|
'y', 't', '1', '2', '3', '4', '6', '5', // 0x10 - 0x17
|
||||||
|
'=', '9', '7', '-', '8', '0', ']', 'o', // 0x18 - 0x1F
|
||||||
|
'u', '[', 'i', 'p', 13, 'l', 'j', '\'', // 0x20 - 0x27
|
||||||
|
'k', ';', '\\', ',', '/', 'n', 'm', '.', // 0x28 - 0x2F
|
||||||
|
9, ' ', '`', 12, 0, 27, 0, 0, // 0x30 - 0x37
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, // 0x38 - 0x3F
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, // 0x40 - 0x47
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, // 0x48 - 0x4F
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, // 0x50 - 0x57
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, // 0x58 - 0x5F
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, // 0x60 - 0x67
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, // 0x68 - 0x6F
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, // 0x70 - 0x77
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, // 0x78 - 0x7F
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t ModifierToDIK(const uint32_t modifier)
|
||||||
|
{
|
||||||
|
switch (modifier)
|
||||||
|
{
|
||||||
|
case NSAlphaShiftKeyMask: return DIK_CAPITAL;
|
||||||
|
case NSShiftKeyMask: return DIK_LSHIFT;
|
||||||
|
case NSControlKeyMask: return DIK_LCONTROL;
|
||||||
|
case NSAlternateKeyMask: return DIK_LMENU;
|
||||||
|
case NSCommandKeyMask: return DIK_LWIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SWORD ModifierFlagsToGUIKeyModifiers(NSEvent* theEvent)
|
||||||
|
{
|
||||||
|
const NSUInteger modifiers([theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask);
|
||||||
|
return ((modifiers & NSShiftKeyMask ) ? GKM_SHIFT : 0)
|
||||||
|
| ((modifiers & NSControlKeyMask ) ? GKM_CTRL : 0)
|
||||||
|
| ((modifiers & NSAlternateKeyMask) ? GKM_ALT : 0)
|
||||||
|
| ((modifiers & NSCommandKeyMask ) ? GKM_META : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShouldGenerateGUICharEvent(NSEvent* theEvent)
|
||||||
|
{
|
||||||
|
const NSUInteger modifiers([theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask);
|
||||||
|
return !(modifiers & NSControlKeyMask)
|
||||||
|
&& !(modifiers & NSAlternateKeyMask)
|
||||||
|
&& !(modifiers & NSCommandKeyMask)
|
||||||
|
&& !(modifiers & NSFunctionKeyMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NSStringEncoding GetEncodingForUnicodeCharacter(const unichar character)
|
||||||
|
{
|
||||||
|
if (character >= L'\u0100' && character <= L'\u024F')
|
||||||
|
{
|
||||||
|
return NSWindowsCP1250StringEncoding; // Central and Eastern Europe
|
||||||
|
}
|
||||||
|
else if (character >= L'\u0370' && character <= L'\u03FF')
|
||||||
|
{
|
||||||
|
return NSWindowsCP1253StringEncoding; // Greek
|
||||||
|
}
|
||||||
|
else if (character >= L'\u0400' && character <= L'\u04FF')
|
||||||
|
{
|
||||||
|
return NSWindowsCP1251StringEncoding; // Cyrillic
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add handling for other characters
|
||||||
|
// TODO: Turkish should use NSWindowsCP1254StringEncoding
|
||||||
|
|
||||||
|
return NSWindowsCP1252StringEncoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char GetCharacterFromNSEvent(NSEvent* theEvent)
|
||||||
|
{
|
||||||
|
const NSString* unicodeCharacters = [theEvent characters];
|
||||||
|
|
||||||
|
if (0 == [unicodeCharacters length])
|
||||||
|
{
|
||||||
|
return '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
const unichar unicodeCharacter = [unicodeCharacters characterAtIndex:0];
|
||||||
|
const NSStringEncoding encoding = GetEncodingForUnicodeCharacter(unicodeCharacter);
|
||||||
|
|
||||||
|
unsigned char character = '\0';
|
||||||
|
|
||||||
|
if (NSWindowsCP1252StringEncoding == encoding)
|
||||||
|
{
|
||||||
|
// TODO: make sure that the following is always correct
|
||||||
|
character = unicodeCharacter & 0xFF;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const NSData* const characters =
|
||||||
|
[[theEvent characters] dataUsingEncoding:encoding];
|
||||||
|
|
||||||
|
character = [characters length] > 0
|
||||||
|
? *static_cast<const unsigned char*>([characters bytes])
|
||||||
|
: '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return character;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessKeyboardEventInMenu(NSEvent* theEvent)
|
||||||
|
{
|
||||||
|
event_t event = {};
|
||||||
|
|
||||||
|
event.type = EV_GUI_Event;
|
||||||
|
event.subtype = NSKeyDown == [theEvent type] ? EV_GUI_KeyDown : EV_GUI_KeyUp;
|
||||||
|
event.data2 = GetCharacterFromNSEvent(theEvent);
|
||||||
|
event.data3 = ModifierFlagsToGUIKeyModifiers(theEvent);
|
||||||
|
|
||||||
|
if (EV_GUI_KeyDown == event.subtype && [theEvent isARepeat])
|
||||||
|
{
|
||||||
|
event.subtype = EV_GUI_KeyRepeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned short keyCode = [theEvent keyCode];
|
||||||
|
|
||||||
|
switch (keyCode)
|
||||||
|
{
|
||||||
|
case kVK_Return: event.data1 = GK_RETURN; break;
|
||||||
|
case kVK_PageUp: event.data1 = GK_PGUP; break;
|
||||||
|
case kVK_PageDown: event.data1 = GK_PGDN; break;
|
||||||
|
case kVK_End: event.data1 = GK_END; break;
|
||||||
|
case kVK_Home: event.data1 = GK_HOME; break;
|
||||||
|
case kVK_LeftArrow: event.data1 = GK_LEFT; break;
|
||||||
|
case kVK_RightArrow: event.data1 = GK_RIGHT; break;
|
||||||
|
case kVK_UpArrow: event.data1 = GK_UP; break;
|
||||||
|
case kVK_DownArrow: event.data1 = GK_DOWN; break;
|
||||||
|
case kVK_Delete: event.data1 = GK_BACKSPACE; break;
|
||||||
|
case kVK_ForwardDelete: event.data1 = GK_DEL; break;
|
||||||
|
case kVK_Escape: event.data1 = GK_ESCAPE; break;
|
||||||
|
case kVK_F1: event.data1 = GK_F1; break;
|
||||||
|
case kVK_F2: event.data1 = GK_F2; break;
|
||||||
|
case kVK_F3: event.data1 = GK_F3; break;
|
||||||
|
case kVK_F4: event.data1 = GK_F4; break;
|
||||||
|
case kVK_F5: event.data1 = GK_F5; break;
|
||||||
|
case kVK_F6: event.data1 = GK_F6; break;
|
||||||
|
case kVK_F7: event.data1 = GK_F7; break;
|
||||||
|
case kVK_F8: event.data1 = GK_F8; break;
|
||||||
|
case kVK_F9: event.data1 = GK_F9; break;
|
||||||
|
case kVK_F10: event.data1 = GK_F10; break;
|
||||||
|
case kVK_F11: event.data1 = GK_F11; break;
|
||||||
|
case kVK_F12: event.data1 = GK_F12; break;
|
||||||
|
default:
|
||||||
|
event.data1 = KEYCODE_TO_ASCII[keyCode];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.data1 < 128)
|
||||||
|
{
|
||||||
|
event.data1 = toupper(event.data1);
|
||||||
|
|
||||||
|
D_PostEvent(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!iscntrl(event.data2)
|
||||||
|
&& EV_GUI_KeyUp != event.subtype
|
||||||
|
&& ShouldGenerateGUICharEvent(theEvent))
|
||||||
|
{
|
||||||
|
event.subtype = EV_GUI_Char;
|
||||||
|
event.data1 = event.data2;
|
||||||
|
event.data2 = event.data3 & GKM_ALT;
|
||||||
|
|
||||||
|
D_PostEvent(&event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NSEventToGameMousePosition(NSEvent* inEvent, event_t* outEvent)
|
||||||
|
{
|
||||||
|
const NSWindow* window = [inEvent window];
|
||||||
|
const NSView* view = [window contentView];
|
||||||
|
|
||||||
|
const NSPoint screenPos = [NSEvent mouseLocation];
|
||||||
|
const NSPoint windowPos = [window convertScreenToBase:screenPos];
|
||||||
|
|
||||||
|
const NSPoint viewPos = I_IsHiDPISupported()
|
||||||
|
? [view convertPointToBacking:windowPos]
|
||||||
|
: [view convertPoint:windowPos fromView:nil];
|
||||||
|
|
||||||
|
const CGFloat frameHeight = I_GetContentViewSize(window).height;
|
||||||
|
|
||||||
|
const CGFloat posX = ( viewPos.x - rbOpts.shiftX) / rbOpts.pixelScale;
|
||||||
|
const CGFloat posY = (frameHeight - viewPos.y - rbOpts.shiftY) / rbOpts.pixelScale;
|
||||||
|
|
||||||
|
outEvent->data1 = static_cast<int>(posX);
|
||||||
|
outEvent->data2 = static_cast<int>(posY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessMouseMoveInMenu(NSEvent* theEvent)
|
||||||
|
{
|
||||||
|
event_t event = {};
|
||||||
|
|
||||||
|
event.type = EV_GUI_Event;
|
||||||
|
event.subtype = EV_GUI_MouseMove;
|
||||||
|
|
||||||
|
NSEventToGameMousePosition(theEvent, &event);
|
||||||
|
|
||||||
|
D_PostEvent(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessMouseMoveInGame(NSEvent* theEvent)
|
||||||
|
{
|
||||||
|
if (!use_mouse)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: remove this magic!
|
||||||
|
|
||||||
|
if (s_skipMouseMoves > 0)
|
||||||
|
{
|
||||||
|
--s_skipMouseMoves;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int x([theEvent deltaX]);
|
||||||
|
int y(-[theEvent deltaY]);
|
||||||
|
|
||||||
|
if (0 == x && 0 == y)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_noprescale)
|
||||||
|
{
|
||||||
|
x *= 3;
|
||||||
|
y *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
event_t event = {};
|
||||||
|
|
||||||
|
static int lastX = 0, lastY = 0;
|
||||||
|
|
||||||
|
if (m_filter)
|
||||||
|
{
|
||||||
|
event.x = (x + lastX) / 2;
|
||||||
|
event.y = (y + lastY) / 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
event.x = x;
|
||||||
|
event.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastX = x;
|
||||||
|
lastY = y;
|
||||||
|
|
||||||
|
if (0 != event.x | 0 != event.y)
|
||||||
|
{
|
||||||
|
event.type = EV_Mouse;
|
||||||
|
|
||||||
|
D_PostEvent(&event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ProcessKeyboardEvent(NSEvent* theEvent)
|
||||||
|
{
|
||||||
|
const unsigned short keyCode = [theEvent keyCode];
|
||||||
|
if (keyCode >= KEY_COUNT)
|
||||||
|
{
|
||||||
|
assert(!"Unknown keycode");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GUICapture)
|
||||||
|
{
|
||||||
|
ProcessKeyboardEventInMenu(theEvent);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
event_t event = {};
|
||||||
|
|
||||||
|
event.type = NSKeyDown == [theEvent type] ? EV_KeyDown : EV_KeyUp;
|
||||||
|
event.data1 = KEYCODE_TO_DIK[ keyCode ];
|
||||||
|
|
||||||
|
if (0 != event.data1)
|
||||||
|
{
|
||||||
|
event.data2 = KEYCODE_TO_ASCII[ keyCode ];
|
||||||
|
|
||||||
|
D_PostEvent(&event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessKeyboardFlagsEvent(NSEvent* theEvent)
|
||||||
|
{
|
||||||
|
static const uint32_t FLAGS_MASK =
|
||||||
|
NSDeviceIndependentModifierFlagsMask & ~NSNumericPadKeyMask;
|
||||||
|
|
||||||
|
const uint32_t modifiers = [theEvent modifierFlags] & FLAGS_MASK;
|
||||||
|
static uint32_t oldModifiers = 0;
|
||||||
|
const uint32_t deltaModifiers = modifiers ^ oldModifiers;
|
||||||
|
|
||||||
|
if (0 == deltaModifiers)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event_t event = {};
|
||||||
|
|
||||||
|
event.type = modifiers > oldModifiers ? EV_KeyDown : EV_KeyUp;
|
||||||
|
event.data1 = ModifierToDIK(deltaModifiers);
|
||||||
|
|
||||||
|
oldModifiers = modifiers;
|
||||||
|
|
||||||
|
// Caps Lock is a modifier key which generates one event per state change
|
||||||
|
// but not per actual key press or release. So treat any event as key down
|
||||||
|
// Also its event should be not be posted in menu and console
|
||||||
|
|
||||||
|
if (DIK_CAPITAL == event.data1)
|
||||||
|
{
|
||||||
|
if (GUICapture)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.type = EV_KeyDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
D_PostEvent(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ProcessMouseMoveEvent(NSEvent* theEvent)
|
||||||
|
{
|
||||||
|
if (GUICapture)
|
||||||
|
{
|
||||||
|
ProcessMouseMoveInMenu(theEvent);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ProcessMouseMoveInGame(theEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessMouseButtonEvent(NSEvent* theEvent)
|
||||||
|
{
|
||||||
|
event_t event = {};
|
||||||
|
|
||||||
|
const NSEventType cocoaEventType = [theEvent type];
|
||||||
|
|
||||||
|
if (GUICapture)
|
||||||
|
{
|
||||||
|
event.type = EV_GUI_Event;
|
||||||
|
|
||||||
|
switch (cocoaEventType)
|
||||||
|
{
|
||||||
|
case NSLeftMouseDown: event.subtype = EV_GUI_LButtonDown; break;
|
||||||
|
case NSRightMouseDown: event.subtype = EV_GUI_RButtonDown; break;
|
||||||
|
case NSOtherMouseDown: event.subtype = EV_GUI_MButtonDown; break;
|
||||||
|
case NSLeftMouseUp: event.subtype = EV_GUI_LButtonUp; break;
|
||||||
|
case NSRightMouseUp: event.subtype = EV_GUI_RButtonUp; break;
|
||||||
|
case NSOtherMouseUp: event.subtype = EV_GUI_MButtonUp; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSEventToGameMousePosition(theEvent, &event);
|
||||||
|
|
||||||
|
D_PostEvent(&event);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (cocoaEventType)
|
||||||
|
{
|
||||||
|
case NSLeftMouseDown:
|
||||||
|
case NSRightMouseDown:
|
||||||
|
case NSOtherMouseDown:
|
||||||
|
event.type = EV_KeyDown;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NSLeftMouseUp:
|
||||||
|
case NSRightMouseUp:
|
||||||
|
case NSOtherMouseUp:
|
||||||
|
event.type = EV_KeyUp;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.data1 = MIN(KEY_MOUSE1 + [theEvent buttonNumber], NSInteger(KEY_MOUSE8));
|
||||||
|
|
||||||
|
D_PostEvent(&event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessMouseWheelEvent(NSEvent* theEvent)
|
||||||
|
{
|
||||||
|
const CGFloat delta = [theEvent deltaY];
|
||||||
|
const bool isZeroDelta = fabs(delta) < 1.0E-5;
|
||||||
|
|
||||||
|
if (isZeroDelta && GUICapture)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event_t event = {};
|
||||||
|
|
||||||
|
if (GUICapture)
|
||||||
|
{
|
||||||
|
event.type = EV_GUI_Event;
|
||||||
|
event.subtype = delta > 0.0f ? EV_GUI_WheelUp : EV_GUI_WheelDown;
|
||||||
|
event.data3 = delta;
|
||||||
|
event.data3 = ModifierFlagsToGUIKeyModifiers(theEvent);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
event.type = isZeroDelta ? EV_KeyUp : EV_KeyDown;
|
||||||
|
event.data1 = delta > 0.0f ? KEY_MWHEELUP : KEY_MWHEELDOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
D_PostEvent(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
|
||||||
|
|
||||||
|
void I_ProcessEvent(NSEvent* event)
|
||||||
|
{
|
||||||
|
const NSEventType eventType = [event type];
|
||||||
|
|
||||||
|
switch (eventType)
|
||||||
|
{
|
||||||
|
case NSMouseMoved:
|
||||||
|
ProcessMouseMoveEvent(event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NSLeftMouseDown:
|
||||||
|
case NSLeftMouseUp:
|
||||||
|
case NSRightMouseDown:
|
||||||
|
case NSRightMouseUp:
|
||||||
|
case NSOtherMouseDown:
|
||||||
|
case NSOtherMouseUp:
|
||||||
|
ProcessMouseButtonEvent(event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NSLeftMouseDragged:
|
||||||
|
case NSRightMouseDragged:
|
||||||
|
case NSOtherMouseDragged:
|
||||||
|
ProcessMouseButtonEvent(event);
|
||||||
|
ProcessMouseMoveEvent(event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NSScrollWheel:
|
||||||
|
ProcessMouseWheelEvent(event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NSKeyDown:
|
||||||
|
case NSKeyUp:
|
||||||
|
ProcessKeyboardEvent(event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NSFlagsChanged:
|
||||||
|
ProcessKeyboardFlagsEvent(event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
581
src/posix/cocoa/i_main.mm
Normal file
581
src/posix/cocoa/i_main.mm
Normal file
|
@ -0,0 +1,581 @@
|
||||||
|
/*
|
||||||
|
** i_main.mm
|
||||||
|
**
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
** 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 <sys/sysctl.h>
|
||||||
|
|
||||||
|
#import <AppKit/NSMenu.h>
|
||||||
|
#import <AppKit/NSEvent.h>
|
||||||
|
|
||||||
|
// Avoid collision between DObject class and Objective-C
|
||||||
|
#define Class ObjectClass
|
||||||
|
|
||||||
|
#include "c_console.h"
|
||||||
|
#include "c_cvars.h"
|
||||||
|
#include "cmdlib.h"
|
||||||
|
#include "d_main.h"
|
||||||
|
#include "doomerrors.h"
|
||||||
|
#include "i_system.h"
|
||||||
|
#include "m_argv.h"
|
||||||
|
#include "s_sound.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
#include "i_common.h"
|
||||||
|
#include "i_osversion.h"
|
||||||
|
|
||||||
|
#undef Class
|
||||||
|
|
||||||
|
|
||||||
|
#define ZD_UNUSED(VARIABLE) ((void)(VARIABLE))
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
EXTERN_CVAR(Int, vid_defwidth )
|
||||||
|
EXTERN_CVAR(Int, vid_defheight)
|
||||||
|
EXTERN_CVAR(Bool, vid_vsync )
|
||||||
|
EXTERN_CVAR(Bool, fullscreen )
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
// The maximum number of functions that can be registered with atterm.
|
||||||
|
const size_t MAX_TERMS = 64;
|
||||||
|
|
||||||
|
void (*TermFuncs[MAX_TERMS])();
|
||||||
|
const char *TermNames[MAX_TERMS];
|
||||||
|
size_t NumTerms;
|
||||||
|
|
||||||
|
void call_terms()
|
||||||
|
{
|
||||||
|
while (NumTerms > 0)
|
||||||
|
{
|
||||||
|
TermFuncs[--NumTerms]();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
|
||||||
|
|
||||||
|
void addterm(void (*func)(), const char *name)
|
||||||
|
{
|
||||||
|
// Make sure this function wasn't already registered.
|
||||||
|
|
||||||
|
for (size_t i = 0; i < NumTerms; ++i)
|
||||||
|
{
|
||||||
|
if (TermFuncs[i] == func)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NumTerms == MAX_TERMS)
|
||||||
|
{
|
||||||
|
func();
|
||||||
|
I_FatalError("Too many exit functions registered.");
|
||||||
|
}
|
||||||
|
|
||||||
|
TermNames[NumTerms] = name;
|
||||||
|
TermFuncs[NumTerms] = func;
|
||||||
|
|
||||||
|
++NumTerms;
|
||||||
|
}
|
||||||
|
|
||||||
|
void popterm()
|
||||||
|
{
|
||||||
|
if (NumTerms)
|
||||||
|
{
|
||||||
|
--NumTerms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Mac_I_FatalError(const char* const message)
|
||||||
|
{
|
||||||
|
I_SetMainWindowVisible(false);
|
||||||
|
|
||||||
|
const CFStringRef errorString = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault,
|
||||||
|
message, kCFStringEncodingASCII, kCFAllocatorNull);
|
||||||
|
|
||||||
|
if (NULL != errorString)
|
||||||
|
{
|
||||||
|
CFOptionFlags dummy;
|
||||||
|
|
||||||
|
CFUserNotificationDisplayAlert( 0, kCFUserNotificationStopAlertLevel, NULL, NULL, NULL,
|
||||||
|
CFSTR("Fatal Error"), errorString, CFSTR("Exit"), NULL, NULL, &dummy);
|
||||||
|
|
||||||
|
CFRelease(errorString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DArgs* Args; // command line arguments
|
||||||
|
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
const int ARGC_MAX = 64;
|
||||||
|
|
||||||
|
int s_argc;
|
||||||
|
char* s_argv[ARGC_MAX];
|
||||||
|
|
||||||
|
TArray<FString> s_argvStorage;
|
||||||
|
|
||||||
|
bool s_restartedFromWADPicker;
|
||||||
|
|
||||||
|
|
||||||
|
void NewFailure()
|
||||||
|
{
|
||||||
|
I_FatalError("Failed to allocate memory from system heap");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int OriginalMain(int argc, char** argv)
|
||||||
|
{
|
||||||
|
printf(GAMENAME" %s - %s - Cocoa version\nCompiled on %s\n\n",
|
||||||
|
GetVersionString(), GetGitTime(), __DATE__);
|
||||||
|
|
||||||
|
seteuid(getuid());
|
||||||
|
std::set_new_handler(NewFailure);
|
||||||
|
|
||||||
|
// Set LC_NUMERIC environment variable in case some library decides to
|
||||||
|
// clear the setlocale call at least this will be correct.
|
||||||
|
// Note that the LANG environment variable is overridden by LC_*
|
||||||
|
setenv("LC_NUMERIC", "C", 1);
|
||||||
|
setlocale(LC_ALL, "C");
|
||||||
|
|
||||||
|
// Set reasonable default values for video settings
|
||||||
|
|
||||||
|
const NSSize screenSize = [[NSScreen mainScreen] frame].size;
|
||||||
|
vid_defwidth = static_cast<int>(screenSize.width);
|
||||||
|
vid_defheight = static_cast<int>(screenSize.height);
|
||||||
|
vid_vsync = true;
|
||||||
|
fullscreen = true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Args = new DArgs(argc, argv);
|
||||||
|
|
||||||
|
/*
|
||||||
|
killough 1/98:
|
||||||
|
|
||||||
|
This fixes some problems with exit handling
|
||||||
|
during abnormal situations.
|
||||||
|
|
||||||
|
The old code called I_Quit() to end program,
|
||||||
|
while now I_Quit() is installed as an exit
|
||||||
|
handler and exit() is called to exit, either
|
||||||
|
normally or abnormally. Seg faults are caught
|
||||||
|
and the error handler is used, to prevent
|
||||||
|
being left in graphics mode or having very
|
||||||
|
loud SFX noise because the sound card is
|
||||||
|
left in an unstable state.
|
||||||
|
*/
|
||||||
|
|
||||||
|
atexit(call_terms);
|
||||||
|
atterm(I_Quit);
|
||||||
|
|
||||||
|
NSString* exePath = [[NSBundle mainBundle] executablePath];
|
||||||
|
progdir = [[exePath stringByDeletingLastPathComponent] UTF8String];
|
||||||
|
progdir += "/";
|
||||||
|
|
||||||
|
I_StartupJoysticks();
|
||||||
|
atterm(I_ShutdownJoysticks);
|
||||||
|
|
||||||
|
C_InitConsole(80 * 8, 25 * 8, false);
|
||||||
|
D_DoomMain();
|
||||||
|
}
|
||||||
|
catch(const CDoomError& error)
|
||||||
|
{
|
||||||
|
const char* const message = error.GetMessage();
|
||||||
|
|
||||||
|
if (NULL != message)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s\n", message);
|
||||||
|
Mac_I_FatalError(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
call_terms();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@interface ApplicationController : NSResponder
|
||||||
|
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||||
|
<NSFileManagerDelegate>
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)keyDown:(NSEvent*)theEvent;
|
||||||
|
- (void)keyUp:(NSEvent*)theEvent;
|
||||||
|
|
||||||
|
- (void)applicationDidBecomeActive:(NSNotification*)aNotification;
|
||||||
|
- (void)applicationWillResignActive:(NSNotification*)aNotification;
|
||||||
|
|
||||||
|
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification;
|
||||||
|
|
||||||
|
- (BOOL)application:(NSApplication*)theApplication openFile:(NSString*)filename;
|
||||||
|
|
||||||
|
- (void)processEvents:(NSTimer*)timer;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
ApplicationController* appCtrl;
|
||||||
|
|
||||||
|
|
||||||
|
@implementation ApplicationController
|
||||||
|
|
||||||
|
- (void)keyDown:(NSEvent*)theEvent
|
||||||
|
{
|
||||||
|
// Empty but present to avoid playing of 'beep' alert sound
|
||||||
|
|
||||||
|
ZD_UNUSED(theEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)keyUp:(NSEvent*)theEvent
|
||||||
|
{
|
||||||
|
// Empty but present to avoid playing of 'beep' alert sound
|
||||||
|
|
||||||
|
ZD_UNUSED(theEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)applicationDidBecomeActive:(NSNotification*)aNotification
|
||||||
|
{
|
||||||
|
ZD_UNUSED(aNotification);
|
||||||
|
|
||||||
|
S_SetSoundPaused(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationWillResignActive:(NSNotification*)aNotification
|
||||||
|
{
|
||||||
|
ZD_UNUSED(aNotification);
|
||||||
|
|
||||||
|
S_SetSoundPaused(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification
|
||||||
|
{
|
||||||
|
// When starting from command line with real executable path, e.g. ZDoom.app/Contents/MacOS/ZDoom
|
||||||
|
// application remains deactivated for an unknown reason.
|
||||||
|
// The following call resolves this issue
|
||||||
|
[NSApp activateIgnoringOtherApps:YES];
|
||||||
|
|
||||||
|
// Setup timer for custom event loop
|
||||||
|
|
||||||
|
NSTimer* timer = [NSTimer timerWithTimeInterval:0
|
||||||
|
target:self
|
||||||
|
selector:@selector(processEvents:)
|
||||||
|
userInfo:nil
|
||||||
|
repeats:YES];
|
||||||
|
[[NSRunLoop currentRunLoop] addTimer:timer
|
||||||
|
forMode:NSDefaultRunLoopMode];
|
||||||
|
|
||||||
|
exit(OriginalMain(s_argc, s_argv));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (BOOL)application:(NSApplication*)theApplication openFile:(NSString*)filename
|
||||||
|
{
|
||||||
|
ZD_UNUSED(theApplication);
|
||||||
|
|
||||||
|
if (s_restartedFromWADPicker
|
||||||
|
|| 0 == [filename length]
|
||||||
|
|| s_argc + 2 >= ARGC_MAX)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some parameters from command line are passed to this function
|
||||||
|
// These parameters need to be skipped to avoid duplication
|
||||||
|
// Note: SDL has different approach to fix this issue, see the same method in SDLMain.m
|
||||||
|
|
||||||
|
const char* const charFileName = [filename UTF8String];
|
||||||
|
|
||||||
|
for (int i = 0; i < s_argc; ++i)
|
||||||
|
{
|
||||||
|
if (0 == strcmp(s_argv[i], charFileName))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s_argvStorage.Push("-file");
|
||||||
|
s_argv[s_argc++] = s_argvStorage.Last().LockBuffer();
|
||||||
|
|
||||||
|
s_argvStorage.Push([filename UTF8String]);
|
||||||
|
s_argv[s_argc++] = s_argvStorage.Last().LockBuffer();
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void)processEvents:(NSTimer*)timer
|
||||||
|
{
|
||||||
|
ZD_UNUSED(timer);
|
||||||
|
|
||||||
|
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
|
||||||
|
untilDate:[NSDate dateWithTimeIntervalSinceNow:0]
|
||||||
|
inMode:NSDefaultRunLoopMode
|
||||||
|
dequeue:YES];
|
||||||
|
if (nil == event)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
I_ProcessEvent(event);
|
||||||
|
|
||||||
|
[NSApp sendEvent:event];
|
||||||
|
}
|
||||||
|
|
||||||
|
[NSApp updateWindows];
|
||||||
|
|
||||||
|
[pool release];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
NSMenuItem* CreateApplicationMenu()
|
||||||
|
{
|
||||||
|
NSMenu* menu = [NSMenu new];
|
||||||
|
|
||||||
|
[menu addItemWithTitle:[@"About " stringByAppendingString:@GAMENAME]
|
||||||
|
action:@selector(orderFrontStandardAboutPanel:)
|
||||||
|
keyEquivalent:@""];
|
||||||
|
[menu addItem:[NSMenuItem separatorItem]];
|
||||||
|
[menu addItemWithTitle:[@"Hide " stringByAppendingString:@GAMENAME]
|
||||||
|
action:@selector(hide:)
|
||||||
|
keyEquivalent:@"h"];
|
||||||
|
[[menu addItemWithTitle:@"Hide Others"
|
||||||
|
action:@selector(hideOtherApplications:)
|
||||||
|
keyEquivalent:@"h"]
|
||||||
|
setKeyEquivalentModifierMask:NSAlternateKeyMask | NSCommandKeyMask];
|
||||||
|
[menu addItemWithTitle:@"Show All"
|
||||||
|
action:@selector(unhideAllApplications:)
|
||||||
|
keyEquivalent:@""];
|
||||||
|
[menu addItem:[NSMenuItem separatorItem]];
|
||||||
|
[menu addItemWithTitle:[@"Quit " stringByAppendingString:@GAMENAME]
|
||||||
|
action:@selector(terminate:)
|
||||||
|
keyEquivalent:@"q"];
|
||||||
|
|
||||||
|
NSMenuItem* menuItem = [NSMenuItem new];
|
||||||
|
[menuItem setSubmenu:menu];
|
||||||
|
|
||||||
|
if ([NSApp respondsToSelector:@selector(setAppleMenu:)])
|
||||||
|
{
|
||||||
|
[NSApp performSelector:@selector(setAppleMenu:) withObject:menu];
|
||||||
|
}
|
||||||
|
|
||||||
|
return menuItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMenuItem* CreateEditMenu()
|
||||||
|
{
|
||||||
|
NSMenu* menu = [[NSMenu alloc] initWithTitle:@"Edit"];
|
||||||
|
|
||||||
|
[menu addItemWithTitle:@"Undo"
|
||||||
|
action:@selector(undo:)
|
||||||
|
keyEquivalent:@"z"];
|
||||||
|
[menu addItemWithTitle:@"Redo"
|
||||||
|
action:@selector(redo:)
|
||||||
|
keyEquivalent:@"Z"];
|
||||||
|
[menu addItem:[NSMenuItem separatorItem]];
|
||||||
|
[menu addItemWithTitle:@"Cut"
|
||||||
|
action:@selector(cut:)
|
||||||
|
keyEquivalent:@"x"];
|
||||||
|
[menu addItemWithTitle:@"Copy"
|
||||||
|
action:@selector(copy:)
|
||||||
|
keyEquivalent:@"c"];
|
||||||
|
[menu addItemWithTitle:@"Paste"
|
||||||
|
action:@selector(paste:)
|
||||||
|
keyEquivalent:@"v"];
|
||||||
|
[menu addItemWithTitle:@"Delete"
|
||||||
|
action:@selector(delete:)
|
||||||
|
keyEquivalent:@""];
|
||||||
|
[menu addItemWithTitle:@"Select All"
|
||||||
|
action:@selector(selectAll:)
|
||||||
|
keyEquivalent:@"a"];
|
||||||
|
|
||||||
|
NSMenuItem* menuItem = [NSMenuItem new];
|
||||||
|
[menuItem setSubmenu:menu];
|
||||||
|
|
||||||
|
return menuItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMenuItem* CreateWindowMenu()
|
||||||
|
{
|
||||||
|
NSMenu* menu = [[NSMenu alloc] initWithTitle:@"Window"];
|
||||||
|
[NSApp setWindowsMenu:menu];
|
||||||
|
|
||||||
|
[menu addItemWithTitle:@"Minimize"
|
||||||
|
action:@selector(performMiniaturize:)
|
||||||
|
keyEquivalent:@"m"];
|
||||||
|
[menu addItemWithTitle:@"Zoom"
|
||||||
|
action:@selector(performZoom:)
|
||||||
|
keyEquivalent:@""];
|
||||||
|
[menu addItem:[NSMenuItem separatorItem]];
|
||||||
|
[menu addItemWithTitle:@"Bring All to Front"
|
||||||
|
action:@selector(arrangeInFront:)
|
||||||
|
keyEquivalent:@""];
|
||||||
|
|
||||||
|
NSMenuItem* menuItem = [NSMenuItem new];
|
||||||
|
[menuItem setSubmenu:menu];
|
||||||
|
|
||||||
|
return menuItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateMenu()
|
||||||
|
{
|
||||||
|
NSMenu* menuBar = [NSMenu new];
|
||||||
|
[menuBar addItem:CreateApplicationMenu()];
|
||||||
|
[menuBar addItem:CreateEditMenu()];
|
||||||
|
[menuBar addItem:CreateWindowMenu()];
|
||||||
|
|
||||||
|
[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)
|
||||||
|
{
|
||||||
|
[NSApp setDelegate:nil];
|
||||||
|
[NSApp deactivate];
|
||||||
|
|
||||||
|
[appCtrl release];
|
||||||
|
appCtrl = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
|
||||||
|
|
||||||
|
const DarwinVersion darwinVersion = GetDarwinVersion();
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
for (int i = 0; i <= argc; ++i)
|
||||||
|
{
|
||||||
|
const char* const argument = argv[i];
|
||||||
|
|
||||||
|
if (NULL == argument || '\0' == argument[0])
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == strcmp(argument, "-wad_picker_restart"))
|
||||||
|
{
|
||||||
|
s_restartedFromWADPicker = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s_argvStorage.Push(argument);
|
||||||
|
s_argv[s_argc++] = s_argvStorage.Last().LockBuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
|
||||||
|
[NSApplication sharedApplication];
|
||||||
|
|
||||||
|
// The following code isn't mandatory,
|
||||||
|
// but it enables to run the application without a bundle
|
||||||
|
if ([NSApp respondsToSelector:@selector(setActivationPolicy:)])
|
||||||
|
{
|
||||||
|
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateMenu();
|
||||||
|
|
||||||
|
atterm(ReleaseApplicationController);
|
||||||
|
|
||||||
|
appCtrl = [ApplicationController new];
|
||||||
|
[NSApp setDelegate:appCtrl];
|
||||||
|
[NSApp run];
|
||||||
|
|
||||||
|
[pool release];
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
1234
src/posix/cocoa/i_video.mm
Normal file
1234
src/posix/cocoa/i_video.mm
Normal file
File diff suppressed because it is too large
Load diff
|
@ -485,7 +485,7 @@ fail:
|
||||||
sample_t *tmp;
|
sample_t *tmp;
|
||||||
for (i = sp->data_length, tmp = sp->data; i; --i)
|
for (i = sp->data_length, tmp = sp->data; i; --i)
|
||||||
{
|
{
|
||||||
a = abs(*tmp++);
|
a = fabsf(*tmp++);
|
||||||
if (a > maxamp)
|
if (a > maxamp)
|
||||||
maxamp = a;
|
maxamp = a;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue