diff --git a/FindSDL2.cmake b/FindSDL2.cmake new file mode 100644 index 000000000..614426ccc --- /dev/null +++ b/FindSDL2.cmake @@ -0,0 +1,180 @@ +# Locate SDL2 library +# This module defines +# SDL2_LIBRARY, the name of the library to link against +# SDL2_FOUND, if false, do not try to link to SDL2 +# SDL2_INCLUDE_DIR, where to find SDL.h +# +# This module responds to the the flag: +# SDL2_BUILDING_LIBRARY +# If this is defined, then no SDL2_main will be linked in because +# only applications need main(). +# Otherwise, it is assumed you are building an application and this +# module will attempt to locate and set the the proper link flags +# as part of the returned SDL2_LIBRARY variable. +# +# Don't forget to include SDL2main.h and SDL2main.m your project for the +# OS X framework based version. (Other versions link to -lSDL2main which +# this module will try to find on your behalf.) Also for OS X, this +# module will automatically add the -framework Cocoa on your behalf. +# +# +# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration +# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library +# (SDL2.dll, libsdl2.so, SDL2.framework, etc). +# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again. +# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value +# as appropriate. These values are used to generate the final SDL2_LIBRARY +# variable, but when these values are unset, SDL2_LIBRARY does not get created. +# +# +# $SDL2DIR is an environment variable that would +# correspond to the ./configure --prefix=$SDL2DIR +# used in building SDL2. +# l.e.galup 9-20-02 +# +# Modified by Eric Wing. +# Added code to assist with automated building by using environmental variables +# and providing a more controlled/consistent search behavior. +# Added new modifications to recognize OS X frameworks and +# additional Unix paths (FreeBSD, etc). +# Also corrected the header search path to follow "proper" SDL2 guidelines. +# Added a search for SDL2main which is needed by some platforms. +# Added a search for threads which is needed by some platforms. +# Added needed compile switches for MinGW. +# +# On OSX, this will prefer the Framework version (if found) over others. +# People will have to manually change the cache values of +# SDL2_LIBRARY to override this selection or set the CMake environment +# CMAKE_INCLUDE_PATH to modify the search paths. +# +# Note that the header path has changed from SDL2/SDL.h to just SDL.h +# This needed to change because "proper" SDL2 convention +# is #include "SDL.h", not . This is done for portability +# reasons because not all systems place things in SDL2/ (see FreeBSD). +# +# Ported by Johnny Patterson. This is a literal port for SDL2 of the FindSDL.cmake +# module with the minor edit of changing "SDL" to "SDL2" where necessary. This +# was not created for redistribution, and exists temporarily pending official +# SDL2 CMake modules. + +#============================================================================= +# Copyright 2003-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +FIND_PATH(SDL2_INCLUDE_DIR SDL.h + HINTS + $ENV{SDL2DIR} + PATH_SUFFIXES include/SDL2 include + PATHS + ~/Library/Frameworks + /Library/Frameworks + /usr/local/include/SDL2 + /usr/include/SDL2 + /sw # Fink + /opt/local # DarwinPorts + /opt/csw # Blastwave + /opt +) +#MESSAGE("SDL2_INCLUDE_DIR is ${SDL2_INCLUDE_DIR}") + +FIND_LIBRARY(SDL2_LIBRARY_TEMP + NAMES SDL2 + HINTS + $ENV{SDL2DIR} + PATH_SUFFIXES lib64 lib + PATHS + /sw + /opt/local + /opt/csw + /opt +) + +#MESSAGE("SDL2_LIBRARY_TEMP is ${SDL2_LIBRARY_TEMP}") + +IF(NOT SDL2_BUILDING_LIBRARY) + IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") + # Non-OS X framework versions expect you to also dynamically link to + # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms + # seem to provide SDL2main for compatibility even though they don't + # necessarily need it. + FIND_LIBRARY(SDL2MAIN_LIBRARY + NAMES SDL2main + HINTS + $ENV{SDL2DIR} + PATH_SUFFIXES lib64 lib + PATHS + /sw + /opt/local + /opt/csw + /opt + ) + ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") +ENDIF(NOT SDL2_BUILDING_LIBRARY) + +# SDL2 may require threads on your system. +# The Apple build may not need an explicit flag because one of the +# frameworks may already provide it. +# But for non-OSX systems, I will use the CMake Threads package. +IF(NOT APPLE) + FIND_PACKAGE(Threads) +ENDIF(NOT APPLE) + +# MinGW needs an additional library, mwindows +# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows +# (Actually on second look, I think it only needs one of the m* libraries.) +IF(MINGW) + SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW") +ENDIF(MINGW) + +SET(SDL2_FOUND "NO") +IF(SDL2_LIBRARY_TEMP) + # For SDL2main + IF(NOT SDL2_BUILDING_LIBRARY) + IF(SDL2MAIN_LIBRARY) + SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP}) + ENDIF(SDL2MAIN_LIBRARY) + ENDIF(NOT SDL2_BUILDING_LIBRARY) + + # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. + # CMake doesn't display the -framework Cocoa string in the UI even + # though it actually is there if I modify a pre-used variable. + # I think it has something to do with the CACHE STRING. + # So I use a temporary variable until the end so I can set the + # "real" variable in one-shot. + IF(APPLE) + SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa") + ENDIF(APPLE) + + # For threads, as mentioned Apple doesn't need this. + # In fact, there seems to be a problem if I used the Threads package + # and try using this line, so I'm just skipping it entirely for OS X. + IF(NOT APPLE) + SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT}) + ENDIF(NOT APPLE) + + # For MinGW library + IF(MINGW) + SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP}) + ENDIF(MINGW) + + # Set the final string here so the GUI reflects the final state. + SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found") + # Set the temp variable to INTERNAL so it is not seen in the CMake GUI + SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "") + + SET(SDL2_FOUND "YES") +ENDIF(SDL2_LIBRARY_TEMP) + +INCLUDE(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 + REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR) diff --git a/output_sdl/CMakeLists.txt b/output_sdl/CMakeLists.txt index 289f6f48d..cc3614656 100644 --- a/output_sdl/CMakeLists.txt +++ b/output_sdl/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required( VERSION 2.4 ) add_library( output_sdl MODULE output_sdl.c ) -include_directories( ${FMOD_INCLUDE_DIR} ${SDL_INCLUDE_DIR} ) -target_link_libraries( output_sdl SDL ) +include_directories( ${FMOD_INCLUDE_DIR} ${SDL2_INCLUDE_DIR} ) +target_link_libraries( output_sdl ${SDL2_LIBRARY} ) FILE( WRITE ${CMAKE_CURRENT_BINARY_DIR}/link-make "if [ ! -e ${ZDOOM_OUTPUT_DIR}/liboutput_sdl.so ]; then ln -sf output_sdl/liboutput_sdl.so ${ZDOOM_OUTPUT_DIR}/liboutput_sdl.so; fi" ) add_custom_command( TARGET output_sdl POST_BUILD diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a54488e20..271ead5a1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -191,19 +191,6 @@ else( WIN32 ) set( NO_GTK ON ) endif( GTK2_FOUND ) endif( NOT NO_GTK ) - - # Check for Xcursor library and header files - find_library( XCURSOR_LIB Xcursor ) - if( XCURSOR_LIB ) - find_file( XCURSOR_HEADER "X11/Xcursor/Xcursor.h" ) - if( XCURSOR_HEADER ) - add_definitions( -DUSE_XCURSOR=1 ) - message( STATUS "Found Xcursor at ${XCURSOR_LIB}" ) - set( ZDOOM_LIBS ${ZDOOM_LIBS} ${XCURSOR_LIB} ) - else( XCURSOR_HEADER ) - unset( XCURSOR_LIB ) - endif( XCURSOR_HEADER ) - endif( XCURSOR_LIB ) endif( APPLE ) set( NASM_NAMES nasm ) @@ -211,15 +198,12 @@ else( WIN32 ) add_definitions( -DNO_GTK=1 ) endif( NO_GTK ) - # Non-Windows version also needs SDL - find_package( SDL ) - if( NOT SDL_FOUND ) - message( SEND_ERROR "SDL is required for building." ) - endif( NOT SDL_FOUND ) + # Non-Windows version also needs SDL except native OS X backend if( NOT APPLE OR NOT OSX_COCOA_BACKEND ) - set( ZDOOM_LIBS ${ZDOOM_LIBS} "${SDL_LIBRARY}" ) + find_package( SDL2 REQUIRED ) + include_directories( "${SDL2_INCLUDE_DIR}" ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} "${SDL2_LIBRARY}" ) endif( NOT APPLE OR NOT OSX_COCOA_BACKEND ) - include_directories( "${SDL_INCLUDE_DIR}" ) find_path( FPU_CONTROL_DIR fpu_control.h ) if( FPU_CONTROL_DIR ) @@ -563,57 +547,36 @@ set( PLAT_WIN32_SOURCES win32/i_system.cpp win32/st_start.cpp win32/win32video.cpp ) -set( PLAT_SDL_SYSTEM_SOURCES - sdl/crashcatcher.c - sdl/hardware.cpp - sdl/i_cd.cpp - sdl/i_main.cpp - sdl/i_movie.cpp - sdl/i_steam.cpp - sdl/i_system.cpp - sdl/sdlvideo.cpp - sdl/st_start.cpp ) -set( PLAT_SDL_SPECIAL_SOURCES - sdl/i_gui.cpp - sdl/i_input.cpp - sdl/i_joystick.cpp - sdl/i_timer.cpp ) -set( PLAT_MAC_SOURCES - sdl/iwadpicker_cocoa.mm - sdl/i_system_cocoa.mm ) +set( PLAT_POSIX_SOURCES + posix/i_cd.cpp + posix/i_movie.cpp + posix/i_steam.cpp + posix/i_system.cpp + posix/st_start.cpp ) +set( PLAT_SDL_SOURCES + posix/sdl/crashcatcher.c + posix/sdl/hardware.cpp + posix/sdl/i_gui.cpp + posix/sdl/i_input.cpp + posix/sdl/i_joystick.cpp + posix/sdl/i_main.cpp + posix/sdl/i_timer.cpp + posix/sdl/sdlvideo.cpp ) +set( PLAT_OSX_SOURCES + posix/osx/iwadpicker_cocoa.mm + posix/osx/zdoom.icns ) set( PLAT_COCOA_SOURCES - cocoa/HID_Config_Utilities.c - cocoa/HID_Error_Handler.c - cocoa/HID_Name_Lookup.c - cocoa/HID_Queue_Utilities.c - cocoa/HID_Utilities.c - cocoa/IOHIDDevice_.c - cocoa/IOHIDElement_.c - cocoa/ImmrHIDUtilAddOn.c - cocoa/i_backend_cocoa.mm - cocoa/i_joystick.cpp - cocoa/i_timer.cpp - cocoa/zdoom.icns ) - -if( APPLE ) - set( PLAT_SDL_SOURCES ${PLAT_SDL_SYSTEM_SOURCES} "${FMOD_LIBRARY}" ) - - if( OSX_COCOA_BACKEND ) - set( PLAT_MAC_SOURCES ${PLAT_MAC_SOURCES} ${PLAT_COCOA_SOURCES} ) - else( OSX_COCOA_BACKEND ) - set( PLAT_MAC_SOURCES ${PLAT_MAC_SOURCES} ${PLAT_SDL_SPECIAL_SOURCES} sdl/SDLMain.m ) - endif( OSX_COCOA_BACKEND ) - - set_source_files_properties( cocoa/zdoom.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources ) - set_source_files_properties( "${FMOD_LIBRARY}" PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks ) -else( APPLE ) - set( PLAT_SDL_SOURCES ${PLAT_SDL_SYSTEM_SOURCES} ${PLAT_SDL_SPECIAL_SOURCES} ) -endif( APPLE ) + posix/cocoa/critsec.cpp + posix/cocoa/i_input.mm + posix/cocoa/i_joystick.cpp + posix/cocoa/i_main.mm + posix/cocoa/i_timer.cpp + posix/cocoa/i_video.mm ) if( WIN32 ) set( SYSTEM_SOURCES_DIR win32 ) set( SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} ) - set( OTHER_SYSTEM_SOURCES ${PLAT_SDL_SOURCES} ${PLAT_MAC_SOURCES} ) + set( OTHER_SYSTEM_SOURCES ${PLAT_POSIX_SOURCES} ${PLAT_SDL_SOURCES} ${PLAT_OSX_SOURCES} ${PLAT_COCOA_SOURCES} ) if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) # CMake is not set up to compile and link rc files with GCC. :( @@ -624,15 +587,26 @@ if( WIN32 ) else( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) set( SYSTEM_SOURCES ${SYSTEM_SOURCES} win32/zdoom.rc ) endif( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) +elseif( APPLE ) + if( OSX_COCOA_BACKEND ) + set( SYSTEM_SOURCES_DIR posix posix/cocoa ) + set( SYSTEM_SOURCES ${PLAT_COCOA_SOURCES} ) + set( OTHER_SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} ${PLAT_SDL_SOURCES} ) + else( OSX_COCOA_BACKEND ) + set( SYSTEM_SOURCES_DIR posix posix/sdl ) + set( SYSTEM_SOURCES ${PLAT_SDL_SOURCES} ) + set( PLAT_OSX_SOURCES ${PLAT_OSX_SOURCES} posix/sdl/i_system.mm ) + set( OTHER_SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} ${PLAT_COCOA_SOURCES} ) + endif( OSX_COCOA_BACKEND ) + + set( SYSTEM_SOURCES ${SYSTEM_SOURCES} ${PLAT_POSIX_SOURCES} ${PLAT_OSX_SOURCES} "${FMOD_LIBRARY}" ) + + set_source_files_properties( posix/osx/zdoom.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources ) + set_source_files_properties( "${FMOD_LIBRARY}" PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks ) else( WIN32 ) - set( SYSTEM_SOURCES_DIR sdl ) - set( SYSTEM_SOURCES ${PLAT_SDL_SOURCES} ) - if( APPLE ) - set( SYSTEM_SOURCES ${SYSTEM_SOURCES} ${PLAT_MAC_SOURCES} ) - set( OTHER_SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} ) - else( APPLE ) - set( OTHER_SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} ${PLAT_MAC_SOURCES} ) - endif( APPLE ) + set( SYSTEM_SOURCES_DIR posix posix/sdl ) + set( SYSTEM_SOURCES ${PLAT_POSIX_SOURCES} ${PLAT_SDL_SOURCES} ) + set( OTHER_SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} ${PLAT_OSX_SOURCES} ${PLAT_COCOA_SOURCES} ) endif( WIN32 ) if( NOT ASM_SOURCES ) @@ -696,8 +670,14 @@ endif( DYN_FLUIDSYNTH ) # there's generally a new cpp for every header so this file will get changed if( WIN32 ) set( EXTRA_HEADER_DIRS win32/*.h ) +elseif( APPLE ) + if( OSX_COCOA_BACKEND ) + set( EXTRA_HEADER_DIRS posix/*.h posix/cocoa/*.h ) + else( OSX_COCOA_BACKEND ) + set( EXTRA_HEADER_DIRS posix/*.h posix/sdl/*.h ) + endif( OSX_COCOA_BACKEND ) else( WIN32 ) - set( EXTRA_HEADER_DIRS sdl/*.h ) + set( EXTRA_HEADER_DIRS posix/*.h posix/sdl/*.h ) endif( WIN32 ) file( GLOB HEADER_FILES ${EXTRA_HEADER_DIRS} @@ -712,9 +692,11 @@ file( GLOB HEADER_FILES menu/*.h oplsynth/*.h oplsynth/dosbox/*.h + posix/*.h + posix/cocoa/*.h + posix/sdl/*.h r_data/*.h resourcefiles/*.h - sdl/*.h sfmt/*.h sound/*.h textures/*.h @@ -1226,7 +1208,7 @@ endif( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) if( APPLE ) set_target_properties(zdoom PROPERTIES LINK_FLAGS "-framework Carbon -framework Cocoa -framework IOKit -framework OpenGL" - MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/cocoa/zdoom-info.plist" ) + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/posix/osx/zdoom-info.plist" ) # Fix fmod link so that it can be found in the app bundle. find_program( OTOOL otool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin" ) @@ -1249,7 +1231,6 @@ source_group("Audio Files\\OPL Synth" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURC source_group("Audio Files\\OPL Synth\\DOSBox" FILES oplsynth/dosbox/opl.cpp oplsynth/dosbox/opl.h) source_group("Audio Files\\Timidity\\Headers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/timidity/.+\\.h$") source_group("Audio Files\\Timidity\\Source" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/timidity/.+\\.cpp$") -source_group("Cocoa Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/cocoa/.+") source_group("Decorate++" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/thingdef/.+") source_group("FraggleScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/fragglescript/.+") source_group("Games\\Doom Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_doom/.+") @@ -1266,7 +1247,10 @@ source_group("Render Data\\Resource Sources" REGULAR_EXPRESSION "^${CMAKE_CURREN source_group("Render Data\\Textures" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/textures/.+") source_group("Render Interface" FILES r_defs.h r_renderer.h r_sky.cpp r_sky.h r_state.h r_utility.cpp r_utility.h) source_group("Resource Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/resourcefiles/.+") -source_group("SDL Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sdl/.+") +source_group("POSIX Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/.+") +source_group("Cocoa Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/cocoa/.+") +source_group("OS X Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/osx/.+") +source_group("SDL Files" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/posix/sdl/.+") source_group("SFMT" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/sfmt/.+") source_group("Shared Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_shared/.+") source_group("Versioning" FILES version.h win32/zdoom.rc) diff --git a/src/actor.h b/src/actor.h index 5e8de2ea2..289213450 100644 --- a/src/actor.h +++ b/src/actor.h @@ -752,6 +752,7 @@ public: // These also set CF_INTERPVIEW for players. void SetPitch(int p, bool interpolate); void SetAngle(angle_t ang, bool interpolate); + void SetRoll(angle_t roll, bool interpolate); PClassActor *GetBloodType(int type = 0) const { @@ -955,6 +956,9 @@ public: FNameNoInit DeathType; PClassActor *TeleFogSourceType; PClassActor *TeleFogDestType; + int RipperLevel; + int RipLevelMin; + int RipLevelMax; FState *SpawnState; FState *SeeState; diff --git a/src/b_bot.h b/src/b_bot.h index 69a2f7774..25689a9be 100644 --- a/src/b_bot.h +++ b/src/b_bot.h @@ -130,7 +130,6 @@ private: protected: bool ctf; - int loaded_bots; int t_join; bool observer; //Consoleplayer is observer. }; @@ -188,12 +187,12 @@ public: fixed_t oldy; private: - //(B_think.cpp) + //(b_think.cpp) void Think (); void ThinkForMove (ticcmd_t *cmd); void Set_enemy (); - //(B_func.cpp) + //(b_func.cpp) bool Reachable (AActor *target); void Dofire (ticcmd_t *cmd); AActor *Choose_Mate (); diff --git a/src/b_game.cpp b/src/b_game.cpp index 44aff03fa..e136f3f29 100644 --- a/src/b_game.cpp +++ b/src/b_game.cpp @@ -178,7 +178,10 @@ void FCajunMaster::End () { for (i = 0; i < MAXPLAYERS; i++) { - getspawned.Push(players[i].userinfo.GetName()); + if (players[i].Bot != NULL) + { + getspawned.Push(players[i].userinfo.GetName()); + } } wanted_botnum = botnum; @@ -216,19 +219,16 @@ bool FCajunMaster::SpawnBot (const char *name, int color) "\\color\\cf df 90" //10 = Bleached Bone }; - botinfo_t *thebot; - int botshift; + botinfo_t *thebot = botinfo; + int botshift = 0; if (name) { - thebot = botinfo; - // Check if exist or already in the game. - botshift = 0; while (thebot && stricmp (name, thebot->name)) { - thebot = thebot->next; botshift++; + thebot = thebot->next; } if (thebot == NULL) @@ -246,27 +246,36 @@ bool FCajunMaster::SpawnBot (const char *name, int color) return false; } } - else if (botnum < loaded_bots) - { - bool vacant = false; //Spawn a random bot from bots.cfg if no name given. - while (!vacant) - { - int rnum = (pr_botspawn() % loaded_bots); - thebot = botinfo; - botshift = 0; - while (rnum) - { - --rnum, thebot = thebot->next; - botshift++; - } - if (thebot->inuse == BOTINUSE_No) - vacant = true; - } - } else { - Printf ("Couldn't spawn bot; no bot left in %s\n", BOTFILENAME); - return false; + //Spawn a random bot from bots.cfg if no name given. + TArray BotInfoAvailable; + + while (thebot) + { + if (thebot->inuse == BOTINUSE_No) + BotInfoAvailable.Push (thebot); + + thebot = thebot->next; + } + + if (BotInfoAvailable.Size () == 0) + { + Printf ("Couldn't spawn bot; no bot left in %s\n", BOTFILENAME); + return false; + } + + thebot = BotInfoAvailable[pr_botspawn() % BotInfoAvailable.Size ()]; + + botinfo_t *thebot2 = botinfo; + while (thebot2) + { + if (thebot == thebot2) + break; + + botshift++; + thebot2 = thebot2->next; + } } thebot->inuse = BOTINUSE_Waiting; @@ -478,7 +487,6 @@ void FCajunMaster::ForgetBots () } botinfo = NULL; - loaded_bots = 0; } bool FCajunMaster::LoadBots () @@ -486,6 +494,7 @@ bool FCajunMaster::LoadBots () FScanner sc; FString tmp; bool gotteam = false; + int loaded_bots = 0; bglobal.ForgetBots (); tmp = M_GetCajunPath(BOTFILENAME); @@ -602,9 +611,9 @@ bool FCajunMaster::LoadBots () newinfo->next = bglobal.botinfo; newinfo->lastteam = TEAM_NONE; bglobal.botinfo = newinfo; - bglobal.loaded_bots++; + loaded_bots++; } - Printf ("%d bots read from %s\n", bglobal.loaded_bots, BOTFILENAME); + Printf ("%d bots read from %s\n", loaded_bots, BOTFILENAME); return true; } diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index b323259bc..63950a1f5 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -898,8 +898,8 @@ CCMD(info) linetarget->SpawnHealth()); PrintMiscActorInfo(linetarget); } - else Printf("No target found. Info cannot find actors that have\ - the NOBLOCKMAP flag or have height/radius of 0.\n"); + else Printf("No target found. Info cannot find actors that have " + "the NOBLOCKMAP flag or have height/radius of 0.\n"); } //----------------------------------------------------------------------------- diff --git a/src/c_dispatch.cpp b/src/c_dispatch.cpp index 65e017bdc..7a6748fdc 100644 --- a/src/c_dispatch.cpp +++ b/src/c_dispatch.cpp @@ -185,6 +185,9 @@ static const char *KeyConfCommands[] = "clearplayerclasses" }; +static TArray StoredStartupSets; +static bool RunningStoredStartups; + // CODE -------------------------------------------------------------------- IMPLEMENT_CLASS (DWaitingCommand) @@ -537,6 +540,18 @@ void ResetButtonStates () } } +void C_ExecStoredSets() +{ + assert(!RunningStoredStartups); + RunningStoredStartups = true; + for (unsigned i = 0; i < StoredStartupSets.Size(); ++i) + { + C_DoCommand(StoredStartupSets[i]); + } + StoredStartupSets.Clear(); + RunningStoredStartups = false; +} + void C_DoCommand (const char *cmd, int keynum) { FConsoleCommand *com; @@ -612,7 +627,22 @@ void C_DoCommand (const char *cmd, int keynum) if ( (com = FindNameInHashTable (Commands, beg, len)) ) { - if (gamestate != GS_STARTUP || ParsingKeyConf || + if (gamestate == GS_STARTUP && !RunningStoredStartups && + len == 3 && strnicmp(beg, "set", 3) == 0) + { + // Save setting of unknown cvars for later, in case a loaded wad has a + // CVARINFO that defines it. + FCommandLine args(beg); + if (args.argc() > 1 && FindCVar(args[1], NULL) == NULL) + { + StoredStartupSets.Push(beg); + } + else + { + com->Run(args, players[consoleplayer].mo, keynum); + } + } + else if (gamestate != GS_STARTUP || ParsingKeyConf || (len == 3 && strnicmp (beg, "set", 3) == 0) || (len == 7 && strnicmp (beg, "logfile", 7) == 0) || (len == 9 && strnicmp (beg, "unbindall", 9) == 0) || @@ -657,12 +687,15 @@ void C_DoCommand (const char *cmd, int keynum) } else { // We don't know how to handle this command - char cmdname[64]; - size_t minlen = MIN (len, 63); - - memcpy (cmdname, beg, minlen); - cmdname[len] = 0; - Printf ("Unknown command \"%s\"\n", cmdname); + if (gamestate == GS_STARTUP && !RunningStoredStartups) + { + // Save it for later, in case a CVARINFO defines it. + StoredStartupSets.Push(beg); + } + else + { + Printf ("Unknown command \"%.*s\"\n", len, beg); + } } } } diff --git a/src/c_dispatch.h b/src/c_dispatch.h index f4518608d..b494005c7 100644 --- a/src/c_dispatch.h +++ b/src/c_dispatch.h @@ -42,6 +42,7 @@ class APlayerPawn; extern bool CheckCheatmode (bool printmsg = true); void C_ExecCmdLineParams (); +void C_ExecStoredSets(); // Add commands to the console as if they were typed in. Can handle wait // and semicolon-separated commands. This function may modify the source diff --git a/src/cocoa/HID_Config_Utilities.c b/src/cocoa/HID_Config_Utilities.c deleted file mode 100644 index 18d4672d3..000000000 --- a/src/cocoa/HID_Config_Utilities.c +++ /dev/null @@ -1,926 +0,0 @@ -// File: HID_Config_Utilities.c -// Abstract: Implementation of the HID configuration utilities -// Version: 2.0 -// -// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple -// Inc. ("Apple") in consideration of your agreement to the following -// terms, and your use, installation, modification or redistribution of -// this Apple software constitutes acceptance of these terms. If you do -// not agree with these terms, please do not use, install, modify or -// redistribute this Apple software. -// -// In consideration of your agreement to abide by the following terms, and -// subject to these terms, Apple grants you a personal, non-exclusive -// license, under Apple's copyrights in this original Apple software (the -// "Apple Software"), to use, reproduce, modify and redistribute the Apple -// Software, with or without modifications, in source and/or binary forms; -// provided that if you redistribute the Apple Software in its entirety and -// without modifications, you must retain this notice and the following -// text and disclaimers in all such redistributions of the Apple Software. -// Neither the name, trademarks, service marks or logos of Apple Inc. may -// be used to endorse or promote products derived from the Apple Software -// without specific prior written permission from Apple. Except as -// expressly stated in this notice, no other rights or licenses, express or -// implied, are granted by Apple herein, including but not limited to any -// patent rights that may be infringed by your derivative works or by other -// works in which the Apple Software may be incorporated. -// -// The Apple Software is provided by Apple on an "AS IS" basis. APPLE -// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION -// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS -// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND -// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. -// -// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL -// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, -// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED -// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), -// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Copyright (C) 2009 Apple Inc. All Rights Reserved. -// -//***************************************************** - -#include - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 - -#define LOG_SCORING 0 - -#include // malloc -#include // clock - -#include - -#include "HID_Utilities_External.h" - -// --------------------------------- - -// polls single device's elements for a change greater than kPercentMove. Times out after given time -// returns 1 and pointer to element if found -// returns 0 and NULL for both parameters if not found - -unsigned char HIDConfigureSingleDeviceAction(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef *outIOHIDElementRef, float timeout) { - if ( !inIOHIDDeviceRef ) { - return (0); - } - if ( 0 == HIDHaveDeviceList() ) { // if we do not have a device list - return (0); // return 0 - } - - Boolean found = FALSE; - - // build list of device and elements to save current values - int maxElements = HIDCountDeviceElements(inIOHIDDeviceRef, kHIDElementTypeInput); - int *saveValueArray = (int *) calloc( maxElements, sizeof(int) ); // 2D array to save values - - // store initial values on first pass / compare to initial value on subsequent passes - Boolean first = TRUE; - - // get all the elements from this device - CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements(inIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone); - // if that worked... - if ( elementCFArrayRef ) { - clock_t start = clock(), end; - - // poll all devices and elements - while ( !found ) { - int currElementIndex = 0; - CFIndex idx, cnt = CFArrayGetCount(elementCFArrayRef); - for ( idx = 0; idx < cnt; idx++ ) { - *outIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef, idx); - if ( !*outIOHIDElementRef ) { - continue; - } - - // is this an input element? - IOHIDElementType type = IOHIDElementGetType(*outIOHIDElementRef); - - switch ( type ) { - // these types are inputs - case kIOHIDElementTypeInput_Misc: - case kIOHIDElementTypeInput_Button: - case kIOHIDElementTypeInput_Axis: - case kIOHIDElementTypeInput_ScanCodes: - default: - { - break; - } - case kIOHIDElementTypeOutput: - case kIOHIDElementTypeFeature: - case kIOHIDElementTypeCollection: - { - *outIOHIDElementRef = NULL; // these types are not ( Skip them ) - break; - } - } /* switch */ - if ( !*outIOHIDElementRef ) { - continue; // skip this element - } - - // get this elements current value - int value = 0; // default value is zero - IOHIDValueRef tIOHIDValueRef; - IOReturn ioReturn = IOHIDDeviceGetValue(inIOHIDDeviceRef, *outIOHIDElementRef, &tIOHIDValueRef); - if ( kIOReturnSuccess == ioReturn ) { - value = IOHIDValueGetScaledValue(tIOHIDValueRef, kIOHIDValueScaleTypePhysical); - } - if ( first ) { - saveValueArray[currElementIndex] = value; - } else { - CFIndex min = IOHIDElementGetLogicalMin(*outIOHIDElementRef); - CFIndex max = IOHIDElementGetLogicalMax(*outIOHIDElementRef); - - int initialValue = saveValueArray[currElementIndex]; - int delta = (float)(max - min) * kPercentMove * 0.01; - // is the new value within +/- delta of the initial value? - if ( ( (initialValue + delta) < value ) || ( (initialValue - delta) > value ) ) { - found = 1; // ( yes! ) mark as found - break; - } - } // if ( first ) - - currElementIndex++; // bump element index - } // next idx - - first = FALSE; // no longer the first pass - - // are we done? - end = clock(); - double secs = (double)(end - start) / CLOCKS_PER_SEC; - if ( secs > timeout ) { - break; // ( yes ) timeout - } - } // while ( !found ) - - CFRelease(elementCFArrayRef); - } // if ( elementCFArrayRef ) - // return device and element moved - if ( found ) { - return (1); - } else { - *outIOHIDElementRef = NULL; - return (0); - } -} // HIDConfigureSingleDeviceAction - -//************************************************************************* -// -// HIDConfigureAction( outIOHIDDeviceRef, outIOHIDElementRef, inTimeout ) -// -// Purpose: polls all devices and elements for a change greater than kPercentMove. -// Times out after given time returns 1 and pointer to device and element -// if found; returns 0 and NULL for both parameters if not found -// -// Inputs: outIOHIDDeviceRef - address where to store the device -// outIOHIDElementRef - address where to store the element -// inTimeout - the timeout -// Returns: Boolean - if successful -// outIOHIDDeviceRef - the device -// outIOHIDElementRef - the element -// - -Boolean HIDConfigureAction(IOHIDDeviceRef *outIOHIDDeviceRef, IOHIDElementRef *outIOHIDElementRef, float inTimeout) { - // param error? - if ( !outIOHIDDeviceRef || !outIOHIDElementRef ) { - return (0); - } - if ( !gDeviceCFArrayRef ) { // if we do not have a device list - // and we can't build another list - if ( !HIDBuildDeviceList(0, 0) || !gDeviceCFArrayRef ) { - return (FALSE); // bail - } - } - - IOHIDDeviceRef tIOHIDDeviceRef; - IOHIDElementRef tIOHIDElementRef; - - // remember when we start; used to calculate timeout - clock_t start = clock(), end; - - // determine the maximum number of elements - CFIndex maxElements = 0; - CFIndex devIndex, devCount = CFArrayGetCount(gDeviceCFArrayRef); - for ( devIndex = 0; devIndex < devCount; devIndex++ ) { - tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, devIndex); - if ( !tIOHIDDeviceRef ) { - continue; // skip this one - } - - CFIndex count = HIDCountDeviceElements(tIOHIDDeviceRef, kHIDElementTypeInput); - if ( count > maxElements ) { - maxElements = count; - } - } - - // allocate an array of int's in which to store devCount * maxElements values - double *saveValueArray = (double *) calloc( devCount * maxElements, sizeof(double) ); // clear 2D array to save values - - // on first pass store initial values / compare current values to initial values on subsequent passes - Boolean found = FALSE, first = TRUE; - - while ( !found ) { - double maxDeltaPercent = 0; // we want to find the one that moves the most ( percentage wise ) - for ( devIndex = 0; devIndex < devCount; devIndex++ ) { - tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, devIndex); - if ( !tIOHIDDeviceRef ) { - continue; // skip this one - } - -#ifdef DEBUG - long vendorID = IOHIDDevice_GetVendorID(tIOHIDDeviceRef); - long productID = IOHIDDevice_GetProductID(tIOHIDDeviceRef); -#endif - gElementCFArrayRef = IOHIDDeviceCopyMatchingElements(tIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone); - if ( gElementCFArrayRef ) { - CFIndex eleIndex, eleCount = CFArrayGetCount(gElementCFArrayRef); - for ( eleIndex = 0; eleIndex < eleCount; eleIndex++ ) { - tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(gElementCFArrayRef, eleIndex); - if ( !tIOHIDElementRef ) { - continue; - } - - IOHIDElementType tIOHIDElementType = IOHIDElementGetType(tIOHIDElementRef); - // only care about inputs (no outputs or features) - if ( tIOHIDElementType <= kIOHIDElementTypeInput_ScanCodes ) { - if ( IOHIDElementIsArray(tIOHIDElementRef) ) { - //printf( "ARRAY!\n" ); - continue; // skip array elements - } - - uint32_t usagePage = IOHIDElementGetUsagePage(tIOHIDElementRef); - uint32_t usage = IOHIDElementGetUsage(tIOHIDElementRef); - uint32_t reportCount = IOHIDElementGetReportCount(tIOHIDElementRef); -#ifdef DEBUG - if ( first ) { - IOHIDElementCookie cookie = IOHIDElementGetCookie(tIOHIDElementRef); - printf("%s, dev: {ref:%p, ven: 0x%08lX, pro: 0x%08lX}, ele: {ref:%p, cookie: %p, usage:%04lX:%08lX}\n", - __PRETTY_FUNCTION__, - tIOHIDDeviceRef, - vendorID, - productID, - tIOHIDElementRef, - cookie, - (long unsigned int) usagePage, - (long unsigned int) usage); - fflush(stdout); - if ( (0x054C == vendorID) && (0x0268 == productID) && (0x001E == (UInt32) cookie) ) { - //printf( "DING!\n" ); - } - } - -#endif -#if 1 // work-around for IOHIDValueGetScaledValue crash (when element report count > 1) - if ( reportCount > 1 ) { - //printf( "REPORT!\n" ); - continue; // skip reports - } - -#endif - // ignore PID elements and arrays - if ( (kHIDPage_PID != usagePage) && (((uint32_t)-1) != usage) ) { - // get this elements current value - double value = 0.0; // default value is zero - IOHIDValueRef tIOHIDValueRef; - IOReturn ioReturn = IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &tIOHIDValueRef); - if ( kIOReturnSuccess == ioReturn ) { - value = IOHIDValueGetScaledValue(tIOHIDValueRef, kIOHIDValueScaleTypePhysical); - } - if ( first ) { - saveValueArray[(devIndex * maxElements) + eleIndex] = value; - } else { - double initialValue = saveValueArray[(devIndex * maxElements) + eleIndex]; - - CFIndex valueMin = IOHIDElementGetPhysicalMin(tIOHIDElementRef); - CFIndex valueMax = IOHIDElementGetPhysicalMax(tIOHIDElementRef); - - double deltaPercent = fabs( (initialValue - value) * 100.0 / (valueMax - valueMin) ); -#if 0 // debug code useful to dump out value info for specific (vendorID, productID, usagePage and usage) device - if ( !first ) { - // Device: 0x13b6a0 = { Logitech Inc. - WingMan Force 3D, vendorID: 0x046D, productID: 0xC283, - // usage: 0x0001:0x0004, "Generic Desktop Joystick" - if ( (vendorID == 0x046D) && (productID == 0xC283) ) { - if ( (kHIDPage_GenericDesktop == usagePage) && (kHIDUsage_GD_Rz == usage) ) { - printf("initial: %6.2f, value: %6.2f, diff: %6.2f, delta percent: %6.2f!\n", - initialValue, - value, - fabs(initialValue - value), - deltaPercent); - } - } - } - - deltaPercent = 0.0; -#endif - if ( deltaPercent >= kPercentMove ) { - found = TRUE; - if ( deltaPercent > maxDeltaPercent ) { - maxDeltaPercent = deltaPercent; - - *outIOHIDDeviceRef = tIOHIDDeviceRef; - *outIOHIDElementRef = tIOHIDElementRef; - } - - break; - } - } // if first - - } // if usage - - } // if type - - } // for elements... - - CFRelease(gElementCFArrayRef); - gElementCFArrayRef = NULL; - } // if ( gElementCFArrayRef ) - if ( found ) { - // HIDDumpElementInfo( tIOHIDElementRef ); - break; // DONE! - } - } // for devices - - first = FALSE; // no longer the first pass - - // are we done? - end = clock(); - double secs = (double)(end - start) / CLOCKS_PER_SEC; - if ( secs > inTimeout ) { - break; // ( yes ) timeout - } - } // while ( !found ) - // return device and element moved - if ( !found ) { - *outIOHIDDeviceRef = NULL; - *outIOHIDElementRef = NULL; - } - - return (found); -} // HIDConfigureAction - -//************************************************************************* -// -// HIDSaveElementPref( inKeyCFStringRef, inAppCFStringRef, inIOHIDDeviceRef, inIOHIDElementRef ) -// -// Purpose: Save the device & element values into the specified key in the specified applications preferences -// -// Inputs: inKeyCFStringRef - the preference key -// inAppCFStringRef - the application identifier -// inIOHIDDeviceRef - the device -// inIOHIDElementRef - the element -// Returns: Boolean - if successful -// - -Boolean HIDSaveElementPref(const CFStringRef inKeyCFStringRef, - CFStringRef inAppCFStringRef, - IOHIDDeviceRef inIOHIDDeviceRef, - IOHIDElementRef inIOHIDElementRef) { - Boolean success = FALSE; - if ( inKeyCFStringRef && inAppCFStringRef && inIOHIDDeviceRef && inIOHIDElementRef ) { - long vendorID = IOHIDDevice_GetVendorID(inIOHIDDeviceRef); - require(vendorID, Oops); - - long productID = IOHIDDevice_GetProductID(inIOHIDDeviceRef); - require(productID, Oops); - - long locID = IOHIDDevice_GetLocationID(inIOHIDDeviceRef); - require(locID, Oops); - - uint32_t usagePage = IOHIDDevice_GetUsagePage(inIOHIDDeviceRef); - uint32_t usage = IOHIDDevice_GetUsage(inIOHIDDeviceRef); - if ( !usagePage || !usage ) { - usagePage = IOHIDDevice_GetPrimaryUsagePage(inIOHIDDeviceRef); - usage = IOHIDDevice_GetPrimaryUsage(inIOHIDDeviceRef); - } - - require(usagePage && usage, Oops); - - uint32_t usagePageE = IOHIDElementGetUsagePage(inIOHIDElementRef); - uint32_t usageE = IOHIDElementGetUsage(inIOHIDElementRef); - IOHIDElementCookie eleCookie = IOHIDElementGetCookie(inIOHIDElementRef); - - CFStringRef prefCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, - CFSTR("d:{v:%ld, p:%ld, l:%ld, p:%ld, u:%ld}, e:{p:%ld, u:%ld, c:%ld}"), - vendorID, productID, locID, usagePage, usage, - usagePageE, usageE, eleCookie); - if ( prefCFStringRef ) { - CFPreferencesSetAppValue(inKeyCFStringRef, prefCFStringRef, inAppCFStringRef); - CFRelease(prefCFStringRef); - success = TRUE; - } - } - -Oops: ; - return (success); -} // HIDSaveElementPref - -//************************************************************************* -// -// HIDRestoreElementPref( inKeyCFStringRef, inAppCFStringRef, outIOHIDDeviceRef, outIOHIDElementRef ) -// -// Purpose: Find the specified preference in the specified application -// -// Inputs: inKeyCFStringRef - the preference key -// inAppCFStringRef - the application identifier -// outIOHIDDeviceRef - address where to restore the device -// outIOHIDElementRef - address where to restore the element -// Returns: Boolean - if successful -// outIOHIDDeviceRef - the device -// outIOHIDElementRef - the element -// - -Boolean HIDRestoreElementPref(CFStringRef inKeyCFStringRef, - CFStringRef inAppCFStringRef, - IOHIDDeviceRef * outIOHIDDeviceRef, - IOHIDElementRef *outIOHIDElementRef) { - Boolean found = FALSE; - if ( inKeyCFStringRef && inAppCFStringRef && outIOHIDDeviceRef && outIOHIDElementRef ) { - CFPropertyListRef prefCFPropertyListRef = CFPreferencesCopyAppValue(inKeyCFStringRef, inAppCFStringRef); - if ( prefCFPropertyListRef ) { - if ( CFStringGetTypeID() == CFGetTypeID(prefCFPropertyListRef) ) { - char buffer[256]; - if ( CFStringGetCString( (CFStringRef) prefCFPropertyListRef, buffer, sizeof(buffer), - kCFStringEncodingUTF8 ) ) - { - HID_info_rec searchHIDInfo; - - int count = sscanf(buffer, - "d:{v:%d, p:%d, l:%d, p:%d, u:%d}, e:{p:%d, u:%d, c:%ld}", - &searchHIDInfo.device.vendorID, - &searchHIDInfo.device.productID, - &searchHIDInfo.device.locID, - &searchHIDInfo.device.usagePage, - &searchHIDInfo.device.usage, - &searchHIDInfo.element.usagePage, - &searchHIDInfo.element.usage, - (long *) &searchHIDInfo.element.cookie); - if ( 8 == count ) { // if we found all eight parametersā€¦ - // and can find a device & element that matches theseā€¦ - if ( HIDFindDeviceAndElement(&searchHIDInfo, outIOHIDDeviceRef, outIOHIDElementRef) ) { - found = TRUE; - } - } - } - } else { - // We found the entry with this key but it's the wrong type; delete it. - CFPreferencesSetAppValue(inKeyCFStringRef, NULL, inAppCFStringRef); - (void) CFPreferencesAppSynchronize(inAppCFStringRef); - } - - CFRelease(prefCFPropertyListRef); - } - } - - return (found); -} // HIDRestoreElementPref - -//************************************************************************* -// -// HIDFindDeviceAndElement( inSearchInfo, outFoundDevice, outFoundElement ) -// -// Purpose: find the closest matching device and element for this action -// -// Notes: matches device: serial, vendorID, productID, location, inUsagePage, usage -// matches element: cookie, inUsagePage, usage, -// -// Inputs: inSearchInfo - the device & element info we searching for -// outFoundDevice - the address of the best matching device -// outFoundElement - the address of the best matching element -// -// Returns: Boolean - TRUE if we find a match -// outFoundDevice - the best matching device -// outFoundElement - the best matching element -// - -Boolean HIDFindDeviceAndElement(const HID_info_rec *inSearchInfo, IOHIDDeviceRef *outFoundDevice, IOHIDElementRef *outFoundElement) { - Boolean result = FALSE; - - IOHIDDeviceRef bestIOHIDDeviceRef = NULL; - IOHIDElementRef bestIOHIDElementRef = NULL; - long bestScore = 0; - - CFIndex devIndex, devCount = CFArrayGetCount(gDeviceCFArrayRef); - for ( devIndex = 0; devIndex < devCount; devIndex++ ) { - long deviceScore = 1; - - IOHIDDeviceRef tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, devIndex); - if ( !tIOHIDDeviceRef ) { - continue; - } - // match vendorID, productID (+10, +8) - if ( inSearchInfo->device.vendorID ) { - long vendorID = IOHIDDevice_GetVendorID(tIOHIDDeviceRef); - if ( vendorID ) { - if ( inSearchInfo->device.vendorID == vendorID ) { - deviceScore += 10; - if ( inSearchInfo->device.productID ) { - long productID = IOHIDDevice_GetProductID(tIOHIDDeviceRef); - if ( productID ) { - if ( inSearchInfo->device.productID == productID ) { - deviceScore += 8; - } // if ( inSearchInfo->device.productID == productID ) - - } // if ( productID ) - - } // if ( inSearchInfo->device.productID ) - - } // if (inSearchInfo->device.vendorID == vendorID) - - } // if vendorID - - } // if search->device.vendorID - // match usagePage & usage (+9) - if ( inSearchInfo->device.usagePage && inSearchInfo->device.usage ) { - uint32_t usagePage = IOHIDDevice_GetUsagePage(tIOHIDDeviceRef) ; - uint32_t usage = IOHIDDevice_GetUsage(tIOHIDDeviceRef); - if ( !usagePage || !usage ) { - usagePage = IOHIDDevice_GetPrimaryUsagePage(tIOHIDDeviceRef); - usage = IOHIDDevice_GetPrimaryUsage(tIOHIDDeviceRef); - } - if ( usagePage ) { - if ( inSearchInfo->device.usagePage == usagePage ) { - if ( usage ) { - if ( inSearchInfo->device.usage == usage ) { - deviceScore += 9; - } // if ( inSearchInfo->usage == usage ) - - } // if ( usage ) - - } // if ( inSearchInfo->usagePage == usagePage ) - - } // if ( usagePage ) - - } // if ( inSearchInfo->usagePage && inSearchInfo->usage ) - // match location ID (+5) - if ( inSearchInfo->device.locID ) { - long locID = IOHIDDevice_GetLocationID(tIOHIDDeviceRef); - if ( locID ) { - if ( inSearchInfo->device.locID == locID ) { - deviceScore += 5; - } - } - } - - // iterate over all elements of this device - gElementCFArrayRef = IOHIDDeviceCopyMatchingElements(tIOHIDDeviceRef, NULL, 0); - if ( gElementCFArrayRef ) { - CFIndex eleIndex, eleCount = CFArrayGetCount(gElementCFArrayRef); - for ( eleIndex = 0; eleIndex < eleCount; eleIndex++ ) { - IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(gElementCFArrayRef, eleIndex); - if ( !tIOHIDElementRef ) { - continue; - } - - long score = deviceScore; - // match usage page, usage & cookie - if ( inSearchInfo->element.usagePage && inSearchInfo->element.usage ) { - uint32_t usagePage = IOHIDElementGetUsagePage(tIOHIDElementRef); - if ( inSearchInfo->element.usagePage == usagePage ) { - uint32_t usage = IOHIDElementGetUsage(tIOHIDElementRef); - if ( inSearchInfo->element.usage == usage ) { - score += 5; - IOHIDElementCookie cookie = IOHIDElementGetCookie(tIOHIDElementRef); - if ( inSearchInfo->element.cookie == cookie ) { - score += 4; - } // cookies match - - } else { - score = 0; - } // usages match - - } else { - score = 0; - } // usage pages match - - } // if ( search usage page & usage ) - -#if LOG_SCORING - if ( kHIDPage_KeyboardOrKeypad != tElementRef->usagePage ) { // skip keyboards here - printf("%s: ( %ld:%ld )-I-Debug, score: %ld\t", - __PRETTY_FUNCTION__, - inSearchInfo->element.usagePage, - inSearchInfo->element.usage, - score); - HIDPrintElement(tIOHIDElementRef); - } - -#endif // LOG_SCORING - if ( score > bestScore ) { - bestIOHIDDeviceRef = tIOHIDDeviceRef; - bestIOHIDElementRef = tIOHIDElementRef; - bestScore = score; -#if LOG_SCORING - printf("%s: ( %ld:%ld )-I-Debug, better score: %ld\t", - __PRETTY_FUNCTION__, - inSearchInfo->element.usagePage, - inSearchInfo->element.usage, - score); - HIDPrintElement(bestIOHIDElementRef); -#endif // LOG_SCORING - } - } // for elements... - - CFRelease(gElementCFArrayRef); - gElementCFArrayRef = NULL; - } // if ( gElementCFArrayRef ) - - } // for ( devIndex = 0; devIndex < devCount; devIndex++ ) - if ( bestIOHIDDeviceRef || bestIOHIDElementRef ) { - *outFoundDevice = bestIOHIDDeviceRef; - *outFoundElement = bestIOHIDElementRef; -#if LOG_SCORING - printf("%s: ( %ld:%ld )-I-Debug, best score: %ld\t", - __PRETTY_FUNCTION__, - inSearchInfo->element.usagePage, - inSearchInfo->element.usage, - bestScore); - HIDPrintElement(bestIOHIDElementRef); -#endif // LOG_SCORING - result = TRUE; - } - - return (result); -} // HIDFindDeviceAndElement - -// --------------------------------- - -// takes input records, save required info -// assume file is open and at correct position. -// will always write to file (if file exists) size of HID_info_rec, even if device and or element is bad - -void HIDSaveElementConfig(FILE *fileRef, IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef, int actionCookie) { - // must save: - // actionCookie - // Device: serial,vendorID, productID, location, usagePage, usage - // Element: cookie, usagePage, usage, - HID_info_rec hidInfoRec; - HIDSetElementConfig(&hidInfoRec, inIOHIDDeviceRef, inIOHIDElementRef, actionCookie); - // write to file - if ( fileRef ) { - fwrite( (void *)&hidInfoRec, sizeof(HID_info_rec), 1, fileRef ); - } -} // HIDSaveElementConfig - -// --------------------------------- - -// take file, read one record (assume file position is correct and file is open) -// search for matching device -// return pDevice, pElement and cookie for action - -int HIDRestoreElementConfig(FILE *fileRef, IOHIDDeviceRef *outIOHIDDeviceRef, IOHIDElementRef *outIOHIDElementRef) { - // Device: serial,vendorID, productID, location, usagePage, usage - // Element: cookie, usagePage, usage, - - HID_info_rec hidInfoRec; - fread( (void *) &hidInfoRec, 1, sizeof(HID_info_rec), fileRef ); - return ( HIDGetElementConfig(&hidInfoRec, outIOHIDDeviceRef, outIOHIDElementRef) ); -} // HIDRestoreElementConfig - -// --------------------------------- - -// Set up a config record for saving -// takes an input records, returns record user can save as they want -// Note: the save rec must be pre-allocated by the calling app and will be filled out -void HIDSetElementConfig(HID_info_ptr inHIDInfoPtr, - IOHIDDeviceRef inIOHIDDeviceRef, - IOHIDElementRef inIOHIDElementRef, - int actionCookie) { - // must save: - // actionCookie - // Device: serial,vendorID, productID, location, usagePage, usage - // Element: cookie, usagePage, usage, - inHIDInfoPtr->actionCookie = actionCookie; - // device - // need to add serial number when I have a test case - if ( inIOHIDDeviceRef && inIOHIDElementRef ) { - inHIDInfoPtr->device.vendorID = IOHIDDevice_GetVendorID(inIOHIDDeviceRef); - inHIDInfoPtr->device.productID = IOHIDDevice_GetProductID(inIOHIDDeviceRef); - inHIDInfoPtr->device.locID = IOHIDDevice_GetLocationID(inIOHIDDeviceRef); - inHIDInfoPtr->device.usage = IOHIDDevice_GetUsage(inIOHIDDeviceRef); - inHIDInfoPtr->device.usagePage = IOHIDDevice_GetUsagePage(inIOHIDDeviceRef); - - inHIDInfoPtr->element.usagePage = IOHIDElementGetUsagePage(inIOHIDElementRef); - inHIDInfoPtr->element.usage = IOHIDElementGetUsage(inIOHIDElementRef); - inHIDInfoPtr->element.minReport = IOHIDElement_GetCalibrationSaturationMin(inIOHIDElementRef); - inHIDInfoPtr->element.maxReport = IOHIDElement_GetCalibrationSaturationMax(inIOHIDElementRef); - inHIDInfoPtr->element.cookie = IOHIDElementGetCookie(inIOHIDElementRef); - } else { - inHIDInfoPtr->device.vendorID = 0; - inHIDInfoPtr->device.productID = 0; - inHIDInfoPtr->device.locID = 0; - inHIDInfoPtr->device.usage = 0; - inHIDInfoPtr->device.usagePage = 0; - - inHIDInfoPtr->element.usagePage = 0; - inHIDInfoPtr->element.usage = 0; - inHIDInfoPtr->element.minReport = 0; - inHIDInfoPtr->element.maxReport = 0; - inHIDInfoPtr->element.cookie = 0; - } -} // HIDSetElementConfig - -// --------------------------------- -#if 0 // debug utility function to dump config record -void HIDDumpConfig(HID_info_ptr inHIDInfoPtr) { - printf( - "Config Record for action: %d\n\t vendor: %d product: %d location: %d\n\t usage: %d usagePage: %d\n\t element.usagePage: %d element.usage: %d\n\t minReport: %d maxReport: %d\n\t cookie: %d\n", - inHIDInfoPtr->actionCookie, - inHIDInfoPtr->device.vendorID, - inHIDInfoPtr->device.productID, - inHIDInfoPtr->locID, - inHIDInfoPtr->usage, - inHIDInfoPtr->usagePage, - inHIDInfoPtr->element.usagePage, - inHIDInfoPtr->element.usage, - inHIDInfoPtr->minReport, - inHIDInfoPtr->maxReport, - inHIDInfoPtr->cookie); -} // HIDDumpConfig -#endif // 0 -// --------------------------------- - -// Get matching element from config record -// takes a pre-allocated and filled out config record -// search for matching device -// return pDevice, pElement and cookie for action -int HIDGetElementConfig(HID_info_ptr inHIDInfoPtr, IOHIDDeviceRef *outIOHIDDeviceRef, IOHIDElementRef *outIOHIDElementRef) { - if ( !inHIDInfoPtr->device.locID && !inHIDInfoPtr->device.vendorID && !inHIDInfoPtr->device.productID && !inHIDInfoPtr->device.usage - && !inHIDInfoPtr->device.usagePage ) // - { // - // early out - *outIOHIDDeviceRef = NULL; - *outIOHIDElementRef = NULL; - return (inHIDInfoPtr->actionCookie); - } - - IOHIDDeviceRef tIOHIDDeviceRef, foundIOHIDDeviceRef = NULL; - IOHIDElementRef tIOHIDElementRef, foundIOHIDElementRef = NULL; - - CFIndex devIdx, devCnt, idx, cnt; - // compare to current device list for matches - // look for device - if ( inHIDInfoPtr->device.locID && inHIDInfoPtr->device.vendorID && inHIDInfoPtr->device.productID ) { // look for specific device - // type plug in to same port - devCnt = CFArrayGetCount(gDeviceCFArrayRef); - for ( devIdx = 0; devIdx < devCnt; devIdx++ ) { - tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, devIdx); - if ( !tIOHIDDeviceRef ) { - continue; // skip this device - } - - long locID = IOHIDDevice_GetLocationID(tIOHIDDeviceRef); - long vendorID = IOHIDDevice_GetVendorID(tIOHIDDeviceRef); - long productID = IOHIDDevice_GetProductID(tIOHIDDeviceRef); - if ( (inHIDInfoPtr->device.locID == locID) - && (inHIDInfoPtr->device.vendorID == vendorID) - && (inHIDInfoPtr->device.productID == productID) ) - { - foundIOHIDDeviceRef = tIOHIDDeviceRef; - } - if ( foundIOHIDDeviceRef ) { - break; - } - } // next devIdx - if ( foundIOHIDDeviceRef ) { - CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements(foundIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone); - if ( elementCFArrayRef ) { - cnt = CFArrayGetCount(elementCFArrayRef); - for ( idx = 0; idx < cnt; idx++ ) { - tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef, idx); - if ( !tIOHIDElementRef ) { - continue; // skip this element - } - - IOHIDElementCookie cookie = IOHIDElementGetCookie(tIOHIDElementRef); - if ( inHIDInfoPtr->element.cookie == cookie ) { - foundIOHIDElementRef = tIOHIDElementRef; - } - if ( foundIOHIDElementRef ) { - break; - } - } - if ( !foundIOHIDElementRef ) { - cnt = CFArrayGetCount(elementCFArrayRef); - for ( idx = 0; idx < cnt; idx++ ) { - tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef, idx); - if ( !tIOHIDElementRef ) { - continue; // skip this element - } - - uint32_t usagePage = IOHIDElementGetUsagePage(tIOHIDElementRef); - uint32_t usage = IOHIDElementGetUsage(tIOHIDElementRef); - if ( (inHIDInfoPtr->element.usage == usage) && (inHIDInfoPtr->element.usagePage == usagePage) ) { - foundIOHIDElementRef = tIOHIDElementRef; - } - if ( foundIOHIDElementRef ) { - break; - } - } // next idx - - } // if ( !foundIOHIDElementRef ) - if ( foundIOHIDElementRef ) { // if same device - // setup the calibration - IOHIDElement_SetupCalibration(tIOHIDElementRef); - - IOHIDElement_SetCalibrationSaturationMin(tIOHIDElementRef, inHIDInfoPtr->element.minReport); - IOHIDElement_SetCalibrationSaturationMax(tIOHIDElementRef, inHIDInfoPtr->element.maxReport); - } - - CFRelease(elementCFArrayRef); - } // if ( elementCFArrayRef ) - - } // if ( foundIOHIDDeviceRef ) - // if we have not found a match, look at just vendor and product - if ( (!foundIOHIDDeviceRef) && (inHIDInfoPtr->device.vendorID && inHIDInfoPtr->device.productID) ) { - devCnt = CFArrayGetCount(gDeviceCFArrayRef); - for ( devIdx = 0; devIdx < devCnt; devIdx++ ) { - tIOHIDDeviceRef = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, devIdx); - if ( !tIOHIDDeviceRef ) { - continue; // skip this device - } - - long vendorID = IOHIDDevice_GetVendorID(tIOHIDDeviceRef); - long productID = IOHIDDevice_GetProductID(tIOHIDDeviceRef); - if ( (inHIDInfoPtr->device.vendorID == vendorID) - && (inHIDInfoPtr->device.productID == productID) ) - { - foundIOHIDDeviceRef = tIOHIDDeviceRef; - } - if ( foundIOHIDDeviceRef ) { - break; - } - } - // match elements by cookie since same device type - if ( foundIOHIDDeviceRef ) { - CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements(foundIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone); - if ( elementCFArrayRef ) { - cnt = CFArrayGetCount(elementCFArrayRef); - for ( idx = 0; idx < cnt; idx++ ) { - tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef, idx); - if ( !tIOHIDElementRef ) { - continue; // skip this element - } - - IOHIDElementCookie cookie = IOHIDElementGetCookie(tIOHIDElementRef); - if ( inHIDInfoPtr->element.cookie == cookie ) { - foundIOHIDElementRef = tIOHIDElementRef; - } - if ( foundIOHIDElementRef ) { - break; - } - } - // if no cookie match (should NOT occur) match on usage - if ( !foundIOHIDElementRef ) { - cnt = CFArrayGetCount(elementCFArrayRef); - for ( idx = 0; idx < cnt; idx++ ) { - tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(elementCFArrayRef, idx); - if ( !tIOHIDElementRef ) { - continue; // skip this element - } - - uint32_t usagePage = IOHIDElementGetUsagePage(tIOHIDElementRef); - uint32_t usage = IOHIDElementGetUsage(tIOHIDElementRef); - if ( (inHIDInfoPtr->element.usage == usage) - && (inHIDInfoPtr->element.usagePage == usagePage) ) - { - foundIOHIDElementRef = tIOHIDElementRef; - } - if ( foundIOHIDElementRef ) { - break; - } - } // next idx - - } // if ( !foundIOHIDElementRef ) - if ( foundIOHIDElementRef ) { // if same device - // setup the calibration - IOHIDElement_SetupCalibration(tIOHIDElementRef); - IOHIDElement_SetCalibrationSaturationMin(tIOHIDElementRef, inHIDInfoPtr->element.minReport); - IOHIDElement_SetCalibrationSaturationMax(tIOHIDElementRef, inHIDInfoPtr->element.maxReport); - } - - CFRelease(elementCFArrayRef); - } // if ( elementCFArrayRef ) - - } // if ( foundIOHIDDeviceRef ) - - } // if ( device not found & vendorID & productID ) - - } // if ( inHIDInfoPtr->locID && inHIDInfoPtr->device.vendorID && inHIDInfoPtr->device.productID ) - // can't find matching device return NULL, do not return first device - if ( (!foundIOHIDDeviceRef) || (!foundIOHIDElementRef) ) { - // no HID device - *outIOHIDDeviceRef = NULL; - *outIOHIDElementRef = NULL; - return (inHIDInfoPtr->actionCookie); - } else { - // HID device - *outIOHIDDeviceRef = foundIOHIDDeviceRef; - *outIOHIDElementRef = foundIOHIDElementRef; - return (inHIDInfoPtr->actionCookie); - } -} // HIDGetElementConfig - -#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 diff --git a/src/cocoa/HID_Error_Handler.c b/src/cocoa/HID_Error_Handler.c deleted file mode 100644 index 0802a2ca7..000000000 --- a/src/cocoa/HID_Error_Handler.c +++ /dev/null @@ -1,108 +0,0 @@ -// File: HID_Error_Handler.c -// Abstract: Implementation of the HID utilities error handlers -// Version: 2.0 -// -// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple -// Inc. ("Apple") in consideration of your agreement to the following -// terms, and your use, installation, modification or redistribution of -// this Apple software constitutes acceptance of these terms. If you do -// not agree with these terms, please do not use, install, modify or -// redistribute this Apple software. -// -// In consideration of your agreement to abide by the following terms, and -// subject to these terms, Apple grants you a personal, non-exclusive -// license, under Apple's copyrights in this original Apple software (the -// "Apple Software"), to use, reproduce, modify and redistribute the Apple -// Software, with or without modifications, in source and/or binary forms; -// provided that if you redistribute the Apple Software in its entirety and -// without modifications, you must retain this notice and the following -// text and disclaimers in all such redistributions of the Apple Software. -// Neither the name, trademarks, service marks or logos of Apple Inc. may -// be used to endorse or promote products derived from the Apple Software -// without specific prior written permission from Apple. Except as -// expressly stated in this notice, no other rights or licenses, express or -// implied, are granted by Apple herein, including but not limited to any -// patent rights that may be infringed by your derivative works or by other -// works in which the Apple Software may be incorporated. -// -// The Apple Software is provided by Apple on an "AS IS" basis. APPLE -// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION -// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS -// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND -// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. -// -// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL -// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, -// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED -// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), -// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Copyright (C) 2009 Apple Inc. All Rights Reserved. -// -//***************************************************** - -#include - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 - -#ifdef DEBUG // not used in release -#if !defined (kBuildingLibrary) -#define kVerboseErrors - -// system includes ---------------------------------------------------------- - -#ifdef kVerboseErrors -//#include -#endif -#endif // not kBuildingLibrary -#endif // DEBUG - -#include - -// project includes --------------------------------------------------------- - -#include "HID_Utilities_External.h" - -// globals (internal/private) ----------------------------------------------- - -// prototypes (internal/private) -------------------------------------------- - -// functions (internal/private) --------------------------------------------- - -#pragma mark - -// ------------------------------------- - -// central error reporting - -void HIDReportErrorNum(const char *strError, int numError) { - char errMsgCStr[256]; - - sprintf(errMsgCStr, "%s #%d (0x%x)", strError, numError, numError); - - // out as debug string -#ifdef kVerboseErrors - { - fputs(errMsgCStr, stderr); - } -#endif // kVerboseErrors -} // HIDReportErrorNum - -// ------------------------------------- - -void HIDReportError(const char *strError) { - char errMsgCStr[256]; - - sprintf(errMsgCStr, "%s", strError); - - // out as debug string -#ifdef kVerboseErrors - { - fputs(errMsgCStr, stderr); - } -#endif // kVerboseErrors -} // HIDReportError - -#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 diff --git a/src/cocoa/HID_Name_Lookup.c b/src/cocoa/HID_Name_Lookup.c deleted file mode 100644 index c9a1ca264..000000000 --- a/src/cocoa/HID_Name_Lookup.c +++ /dev/null @@ -1,1210 +0,0 @@ -// File: HID_Name_Lookup.c -// Abstract: HID Name Lookup Utilities. -// Version: 2.0 -// -// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple -// Inc. ("Apple") in consideration of your agreement to the following -// terms, and your use, installation, modification or redistribution of -// this Apple software constitutes acceptance of these terms. If you do -// not agree with these terms, please do not use, install, modify or -// redistribute this Apple software. -// -// In consideration of your agreement to abide by the following terms, and -// subject to these terms, Apple grants you a personal, non-exclusive -// license, under Apple's copyrights in this original Apple software (the -// "Apple Software"), to use, reproduce, modify and redistribute the Apple -// Software, with or without modifications, in source and/or binary forms; -// provided that if you redistribute the Apple Software in its entirety and -// without modifications, you must retain this notice and the following -// text and disclaimers in all such redistributions of the Apple Software. -// Neither the name, trademarks, service marks or logos of Apple Inc. may -// be used to endorse or promote products derived from the Apple Software -// without specific prior written permission from Apple. Except as -// expressly stated in this notice, no other rights or licenses, express or -// implied, are granted by Apple herein, including but not limited to any -// patent rights that may be infringed by your derivative works or by other -// works in which the Apple Software may be incorporated. -// -// The Apple Software is provided by Apple on an "AS IS" basis. APPLE -// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION -// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS -// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND -// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. -// -// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL -// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, -// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED -// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), -// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Copyright (C) 2009 Apple Inc. All Rights Reserved. -// -//***************************************************** - -#include - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 - -#pragma mark - includes & imports -//***************************************************** -#include "HID_Utilities_External.h" -//***************************************************** -#pragma mark - typedefs, enums, defines, etc. -//***************************************************** -#define FAKE_MISSING_NAMES 0 // for debugging; returns the vendor, product & cookie ( or usage info ) as numbers. -#define VERBOSE_ELEMENT_NAMES 0 // set TRUE to include vender & product names in element names ( useful for debugging ) - -#define kNameKeyCFStringRef CFSTR("Name") -//***************************************************** -#pragma mark - local ( static ) function prototypes -//***************************************************** - -#if 0 // currently unused -static SInt32 hu_SaveToXMLFile(CFPropertyListRef inCFPRef, CFURLRef inCFURLRef); -static SInt32 hu_XMLSave(CFPropertyListRef inCFPropertyListRef, CFStringRef inResourceName, CFStringRef inResourceExtension); -#endif -static CFPropertyListRef hu_LoadFromXMLFile(CFURLRef inCFURLRef); -static CFPropertyListRef hu_XMLLoad(CFStringRef inResourceName, CFStringRef inResourceExtension); - -static Boolean hu_XMLSearchForElementNameByCookie(long inVendorID, long inProductID, IOHIDElementCookie inCookie, char *outCStr); -static Boolean hu_XMLSearchForElementNameByUsage(long inVendorID, long inProductID, long inUsagePage, long inUsage, char *outCStr); - -static Boolean hu_XMLSearchForVendorNameByVendorID(long inVendorID, char *outCStr); -static Boolean hu_XMLSearchForProductNameByVendorProductID(long inVendorID, long inProductID, char *outCStr); - -#if 0 // currently unused -static Boolean hu_AddVendorProductToCFDict(CFMutableDictionaryRef inCFMutableDictionaryRef, - long inVendorID, - CFStringRef inVendorCFStringRef, - long inProductID, - CFStringRef inProductCFStringRef); -static Boolean hu_AddDeviceElementToUsageXML(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef); -#endif -//***************************************************** -#pragma mark - exported globals -//***************************************************** -#pragma mark - local ( static ) globals -//***************************************************** -static CFPropertyListRef gCookieCFPropertyListRef = NULL; -static CFPropertyListRef gUsageCFPropertyListRef = NULL; - -//***************************************************** -#pragma mark - exported function implementations -//***************************************************** - -/************************************************************************* - * - * HIDGetVendorNameFromVendorID( inVendorID, inProductID, inCookie, outCStrName ) - * - * Purpose: Uses an devices vendor ID to generate a name for it. - * - * Notes: Now uses XML files to store dictionary of names - * - * Inputs: inVendorID - the elements vendor ID - * outCStrName - address where result will be returned - * Returns: Boolean - if successful - */ -Boolean HIDGetVendorNameFromVendorID(long inVendorID, char *outCStrName) { - Boolean result = FALSE; - *outCStrName = 0; // clear name - if ( hu_XMLSearchForVendorNameByVendorID(inVendorID, outCStrName) ) { - return (TRUE); - } - -#if FAKE_MISSING_NAMES - sprintf(outCStrName, "#{ V: %ld}#", inVendorID); - result = TRUE; -#endif // FAKE_MISSING_NAMES - return (result); -} // HIDGetVendorNameFromVendorID - -/************************************************************************* - * - * HIDGetProductNameFromVendorProductID( inVendorID, inProductID, outCStrName ) - * - * Purpose: Uses an elements vendor, product & usage info to generate a name for it. - * - * Notes: Now uses XML files to store dictionary of names - * - * Inputs: inVendorID - the elements vendor ID - * inProductID - the elements product ID - * inUsagePage - the elements usage page - * inUsage - the elements usage - * outCStrName - address where result will be returned - * Returns: Boolean - if successful - */ -Boolean HIDGetProductNameFromVendorProductID(long inVendorID, long inProductID, char *outCStrName) { - Boolean result = FALSE; - *outCStrName = 0; // clear name - if ( hu_XMLSearchForProductNameByVendorProductID(inVendorID, inProductID, outCStrName) ) { - return (TRUE); - } - -#if FAKE_MISSING_NAMES - sprintf(outCStrName, "#{ V: %ld, P: %ld, U: %ld: %ld}#", inVendorID, inProductID, inUsagePage, inUsage); - result = TRUE; -#endif // FAKE_MISSING_NAMES - return (result); -} // HIDGetProductNameFromVendorProductID - -/************************************************************************* - * - * HIDGetElementNameFromVendorProductCookie( inVendorID, inProductID, inCookie, outCStrName ) - * - * Purpose: Uses an elements vendor, product & cookie to generate a name for it. - * - * Notes: Now uses XML files to store dictionary of names - * - * Inputs: inVendorID - the elements vendor ID - * inProductID - the elements product ID - * inCookie - the elements cookie - * outCStrName - address where result will be returned - * Returns: Boolean - if successful - */ -Boolean HIDGetElementNameFromVendorProductCookie(int inVendorID, int inProductID, IOHIDElementCookie inCookie, char *outCStrName) { - Boolean result = FALSE; - *outCStrName = 0; // clear name - // Look in the XML file first - if ( hu_XMLSearchForElementNameByCookie(inVendorID, inProductID, inCookie, outCStrName) ) { - return (TRUE); - } - -#if FAKE_MISSING_NAMES - sprintf(outCStrName, "#{ V: %ld, P: %ld, C: %ld}#", inVendorID, inProductID, inCookie); -#else - result = FALSE; -#endif // FAKE_MISSING_NAMES - return (result); -} // HIDGetElementNameFromVendorProductCookie - -/************************************************************************* - * - * HIDGetElementNameFromVendorProductUsage( inVendorID, inProductID, inUsagePage, inUsage, outCStrName ) - * - * Purpose: Uses an elements vendor, product & usage info to generate a name for it. - * - * Notes: Now uses XML files to store dictionary of names - * - * Inputs: inVendorID - the elements vendor ID - * inProductID - the elements product ID - * inUsagePage - the elements usage page - * inUsage - the elements usage - * outCStrName - address where result will be returned - * Returns: Boolean - if successful - */ -Boolean HIDGetElementNameFromVendorProductUsage(long inVendorID, - long inProductID, - long inUsagePage, - long inUsage, - char *outCStrName) { - Boolean result = FALSE; - *outCStrName = 0; // clear name - if ( hu_XMLSearchForElementNameByUsage(inVendorID, inProductID, inUsagePage, inUsage, outCStrName) ) { - return (TRUE); - } - -#if FAKE_MISSING_NAMES - sprintf(outCStrName, "#{ V: %ld, P: %ld, U: %ld: %ld}#", inVendorID, inProductID, inUsagePage, inUsage); - result = TRUE; -#endif // FAKE_MISSING_NAMES - return (result); -} // HIDGetElementNameFromVendorProductUsage - -#if 0 // currently unused -/************************************************************************* - * - * HIDAddDeviceToXML( inDevice ) - * - * Purpose: Adds a devices info to the HID_device_usage_strings.plist( XML ) file - * - * Inputs: inDevice - the device - * Returns: Boolean - if successful - */ -static Boolean HIDAddDeviceToXML(IOHIDDeviceRef inIOHIDDeviceRef) { - Boolean result = FALSE; - if ( HIDIsValidDevice(inIOHIDDeviceRef) ) { - CFStringRef vendorCFStringRef = IOHIDDevice_GetManufacturer(inIOHIDDeviceRef); - CFStringRef productCFStringRef = IOHIDDevice_GetProduct(inIOHIDDeviceRef); - if ( vendorCFStringRef && productCFStringRef ) { -#if 0 // don't update the cookie xml file - gCookieCFPropertyListRef = - hu_XMLLoad( CFSTR( - "HID_cookie_strings"), CFSTR("plist") ); - if ( gCookieCFPropertyListRef ) { - CFMutableDictionaryRef tCFMutableDictionaryRef = - CFDictionaryCreateMutableCopy( - kCFAllocatorDefault, - 0, - gCookieCFPropertyListRef); - if ( tCFMutableDictionaryRef ) { - if ( hu_AddVendorProductToCFDict(tCFMutableDictionaryRef, vendorID, vendorCFStringRef, productID, - productCFStringRef) ) - { - hu_XMLSave( tCFMutableDictionaryRef, - CFSTR( - "HID_cookie_strings"), CFSTR("plist") ); - result = TRUE; - } - - CFRelease(tCFMutableDictionaryRef); - } - } - -#endif - if ( gUsageCFPropertyListRef ) { - CFRelease(gUsageCFPropertyListRef); - } - - gUsageCFPropertyListRef = - hu_XMLLoad( CFSTR( - "HID_device_usage_strings"), CFSTR("plist") ); - if ( gUsageCFPropertyListRef ) { - CFMutableDictionaryRef tCFMutableDictionaryRef = - CFDictionaryCreateMutableCopy( - kCFAllocatorDefault, - 0, - gUsageCFPropertyListRef); - if ( tCFMutableDictionaryRef ) { - long vendorID = IOHIDDevice_GetVendorID(inIOHIDDeviceRef); - long productID = IOHIDDevice_GetProductID(inIOHIDDeviceRef); - if ( hu_AddVendorProductToCFDict(tCFMutableDictionaryRef, vendorID, vendorCFStringRef, productID, - productCFStringRef) ) - { - hu_XMLSave( tCFMutableDictionaryRef, - CFSTR( - "HID_device_usage_strings"), CFSTR("plist") ); - result = TRUE; - } - - CFRelease(tCFMutableDictionaryRef); - } - } - } - } - - return (result); -} // HIDAddDeviceToXML - -/************************************************************************* - * - * HIDAddDeviceElementToXML( inDevice, inElement ) - * - * Purpose: Adds a devices info to the HID_device_usage_strings.plist( XML ) file - * - * Inputs: inDevice - the device - * inElement - the element - * - * Returns: Boolean - if successful - */ -Boolean HIDAddDeviceElementToXML(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef) { - Boolean result = FALSE; - if ( HIDIsValidElement(inIOHIDElementRef) ) { - if ( HIDAddDeviceToXML(inIOHIDDeviceRef) ) { - result = TRUE; - } - if ( hu_AddDeviceElementToUsageXML(inIOHIDDeviceRef, inIOHIDElementRef) ) { - result = TRUE; - } - } - - return (result); -} // HIDAddDeviceElementToXML -#endif -/************************************************************************* - * - * HIDGetTypeName( inIOHIDElementType, outCStrName ) - * - * Purpose: return a C string for a given element type( see IOHIDKeys.h ) - * Notes: returns "Unknown Type" for invalid types - * - * Inputs: inIOHIDElementType - type element type - * outCStrName - address where to store element type string - * - * Returns: outCStrName - the element type string - */ - -void HIDGetTypeName(IOHIDElementType inIOHIDElementType, char *outCStrName) { - switch ( inIOHIDElementType ) { - case kIOHIDElementTypeInput_Misc: - { - sprintf(outCStrName, "Miscellaneous Input"); - break; - } - - case kIOHIDElementTypeInput_Button: - { - sprintf(outCStrName, "Button Input"); - break; - } - - case kIOHIDElementTypeInput_Axis: - { - sprintf(outCStrName, "Axis Input"); - break; - } - - case kIOHIDElementTypeInput_ScanCodes: - { - sprintf(outCStrName, "Scan Code Input"); - break; - } - - case kIOHIDElementTypeOutput: - { - sprintf(outCStrName, "Output"); - break; - } - - case kIOHIDElementTypeFeature: - { - sprintf(outCStrName, "Feature"); - break; - } - - case kIOHIDElementTypeCollection: - { - sprintf(outCStrName, "Collection"); - break; - } - - default: - { - sprintf(outCStrName, "Unknown Type"); - break; - } - } // switch - -} // HIDGetTypeName - -//************************************************************************* -// -// HIDCopyUsageName( inUsagePage, inUsage ) -// -// Purpose: return a CFStringRef string for a given usage page & usage( see IOUSBHIDParser.h ) -// -// Notes: returns usage page and usage values in CFString form for unknown values -// -// Inputs: inUsagePage - the usage page -// inUsage - the usage -// -// Returns: CFStringRef - the resultant string -// - -CFStringRef HIDCopyUsageName(long inUsagePage, long inUsage) { - static CFPropertyListRef tCFPropertyListRef = NULL; - CFStringRef result = NULL; - if ( !tCFPropertyListRef ) { - tCFPropertyListRef = - hu_XMLLoad( CFSTR( - "HID_usage_strings"), CFSTR("plist") ); - } - if ( tCFPropertyListRef ) { - if ( - CFDictionaryGetTypeID() == CFGetTypeID(tCFPropertyListRef) ) - { - CFStringRef pageKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("0x%4.4lX"), inUsagePage); - if ( pageKeyCFStringRef ) { - CFDictionaryRef pageCFDictionaryRef; - if ( CFDictionaryGetValueIfPresent(tCFPropertyListRef, pageKeyCFStringRef, - (const void **) &pageCFDictionaryRef) ) - { - CFStringRef pageCFStringRef; - if ( CFDictionaryGetValueIfPresent(pageCFDictionaryRef, kNameKeyCFStringRef, - (const void **) &pageCFStringRef) ) - { - CFStringRef usageKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR( - "0x%4.4lX"), inUsage); - if ( usageKeyCFStringRef ) { - CFStringRef usageCFStringRef; - if ( CFDictionaryGetValueIfPresent(pageCFDictionaryRef, usageKeyCFStringRef, - (const void **) &usageCFStringRef) ) - { - result = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR( - "%@ %@"), pageCFStringRef, usageCFStringRef); - } - -#if FAKE_MISSING_NAMES - else { - result = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR( - "%@ #%@"), pageCFStringRef, usageKeyCFStringRef); - } -#endif - CFRelease(usageKeyCFStringRef); - } - } else { - // no name data for this page - } - } else { - // no data for this page - } - - CFRelease(pageKeyCFStringRef); - } - } - - // CFRelease( tCFPropertyListRef ); // Leak this! - // tCFPropertyListRef = NULL; - } - - return (result); -} // HIDCopyUsageName - -//***************************************************** -#pragma mark - local ( static ) function implementations -//***************************************************** -#if 0 // currently unused -/************************************************************************* - * - * hu_SaveToXMLFile( inCFPRef, inCFURLRef ) - * - * Purpose: save a property list into an XML file - * - * Inputs: inCFPRef - the data - * inCFURLRef - URL for the file - * - * Returns: SInt32 - error code ( if any ) - */ -static SInt32 hu_SaveToXMLFile(CFPropertyListRef inCFPRef, CFURLRef inCFURLRef) { - CFDataRef xmlCFDataRef; - SInt32 error = coreFoundationUnknownErr; - - // Convert the property list into XML data. - xmlCFDataRef = CFPropertyListCreateXMLData(kCFAllocatorDefault, inCFPRef); - if ( xmlCFDataRef ) { - // Write the XML data to the file. - (void) CFURLWriteDataAndPropertiesToResource(inCFURLRef, xmlCFDataRef, NULL, &error); - - // Release the XML data - CFRelease(xmlCFDataRef); - } - - return (error); -} // hu_SaveToXMLFile -#endif -/************************************************************************* - * - * hu_LoadFromXMLFile( inCFURLRef ) - * - * Purpose: load a property list from an XML file - * - * Inputs: inCFURLRef - URL for the file - * - * Returns: CFPropertyListRef - the data - */ -static CFPropertyListRef hu_LoadFromXMLFile(CFURLRef inCFURLRef) { - CFDataRef xmlCFDataRef; - CFPropertyListRef myCFPropertyListRef = NULL; - - // Read the XML file. - SInt32 error; - if ( CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, inCFURLRef, &xmlCFDataRef, NULL, NULL, &error) ) { - CFStringRef errorString; - // Reconstitute the dictionary using the XML data. - myCFPropertyListRef = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, - xmlCFDataRef, - kCFPropertyListImmutable, - &errorString); - // Release the XML data - CFRelease(xmlCFDataRef); - } - - return (myCFPropertyListRef); -} // hu_LoadFromXMLFile - -#if 0 // currently unused -/************************************************************************* - * - * hu_XMLSave( inCFPropertyListRef, inResourceName, inResourceExtension ) - * - * Purpose: save a CFPropertyListRef into a resource( XML ) file - * - * Inputs: inCFPropertyListRef - the data - * inResourceName - name of the resource file - * inResourceExtension - extension of the resource file - * - * Returns: SInt32 - error code ( if any ) - */ -static SInt32 hu_XMLSave(CFPropertyListRef inCFPropertyListRef, CFStringRef inResourceName, CFStringRef inResourceExtension) { - CFURLRef resFileCFURLRef; - SInt32 error = -1; - - // check the main (application) bundle - resFileCFURLRef = CFBundleCopyResourceURL(CFBundleGetMainBundle(), inResourceName, inResourceExtension, NULL); - - if ( !resFileCFURLRef ) { - // check this specific (HID_Utilities framework) bundle - CFBundleRef tCFBundleRef = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HID_Utilities")); - if ( tCFBundleRef ) { - resFileCFURLRef = CFBundleCopyResourceURL( tCFBundleRef, inResourceName, inResourceExtension, NULL ); - } - } - if ( !resFileCFURLRef ) { - // check bundles already loaded or otherwise known to the current process - CFArrayRef tCFArrayRef = CFBundleGetAllBundles(); - CFIndex idx, cnt = CFArrayGetCount(tCFArrayRef); - for ( idx = 0; idx < cnt; idx++ ) { - CFBundleRef tCFBundleRef = (CFBundleRef) CFArrayGetValueAtIndex(tCFArrayRef, idx) ; - if ( tCFBundleRef ) { - resFileCFURLRef = CFBundleCopyResourceURL( tCFBundleRef, inResourceName, inResourceExtension, NULL ); - if ( resFileCFURLRef ) { - break; - } - } - } - } - if ( resFileCFURLRef ) { - error = hu_SaveToXMLFile(inCFPropertyListRef, resFileCFURLRef); - CFRelease(resFileCFURLRef); - } - - return (error); -} // hu_XMLSave -#endif -/************************************************************************* - * - * hu_XMLLoad( inResourceName, inResourceExtension ) - * - * Purpose: Load a resource( XML ) file into a CFPropertyListRef - * - * Inputs: inResourceName - name of the resource file - * inResourceExtension - extension of the resource file - * - * Returns: CFPropertyListRef - the data - */ -static CFPropertyListRef hu_XMLLoad(CFStringRef inResourceName, CFStringRef inResourceExtension) { - CFURLRef resFileCFURLRef; - CFPropertyListRef tCFPropertyListRef = NULL; - - // check the main (application) bundle - resFileCFURLRef = CFBundleCopyResourceURL(CFBundleGetMainBundle(), inResourceName, inResourceExtension, NULL); - - if ( !resFileCFURLRef ) { - // check this specific (HID_Utilities framework) bundle - CFBundleRef tCFBundleRef = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HID_Utilities")); - if ( tCFBundleRef ) { - resFileCFURLRef = CFBundleCopyResourceURL( tCFBundleRef, inResourceName, inResourceExtension, NULL ); - } - } - if ( !resFileCFURLRef ) { - // check bundles already loaded or otherwise known to the current process - CFArrayRef tCFArrayRef = CFBundleGetAllBundles(); - CFIndex idx, cnt = CFArrayGetCount(tCFArrayRef); - for ( idx = 0; idx < cnt; idx++ ) { - CFBundleRef tCFBundleRef = (CFBundleRef) CFArrayGetValueAtIndex(tCFArrayRef, idx) ; - if ( tCFBundleRef ) { - resFileCFURLRef = CFBundleCopyResourceURL( tCFBundleRef, inResourceName, inResourceExtension, NULL ); - if ( resFileCFURLRef ) { - break; - } - } - } - } - if ( resFileCFURLRef ) { - tCFPropertyListRef = hu_LoadFromXMLFile(resFileCFURLRef); - CFRelease(resFileCFURLRef); - } - - return (tCFPropertyListRef); -} // hu_XMLLoad - -/************************************************************************* - * - * hu_XMLSearchForVendorNameByVendorID( inVendorID, outCStr ) - * - * Purpose: Find a vendor string in the resource ( XML ) file - * - * Inputs: inVendorID - the elements vendor ID - * inProductID - the elements product ID - * outCStr - address where result will be returned - * - * Returns: Boolean - if successful - */ -static Boolean hu_XMLSearchForVendorNameByVendorID(long inVendorID, char *outCStr) { - Boolean results = FALSE; - if ( !gUsageCFPropertyListRef ) { - gUsageCFPropertyListRef = - hu_XMLLoad( CFSTR( - "HID_device_usage_strings"), CFSTR("plist") ); - } - if ( gUsageCFPropertyListRef ) { - if ( - CFDictionaryGetTypeID() == CFGetTypeID(gUsageCFPropertyListRef) ) - { - CFDictionaryRef vendorCFDictionaryRef; - CFStringRef vendorKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), inVendorID); - if ( vendorKeyCFStringRef ) { - if ( CFDictionaryGetValueIfPresent(gUsageCFPropertyListRef, vendorKeyCFStringRef, - (const void **) &vendorCFDictionaryRef) ) - { - CFStringRef vendorCFStringRef = NULL; - if ( CFDictionaryGetValueIfPresent(vendorCFDictionaryRef, kNameKeyCFStringRef, - (const void **) &vendorCFStringRef) && vendorCFStringRef ) - { - // CFShow( vendorCFStringRef ); - results = - CFStringGetCString(vendorCFStringRef, outCStr, CFStringGetLength( - vendorCFStringRef) * sizeof(UniChar) + 1, kCFStringEncodingUTF8); - } - } - - CFRelease(vendorKeyCFStringRef); - } - } - - // ++ CFRelease( gUsageCFPropertyListRef ); // Leak this ! - } - - return (results); -} // hu_XMLSearchForVendorNameByVendorID - -/************************************************************************* - * - * hu_XMLSearchForProductNameByVendorProductID( inVendorID, inProductID, outCStr ) - * - * Purpose: Find an product string in the resource ( XML ) file - * - * Inputs: inVendorID - the elements vendor ID - * inProductID - the elements product ID - * outCStr - address where result will be returned - * - * Returns: Boolean - if successful - */ -static Boolean hu_XMLSearchForProductNameByVendorProductID(long inVendorID, long inProductID, char *outCStr) { - Boolean results = FALSE; - if ( !gUsageCFPropertyListRef ) { - gUsageCFPropertyListRef = - hu_XMLLoad( CFSTR( - "HID_device_usage_strings"), CFSTR("plist") ); - } - if ( gUsageCFPropertyListRef ) { - if ( - CFDictionaryGetTypeID() == CFGetTypeID(gUsageCFPropertyListRef) ) - { - // first we make our vendor ID key - CFStringRef vendorKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), inVendorID); - if ( vendorKeyCFStringRef ) { - // and use it to look up our vendor dictionary - CFDictionaryRef vendorCFDictionaryRef; - if ( CFDictionaryGetValueIfPresent(gUsageCFPropertyListRef, vendorKeyCFStringRef, - (const void **) &vendorCFDictionaryRef) ) - { - // pull our vendor name our of that dictionary - CFStringRef vendorCFStringRef = NULL; - if ( CFDictionaryGetValueIfPresent(vendorCFDictionaryRef, kNameKeyCFStringRef, - (const void **) &vendorCFStringRef) ) - { -#if FAKE_MISSING_NAMES - CFRetain(vendorCFStringRef); // so we can CFRelease it later - } else { - vendorCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR( - "V: %@"), vendorKeyCFStringRef); -#endif - } - - // now we make our product ID key - CFStringRef productKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR( - "%ld"), inProductID); - if ( productKeyCFStringRef ) { - // and use that key to look up our product dictionary in the vendor dictionary - CFDictionaryRef productCFDictionaryRef; - if ( CFDictionaryGetValueIfPresent(vendorCFDictionaryRef, productKeyCFStringRef, - (const void **) &productCFDictionaryRef) ) - { - // pull our product name our of the product dictionary - CFStringRef productCFStringRef = NULL; - if ( CFDictionaryGetValueIfPresent(productCFDictionaryRef, kNameKeyCFStringRef, - (const void **) &productCFStringRef) ) - { -#if FAKE_MISSING_NAMES - CFRetain(productCFStringRef); // so we can CFRelease it later - } else { - productCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR( - "P: %@"), kNameKeyCFStringRef); -#endif - } - - CFStringRef fullCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR( - "%@ %@"), vendorCFStringRef, - productCFStringRef); - if ( fullCFStringRef ) { - // CFShow( fullCFStringRef ); - results = - CFStringGetCString(fullCFStringRef, outCStr, CFStringGetLength( - fullCFStringRef) * sizeof(UniChar) + 1, kCFStringEncodingUTF8); - CFRelease(fullCFStringRef); - } - -#if FAKE_MISSING_NAMES - if ( productCFStringRef ) { - CFRelease(productCFStringRef); - } - -#endif - } - - CFRelease(productKeyCFStringRef); - } - -#if FAKE_MISSING_NAMES - if ( vendorCFStringRef ) { - CFRelease(vendorCFStringRef); - } - -#endif - } - - CFRelease(vendorKeyCFStringRef); - } - } - - // ++ CFRelease( gUsageCFPropertyListRef ); // Leak this ! - } - - return (results); -} // hu_XMLSearchForProductNameByVendorProductID - -/************************************************************************* - * - * hu_XMLSearchForElementNameByCookie( inVendorID, inProductID, inCookie, outCStr ) - * - * Purpose: Find an element string in the resource( XML ) file - * - * Inputs: inVendorID - the elements vendor ID - * inProductID - the elements product ID - * inCookie - the elements cookie - * outCStr - address where result will be returned - * - * Returns: Boolean - if successful - */ -static Boolean hu_XMLSearchForElementNameByCookie(long inVendorID, long inProductID, IOHIDElementCookie inCookie, char *outCStr) { - Boolean results = FALSE; - if ( !gCookieCFPropertyListRef ) { - gCookieCFPropertyListRef = - hu_XMLLoad( CFSTR( - "HID_cookie_strings"), CFSTR("plist") ); - } - if ( gCookieCFPropertyListRef ) { - if ( - CFDictionaryGetTypeID() == CFGetTypeID(gCookieCFPropertyListRef) ) - { - CFStringRef vendorKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), inVendorID); - if ( vendorKeyCFStringRef ) { - CFDictionaryRef vendorCFDictionaryRef; - if ( CFDictionaryGetValueIfPresent(gCookieCFPropertyListRef, vendorKeyCFStringRef, - (const void **) &vendorCFDictionaryRef) ) - { - CFDictionaryRef productCFDictionaryRef; - CFStringRef productKeyCFStringRef; - CFStringRef vendorCFStringRef; - if ( CFDictionaryGetValueIfPresent(vendorCFDictionaryRef, kNameKeyCFStringRef, - (const void **) &vendorCFStringRef) ) - { - // CFShow( vendorCFStringRef ); - } - - productKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), inProductID); - if ( CFDictionaryGetValueIfPresent(vendorCFDictionaryRef, productKeyCFStringRef, - (const void **) &productCFDictionaryRef) ) - { - CFStringRef fullCFStringRef = NULL; - CFStringRef cookieKeyCFStringRef; - CFStringRef productCFStringRef; - CFStringRef cookieCFStringRef; - if ( CFDictionaryGetValueIfPresent(productCFDictionaryRef, kNameKeyCFStringRef, - (const void **) &productCFStringRef) ) - { - // CFShow( productCFStringRef ); - } - - cookieKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), inCookie); - if ( CFDictionaryGetValueIfPresent(productCFDictionaryRef, cookieKeyCFStringRef, - (const void **) &cookieCFStringRef) ) - { -#if VERBOSE_ELEMENT_NAMES - fullCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR( - "%@ %@ %@"), vendorCFStringRef, productCFStringRef, - cookieCFStringRef); -#else - fullCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), cookieCFStringRef); -#endif // VERBOSE_ELEMENT_NAMES - // CFShow( cookieCFStringRef ); - } - -#if FAKE_MISSING_NAMES - else { - fullCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR( - "%@ %@ # %@"), vendorCFStringRef, productCFStringRef, - cookieKeyCFStringRef); - } -#endif // FAKE_MISSING_NAMES - if ( fullCFStringRef ) { - // CFShow( fullCFStringRef ); - results = - CFStringGetCString(fullCFStringRef, outCStr, CFStringGetLength( - fullCFStringRef) * sizeof(UniChar) + 1, kCFStringEncodingUTF8); - CFRelease(fullCFStringRef); - } - - CFRelease(cookieKeyCFStringRef); - } - - CFRelease(productKeyCFStringRef); - } - - CFRelease(vendorKeyCFStringRef); - } - } - - // ++ CFRelease( gCookieCFPropertyListRef ); // Leak this ! - } - - return (results); -} // hu_XMLSearchForElementNameByCookie - -/************************************************************************* - * - * hu_XMLSearchForElementNameByUsage( inVendorID, inProductID, inUsagePage, inUsage, outCStr ) - * - * Purpose: Find an element string in the resource( XML ) file - * - * Inputs: inVendorID - the elements vendor ID - * inProductID - the elements product ID - * inUsagePage - the elements usage page - * inUsage - the elements usage - * outCStr - address where result will be returned - * - * Returns: Boolean - if successful - */ -static Boolean hu_XMLSearchForElementNameByUsage(long inVendorID, long inProductID, long inUsagePage, long inUsage, - char *outCStr) { - Boolean results = FALSE; - if ( !gUsageCFPropertyListRef ) { - gUsageCFPropertyListRef = - hu_XMLLoad( CFSTR( - "HID_device_usage_strings"), CFSTR("plist") ); - } - if ( gUsageCFPropertyListRef ) { - if ( - CFDictionaryGetTypeID() == CFGetTypeID(gUsageCFPropertyListRef) ) - { - CFStringRef vendorKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), inVendorID); - if ( vendorKeyCFStringRef ) { - CFDictionaryRef vendorCFDictionaryRef; - if ( CFDictionaryGetValueIfPresent(gUsageCFPropertyListRef, vendorKeyCFStringRef, - (const void **) &vendorCFDictionaryRef) ) - { - CFStringRef vendorCFStringRef = NULL; - if ( CFDictionaryGetValueIfPresent(vendorCFDictionaryRef, kNameKeyCFStringRef, - (const void **) &vendorCFStringRef) ) - { - vendorCFStringRef = CFStringCreateCopy(kCFAllocatorDefault, vendorCFStringRef); - } else { - vendorCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("v: %ld"), inVendorID); - // CFShow( vendorCFStringRef ); - } - - CFStringRef productKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR( - "%ld"), inProductID); - - CFDictionaryRef productCFDictionaryRef; - if ( CFDictionaryGetValueIfPresent(vendorCFDictionaryRef, productKeyCFStringRef, - (const void **) &productCFDictionaryRef) ) - { - CFStringRef fullCFStringRef = NULL; - - CFStringRef productCFStringRef; - if ( CFDictionaryGetValueIfPresent(productCFDictionaryRef, kNameKeyCFStringRef, - (const void **) &productCFStringRef) ) - { - // CFShow( productCFStringRef ); - } - - CFStringRef usageKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR( - "%ld:%ld"), inUsagePage, inUsage); - CFStringRef usageCFStringRef; - if ( CFDictionaryGetValueIfPresent(productCFDictionaryRef, usageKeyCFStringRef, - (const void **) &usageCFStringRef) ) - { -#if VERBOSE_ELEMENT_NAMES - fullCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR( - "%@ %@ %@"), vendorCFStringRef, productCFStringRef, - usageCFStringRef); -#else - fullCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@"), usageCFStringRef); -#endif // VERBOSE_ELEMENT_NAMES - // CFShow( usageCFStringRef ); - } - -#if FAKE_MISSING_NAMES - else { - fullCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR( - "%@ %@ # %@"), vendorCFStringRef, productCFStringRef, - usageKeyCFStringRef); - } -#endif // FAKE_MISSING_NAMES - if ( fullCFStringRef ) { - // CFShow( fullCFStringRef ); - results = - CFStringGetCString(fullCFStringRef, outCStr, CFStringGetLength( - fullCFStringRef) * sizeof(UniChar) + 1, kCFStringEncodingUTF8); - CFRelease(fullCFStringRef); - } - - CFRelease(usageKeyCFStringRef); - } - if ( vendorCFStringRef ) { - CFRelease(vendorCFStringRef); - } - - CFRelease(productKeyCFStringRef); - } - - CFRelease(vendorKeyCFStringRef); - } - } - - // ++ CFRelease( gUsageCFPropertyListRef ); // Leak this ! - } - - return (results); -} // hu_XMLSearchForElementNameByUsage - -#if 0 // currently unused -/************************************************************************* - * - * hu_AddVendorProductToCFDict( inCFMutableDictionaryRef, inVendorID, inVendorCFStringRef, inProductID, inProductCFStringRef ) - * - * Purpose: add a vendor & product to a dictionary - * - * Inputs: inCFMutableDictionaryRef - the dictionary - * inVendorID - the elements vendor ID - * inProductID - the elements product ID - * inProductCFStringRef - the string to be added - * - * Returns: Boolean - if successful - */ -static Boolean hu_AddVendorProductToCFDict(CFMutableDictionaryRef inCFMutableDictionaryRef, - long inVendorID, - CFStringRef inVendorCFStringRef, - long inProductID, - CFStringRef inProductCFStringRef) { - Boolean results = FALSE; - if ( inCFMutableDictionaryRef && ( CFDictionaryGetTypeID() == CFGetTypeID(inCFMutableDictionaryRef) ) ) { - CFMutableDictionaryRef vendorCFMutableDictionaryRef; - CFStringRef vendorKeyCFStringRef; - - CFMutableDictionaryRef productCFMutableDictionaryRef; - CFStringRef productKeyCFStringRef; - - // if the vendor dictionary doesn't exist - vendorKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), inVendorID); - if ( CFDictionaryGetValueIfPresent(inCFMutableDictionaryRef, vendorKeyCFStringRef, - (const void **) &vendorCFMutableDictionaryRef) ) - { - // copy it. - vendorCFMutableDictionaryRef = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, vendorCFMutableDictionaryRef); - } else { // ...otherwise... - // create it. - vendorCFMutableDictionaryRef = CFDictionaryCreateMutable(kCFAllocatorDefault, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - results = TRUE; - } - // if the vendor name key doesn't exist - if ( !CFDictionaryContainsKey(vendorCFMutableDictionaryRef, kNameKeyCFStringRef) ) { - // create it. - CFDictionaryAddValue(vendorCFMutableDictionaryRef, kNameKeyCFStringRef, inVendorCFStringRef); - results = TRUE; - } - - // if the product key exists in the vendor dictionary - productKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), inProductID); - if ( CFDictionaryGetValueIfPresent(vendorCFMutableDictionaryRef, productKeyCFStringRef, - (const void **) &productCFMutableDictionaryRef) ) - { - // copy it. - productCFMutableDictionaryRef = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, productCFMutableDictionaryRef); - } else { // ...otherwise... - // create it. - productCFMutableDictionaryRef = CFDictionaryCreateMutable(kCFAllocatorDefault, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - results = TRUE; - } - // if the product name key doesn't exist - if ( !CFDictionaryContainsKey(productCFMutableDictionaryRef, kNameKeyCFStringRef) ) { - // create it. - CFDictionaryAddValue(productCFMutableDictionaryRef, kNameKeyCFStringRef, inProductCFStringRef); - results = TRUE; - } - if ( vendorCFMutableDictionaryRef ) { - if ( productCFMutableDictionaryRef ) { - if ( results ) { - CFDictionarySetValue(vendorCFMutableDictionaryRef, productKeyCFStringRef, productCFMutableDictionaryRef); - } - - CFRelease(productCFMutableDictionaryRef); - } - if ( results ) { - CFDictionarySetValue(inCFMutableDictionaryRef, vendorKeyCFStringRef, vendorCFMutableDictionaryRef); - } - - CFRelease(vendorCFMutableDictionaryRef); - } - if ( productKeyCFStringRef ) { - CFRelease(productKeyCFStringRef); - } - if ( vendorKeyCFStringRef ) { - CFRelease(vendorKeyCFStringRef); - } - } - - return (results); -} // hu_AddVendorProductToCFDict - -/************************************************************************* - * - * hu_AddDeviceElementToUsageXML( inDevice, inElement ) - * - * Purpose: add a device and it's elements to our usage( XML ) file - * - * Inputs: inDevice - the device - * inElement - the element - * - * Returns: Boolean - if successful - */ -static Boolean hu_AddDeviceElementToUsageXML(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef) { - Boolean results = FALSE; - if ( gUsageCFPropertyListRef ) { - CFRelease(gUsageCFPropertyListRef); - } - - gUsageCFPropertyListRef = - hu_XMLLoad( CFSTR( - "HID_device_usage_strings"), CFSTR("plist") ); - if ( gUsageCFPropertyListRef ) { - CFMutableDictionaryRef tCFMutableDictionaryRef = - CFDictionaryCreateMutableCopy( - kCFAllocatorDefault, - 0, - gUsageCFPropertyListRef); - if ( tCFMutableDictionaryRef ) { - CFMutableDictionaryRef vendorCFMutableDictionaryRef; - - CFMutableDictionaryRef productCFMutableDictionaryRef; - CFStringRef productKeyCFStringRef; - - CFStringRef usageKeyCFStringRef; - - // if the vendor dictionary exists... - long vendorID = IOHIDDevice_GetVendorID(inIOHIDDeviceRef); - CFStringRef vendorKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), vendorID); - if ( vendorKeyCFStringRef ) { - if ( CFDictionaryGetValueIfPresent(tCFMutableDictionaryRef, vendorKeyCFStringRef, - (const void **) &vendorCFMutableDictionaryRef) ) - { - // ...copy it... - vendorCFMutableDictionaryRef = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, - 0, - vendorCFMutableDictionaryRef); - } else { // ...otherwise... - // ...create it. - vendorCFMutableDictionaryRef = CFDictionaryCreateMutable(kCFAllocatorDefault, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - results = TRUE; - } - // if the vendor name key doesn't exist... - if ( !CFDictionaryContainsKey(vendorCFMutableDictionaryRef, kNameKeyCFStringRef) ) { - CFStringRef manCFStringRef = IOHIDDevice_GetManufacturer(inIOHIDDeviceRef); - // ...create it. - CFDictionaryAddValue(vendorCFMutableDictionaryRef, kNameKeyCFStringRef, manCFStringRef); - results = TRUE; - } - - // if the product key exists in the vendor dictionary... - long productID = IOHIDDevice_GetProductID(inIOHIDDeviceRef); - productKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld"), productID); - if ( CFDictionaryGetValueIfPresent(vendorCFMutableDictionaryRef, productKeyCFStringRef, - (const void **) &productCFMutableDictionaryRef) ) - { - // ...copy it... - productCFMutableDictionaryRef = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, - 0, - productCFMutableDictionaryRef); - } else { // ...otherwise... - // ...create it. - productCFMutableDictionaryRef = CFDictionaryCreateMutable(kCFAllocatorDefault, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - results = TRUE; - } - // if the product name key doesn't exist... - if ( !CFDictionaryContainsKey(productCFMutableDictionaryRef, kNameKeyCFStringRef) ) { - CFStringRef productCFStringRef = IOHIDDevice_GetProduct(inIOHIDDeviceRef); - // ...create it. - CFDictionaryAddValue(productCFMutableDictionaryRef, kNameKeyCFStringRef, productCFStringRef); - results = TRUE; - } - - // if the usage key doesn't exist in the product dictionary... - uint32_t usagePage = IOHIDElementGetUsagePage(inIOHIDElementRef); - uint32_t usage = IOHIDElementGetUsagePage(inIOHIDElementRef); - usageKeyCFStringRef = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%ld:%ld"), usagePage, usage); - if ( usageKeyCFStringRef ) { - if ( !CFDictionaryContainsKey(productCFMutableDictionaryRef, usageKeyCFStringRef) ) { - // find it's generic name - CFStringRef usageCFStringRef = HIDCopyUsageName(usagePage, usage); - if ( usageCFStringRef ) { - // and add that. - CFDictionaryAddValue(productCFMutableDictionaryRef, usageKeyCFStringRef, usageCFStringRef); - results = TRUE; - CFRelease(usageCFStringRef); - } - } - - CFRelease(usageKeyCFStringRef); - } - if ( vendorCFMutableDictionaryRef ) { - if ( productCFMutableDictionaryRef ) { - if ( results ) { - CFDictionarySetValue(vendorCFMutableDictionaryRef, productKeyCFStringRef, productCFMutableDictionaryRef); - } - - CFRelease(productCFMutableDictionaryRef); - } - if ( results ) { - CFDictionarySetValue(tCFMutableDictionaryRef, vendorKeyCFStringRef, vendorCFMutableDictionaryRef); - } - - CFRelease(vendorCFMutableDictionaryRef); - } - - CFRelease(vendorKeyCFStringRef); - } - if ( productKeyCFStringRef ) { - CFRelease(productKeyCFStringRef); - } - if ( results ) { - hu_XMLSave( tCFMutableDictionaryRef, - CFSTR( - "HID_device_usage_strings"), CFSTR("plist") ); - } - - CFRelease( - tCFMutableDictionaryRef); - } - } - - return (results); -} // hu_AddDeviceElementToUsageXML -#endif - -#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 diff --git a/src/cocoa/HID_Queue_Utilities.c b/src/cocoa/HID_Queue_Utilities.c deleted file mode 100644 index ab1d83667..000000000 --- a/src/cocoa/HID_Queue_Utilities.c +++ /dev/null @@ -1,361 +0,0 @@ -// File: HID_Queue_Utilities.c -// Abstract: HID Queue Utilities. -// Version: 2.0 -// -// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple -// Inc. ("Apple") in consideration of your agreement to the following -// terms, and your use, installation, modification or redistribution of -// this Apple software constitutes acceptance of these terms. If you do -// not agree with these terms, please do not use, install, modify or -// redistribute this Apple software. -// -// In consideration of your agreement to abide by the following terms, and -// subject to these terms, Apple grants you a personal, non-exclusive -// license, under Apple's copyrights in this original Apple software (the -// "Apple Software"), to use, reproduce, modify and redistribute the Apple -// Software, with or without modifications, in source and/or binary forms; -// provided that if you redistribute the Apple Software in its entirety and -// without modifications, you must retain this notice and the following -// text and disclaimers in all such redistributions of the Apple Software. -// Neither the name, trademarks, service marks or logos of Apple Inc. may -// be used to endorse or promote products derived from the Apple Software -// without specific prior written permission from Apple. Except as -// expressly stated in this notice, no other rights or licenses, express or -// implied, are granted by Apple herein, including but not limited to any -// patent rights that may be infringed by your derivative works or by other -// works in which the Apple Software may be incorporated. -// -// The Apple Software is provided by Apple on an "AS IS" basis. APPLE -// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION -// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS -// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND -// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. -// -// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL -// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, -// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED -// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), -// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Copyright (C) 2009 Apple Inc. All Rights Reserved. -// -//***************************************************** - -#include - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 - -#include "HID_Utilities_External.h" - -// ================================== -// private functions - -// creates a queue for a device, creates and opens device interface if required -static IOReturn HIDCreateQueue(IOHIDDeviceRef inIOHIDDeviceRef) { - IOReturn result = kIOReturnSuccess; - if ( inIOHIDDeviceRef ) { - assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); - - // do we already have a queue? - IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); - if ( tIOHIDQueueRef ) { // (yes) - assert( IOHIDQueueGetTypeID() == CFGetTypeID(tIOHIDQueueRef) ); - } else { - tIOHIDQueueRef = IOHIDQueueCreate(kCFAllocatorDefault, inIOHIDDeviceRef, kDeviceQueueSize, kIOHIDOptionsTypeNone); - if ( tIOHIDQueueRef ) { // did that work - IOHIDDevice_SetQueue(inIOHIDDeviceRef, tIOHIDQueueRef); - result = kIOReturnSuccess; - } else { - HIDReportErrorNum("Failed to create queue via create", result); - } - } - } else { - HIDReportErrorNum("HID device ref does not exist for queue creation", result); - } - - return (result); -} /* HIDCreateQueue */ - -// --------------------------------- -// returns true if queue is empty false otherwise -// error if no device, empty if no queue -static unsigned char HIDIsDeviceQueueEmpty(IOHIDDeviceRef inIOHIDDeviceRef) { - if ( inIOHIDDeviceRef ) { // need device and queue - assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); - IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); - if ( tIOHIDQueueRef ) { - IOHIDElementRef tIOHIDElementRef = HIDGetFirstDeviceElement(inIOHIDDeviceRef, kHIDElementTypeIO); - - while ( tIOHIDElementRef ) { - if ( IOHIDQueueContainsElement(tIOHIDQueueRef, tIOHIDElementRef) ) { - return (false); - } - - tIOHIDElementRef = HIDGetNextDeviceElement(tIOHIDElementRef, kHIDElementTypeIO); - } - } else { - HIDReportError("NULL device passed to HIDIsDeviceQueueEmpty."); - } - } else { - HIDReportError("NULL device passed to HIDIsDeviceQueueEmpty."); - } - - return (true); -} /* HIDIsDeviceQueueEmpty */ - -// --------------------------------- - -// disposes and releases queue, sets queue to NULL,. -// Note: will have no effect if device or queue do not exist -static IOReturn HIDDisposeReleaseQueue(IOHIDDeviceRef inIOHIDDeviceRef) { - IOReturn result = kIOReturnSuccess; - if ( inIOHIDDeviceRef ) { - IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); - if ( tIOHIDQueueRef ) { - // stop queue - IOHIDQueueStop(tIOHIDQueueRef); - - // release the queue - CFRelease(tIOHIDQueueRef); - } - } else { - HIDReportError("NULL device passed to HIDDisposeReleaseQueue."); - } - - return (result); -} /* HIDDisposeReleaseQueue */ - -// ================================== -// public functions -// ---------------------------------- - -// queues specific element, performing any device queue set up required -// queue is started and ready to return events on exit from this function -int HIDQueueElement(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef) { - IOReturn result = kIOReturnSuccess; - if ( inIOHIDDeviceRef ) { - assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); - if ( inIOHIDElementRef ) { - assert( IOHIDElementGetTypeID() == CFGetTypeID(inIOHIDElementRef) ); - IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); - if ( !tIOHIDQueueRef ) { // if no queue create queue - result = HIDCreateQueue(inIOHIDDeviceRef); - if ( kIOReturnSuccess == result ) { - tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); - } - } - if ( tIOHIDQueueRef ) { - // stop queue - IOHIDQueueStop(tIOHIDQueueRef); - // queue element - if ( !IOHIDQueueContainsElement(tIOHIDQueueRef, inIOHIDElementRef) ) { - IOHIDQueueAddElement(tIOHIDQueueRef, inIOHIDElementRef); - } - - // restart queue - IOHIDQueueStart(tIOHIDQueueRef); - } else { - HIDReportError("No queue for device passed to HIDQueueElement."); - if ( kIOReturnSuccess == result ) { - result = kIOReturnError; - } - } - } else { - HIDReportError("NULL element passed to HIDQueueElement."); - result = kIOReturnBadArgument; - } - } else { - HIDReportError("NULL device passed to HIDQueueElement."); - result = kIOReturnBadArgument; - } - - return (result); -} /* HIDQueueElement */ -// --------------------------------- - -// adds all elements to queue, performing any device queue set up required -// queue is started and ready to return events on exit from this function -int HIDQueueDevice(IOHIDDeviceRef inIOHIDDeviceRef) { - IOReturn result = kIOReturnSuccess; - // error checking - if ( !inIOHIDDeviceRef ) { - HIDReportError("Device does not exist, cannot queue device."); - return (kIOReturnBadArgument); - } - if ( !inIOHIDDeviceRef ) { // must have interface - HIDReportError("Device does not have hid device ref, cannot queue device."); - return (kIOReturnError); - } - - IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); - if ( !tIOHIDQueueRef ) { // if no queue create queue - result = HIDCreateQueue(inIOHIDDeviceRef); - if ( kIOReturnSuccess == result ) { - tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); - } - } - if ( (kIOReturnSuccess != result) || (!tIOHIDQueueRef) ) { - HIDReportErrorNum("Could not queue device due to problem creating queue.", result); - if ( kIOReturnSuccess != result ) { - return (result); - } else { - return (kIOReturnError); - } - } - - // stop queue - IOHIDQueueStop(tIOHIDQueueRef); - - // queue element - IOHIDElementRef tIOHIDElementRef = HIDGetFirstDeviceElement(inIOHIDDeviceRef, kHIDElementTypeIO); - - while ( tIOHIDElementRef ) { - if ( !IOHIDQueueContainsElement(tIOHIDQueueRef, tIOHIDElementRef) ) { - IOHIDQueueAddElement(tIOHIDQueueRef, tIOHIDElementRef); - } - - tIOHIDElementRef = HIDGetNextDeviceElement(tIOHIDElementRef, kHIDElementTypeIO); - } - - // restart queue - IOHIDQueueStart(tIOHIDQueueRef); - - return (result); -} /* HIDQueueDevice */ - -// --------------------------------- -// removes element for queue, if last element in queue will release queue and closes device interface -int HIDDequeueElement(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHIDElementRef) { - IOReturn result = kIOReturnSuccess; - if ( inIOHIDDeviceRef ) { - assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); - if ( inIOHIDElementRef ) { - assert( IOHIDElementGetTypeID() == CFGetTypeID(inIOHIDElementRef) ); - IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); - if ( tIOHIDQueueRef ) { - // stop queue - IOHIDQueueStop(tIOHIDQueueRef); - // de-queue element - if ( IOHIDQueueContainsElement(tIOHIDQueueRef, inIOHIDElementRef) ) { - IOHIDQueueRemoveElement(tIOHIDQueueRef, inIOHIDElementRef); - } - // release device queue and close interface if queue empty - if ( HIDIsDeviceQueueEmpty(inIOHIDDeviceRef) ) { - result = HIDDisposeReleaseQueue(inIOHIDDeviceRef); - if ( kIOReturnSuccess != result ) { - HIDReportErrorNum("Failed to dispose and release queue.", result); - } - } else { // not empty so restart queue - IOHIDQueueStart(tIOHIDQueueRef); - } - } else { - HIDReportError("No queue for device passed to HIDDequeueElement."); - if ( kIOReturnSuccess == result ) { - result = kIOReturnError; - } - } - } else { - HIDReportError("NULL element passed to HIDDequeueElement."); - result = kIOReturnBadArgument; - } - } else { - HIDReportError("NULL device passed to HIDDequeueElement."); - result = kIOReturnBadArgument; - } - - return (result); -} /* HIDDequeueElement */ - -// --------------------------------- -// completely removes all elements from queue and releases queue and closes device interface -// does not release device interfaces, application must call ReleaseHIDDeviceList on exit -int HIDDequeueDevice(IOHIDDeviceRef inIOHIDDeviceRef) { - IOReturn result = kIOReturnSuccess; - // error checking - if ( !inIOHIDDeviceRef ) { - HIDReportError("Device does not exist, cannot queue device."); - return (kIOReturnBadArgument); - } - if ( !inIOHIDDeviceRef ) { // must have interface - HIDReportError("Device does not have hid device ref, cannot queue device."); - return (kIOReturnError); - } - - IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); - if ( tIOHIDQueueRef ) { - // iterate through elements and if queued, remove - IOHIDElementRef tIOHIDElementRef = HIDGetFirstDeviceElement(inIOHIDDeviceRef, kHIDElementTypeIO); - - while ( tIOHIDElementRef ) { - // de-queue element - if ( IOHIDQueueContainsElement(tIOHIDQueueRef, tIOHIDElementRef) ) { - IOHIDQueueRemoveElement(tIOHIDQueueRef, tIOHIDElementRef); - } - - tIOHIDElementRef = HIDGetNextDeviceElement(tIOHIDElementRef, kHIDElementTypeIO); - } - - // ensure queue is disposed and released - result = HIDDisposeReleaseQueue(inIOHIDDeviceRef); - if ( kIOReturnSuccess != result ) { - HIDReportErrorNum("Failed to dispose and release queue.", result); - } - } else { - HIDReportError("No queue for device passed to HIDDequeueElement."); - if ( kIOReturnSuccess == result ) { - result = kIOReturnError; - } - } - - return (result); -} /* HIDDequeueDevice */ -// --------------------------------- - -// releases all device queues for quit or rebuild (must be called) -// does not release device interfaces, application must call ReleaseHIDDeviceList on exit -IOReturn HIDReleaseAllDeviceQueues(void) { - IOReturn result = kIOReturnSuccess; - IOHIDDeviceRef tIOHIDDeviceRef = HIDGetFirstDevice(); - - while ( tIOHIDDeviceRef ) { - result = HIDDequeueDevice(tIOHIDDeviceRef); - if ( kIOReturnSuccess != result ) { - HIDReportErrorNum("Could not dequeue device.", result); - } - - tIOHIDDeviceRef = HIDGetNextDevice(tIOHIDDeviceRef); - } - - return (result); -} /* HIDReleaseAllDeviceQueues */ - -// --------------------------------- -// Get the next event in the queue for a device -// elements or entire device should be queued prior to calling this with HIDQueueElement or HIDQueueDevice -// returns true if an event is avialable for the element and fills out *pHIDEvent structure, returns false otherwise -// Note: kIOReturnUnderrun returned from getNextEvent indicates an empty queue not an error condition -// Note: application should pass in a pointer to a IOHIDEventStruct cast to a void (for CFM compatibility) -unsigned char HIDGetEvent(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDValueRef *pIOHIDValueRef) { - if ( inIOHIDDeviceRef ) { - IOHIDQueueRef tIOHIDQueueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); - if ( tIOHIDQueueRef ) { - if ( pIOHIDValueRef ) { - *pIOHIDValueRef = IOHIDQueueCopyNextValueWithTimeout(tIOHIDQueueRef, 0.0); - if ( *pIOHIDValueRef ) { - return (true); - } - } - } else { - HIDReportError("Could not get HID event, hid queue reference does not exist."); - } - } else { - HIDReportError("Could not get HID event, device does not exist."); - } - - return (false); // did not get event -} /* HIDGetEvent */ - -#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 diff --git a/src/cocoa/HID_Utilities.c b/src/cocoa/HID_Utilities.c deleted file mode 100644 index 3152cfdd9..000000000 --- a/src/cocoa/HID_Utilities.c +++ /dev/null @@ -1,1068 +0,0 @@ -// File: HID_Utilities.c -// Abstract: Implementation of the HID utilities -// Version: 2.0 -// -// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple -// Inc. ("Apple") in consideration of your agreement to the following -// terms, and your use, installation, modification or redistribution of -// this Apple software constitutes acceptance of these terms. If you do -// not agree with these terms, please do not use, install, modify or -// redistribute this Apple software. -// -// In consideration of your agreement to abide by the following terms, and -// subject to these terms, Apple grants you a personal, non-exclusive -// license, under Apple's copyrights in this original Apple software (the -// "Apple Software"), to use, reproduce, modify and redistribute the Apple -// Software, with or without modifications, in source and/or binary forms; -// provided that if you redistribute the Apple Software in its entirety and -// without modifications, you must retain this notice and the following -// text and disclaimers in all such redistributions of the Apple Software. -// Neither the name, trademarks, service marks or logos of Apple Inc. may -// be used to endorse or promote products derived from the Apple Software -// without specific prior written permission from Apple. Except as -// expressly stated in this notice, no other rights or licenses, express or -// implied, are granted by Apple herein, including but not limited to any -// patent rights that may be infringed by your derivative works or by other -// works in which the Apple Software may be incorporated. -// -// The Apple Software is provided by Apple on an "AS IS" basis. APPLE -// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION -// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS -// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND -// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. -// -// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL -// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, -// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED -// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), -// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Copyright (C) 2009 Apple Inc. All Rights Reserved. -// -//*************************************************** - -#include - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 - -#pragma mark - includes & imports -//----------------------------------------------------- - -#include - -#include "HID_Utilities_External.h" - -//*************************************************** -#pragma mark - typedefs, enums, defines, etc. -//----------------------------------------------------- -#define FAKE_MISSING_NAMES 1 // set this to true while debuging to get more explicit element names; false for -// the -// generic ones - -#define kPercentMove 10 // precent of overall range a element must move to register -#define kNameKeyCFStringRef CFSTR("Name") // dictionary key - -//*************************************************** -#pragma mark - local ( static ) function prototypes -//----------------------------------------------------- - -static void CFSetApplierFunctionCopyToCFArray(const void *value, void *context); -static CFComparisonResult CFDeviceArrayComparatorFunction(const void *val1, const void *val2, void *context); -static CFMutableDictionaryRef hu_SetUpMatchingDictionary(UInt32 inUsagePage, UInt32 inUsage); - -//*************************************************** -#pragma mark - exported globals -//----------------------------------------------------- - -IOHIDManagerRef gIOHIDManagerRef = NULL; -CFMutableArrayRef gDeviceCFArrayRef = NULL; -CFIndex gDeviceIndex; -CFArrayRef gElementCFArrayRef = NULL; - -//*************************************************** -#pragma mark - local ( static ) globals -//----------------------------------------------------- - -//*************************************************** -#pragma mark - exported function implementations -//----------------------------------------------------- - -//************************************************************************* -// -// HIDBuildMultiDeviceList( inUsagePages, inUsages, inNumDeviceTypes ) -// -// Purpose: builds list of devices with elements -// -// Inputs: inUsagePages - inNumDeviceTypes sized array of matching usage pages -// inUsages - inNumDeviceTypes sized array of matching usages -// inNumDeviceTypes - number of usage pages & usages -// -// Returns: Boolean - if successful -// -Boolean HIDBuildMultiDeviceList(const UInt32 *inUsagePages, const UInt32 *inUsages, int inNumDeviceTypes) { - Boolean result = FALSE; // assume failure ( pessimist! ) - Boolean first = (!gIOHIDManagerRef); // not yet created? - if ( first ) { - // create the manager - gIOHIDManagerRef = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); - } - if ( gIOHIDManagerRef ) { - CFMutableArrayRef hidMatchingCFMutableArrayRef = NULL; - if ( inUsages && inUsagePages && inNumDeviceTypes ) { - hidMatchingCFMutableArrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - if ( hidMatchingCFMutableArrayRef ) { - int idx; - for ( idx = 0; idx < inNumDeviceTypes; idx++ ) { // for all usage and usage page types - // Set up matching dictionary. returns NULL on error. - CFMutableDictionaryRef hidMatchingCFDictRef = hu_SetUpMatchingDictionary(inUsagePages[idx], inUsages[idx]); - if ( hidMatchingCFDictRef ) { - CFArrayAppendValue(hidMatchingCFMutableArrayRef, (void *) hidMatchingCFDictRef); - CFRelease(hidMatchingCFDictRef); - } else { - fprintf(stderr, "%s: Couldnā€™t create a matching dictionary.", __PRETTY_FUNCTION__); - } - } - } else { - fprintf(stderr, "%s: Couldnā€™t create a matching array.", __PRETTY_FUNCTION__); - } - } - - // set it for IOHIDManager to use to match against - IOHIDManagerSetDeviceMatchingMultiple(gIOHIDManagerRef, hidMatchingCFMutableArrayRef); - if ( hidMatchingCFMutableArrayRef ) { - CFRelease(hidMatchingCFMutableArrayRef); - } - if ( first ) { - // open it - IOReturn tIOReturn = IOHIDManagerOpen(gIOHIDManagerRef, kIOHIDOptionsTypeNone); - if ( kIOReturnSuccess != tIOReturn ) { - fprintf(stderr, "%s: Couldnā€™t open IOHIDManager.", __PRETTY_FUNCTION__); - goto Oops; - } - } - - HIDRebuildDevices(); - result = TRUE; - } else { - fprintf(stderr, "%s: Couldnā€™t create a IOHIDManager.", __PRETTY_FUNCTION__); - } - -Oops: ; - return (result); -} // HIDBuildMultiDeviceList - -/************************************************************************* - * - * HIDBuildDeviceList( inUsagePage, inUsage ) - * - * Purpose: builds list of devices with elements - * - * Notes: same as above but this uses a single inUsagePage and usage - * allocates memory and captures devices - * list is allocated internally within HID Utilites and can be accessed via accessor functions - * structures within list are considered flat and user accessable, but not user modifiable - * can be called again to rebuild list to account for new devices - * ( will do the right thing in case of disposing existing list ) - * - * Inputs: inUsagePage - usage page - * inUsage - usages - * - * Returns: Boolean - if successful - */ - -Boolean HIDBuildDeviceList(UInt32 inUsagePage, UInt32 inUsage) { - return ( HIDBuildMultiDeviceList(&inUsagePage, &inUsage, 1) ); // call HIDBuildMultiDeviceList with a single usage -} - -/************************************************************************* - * - * HIDUpdateDeviceList( inUsagePages, inUsages, inNumDeviceTypes ) - * - * Purpose: updates the current device list for any new/removed devices - * - * Notes: if this is called before HIDBuildDeviceList then it functions like HIDBuildMultiDeviceList - * inUsagePage & inUsage are each a inNumDeviceTypes sized array of matching usage and usage pages - * - * Inputs: inUsagePages - inNumDeviceTypes sized array of matching usage pages - * inUsages - inNumDeviceTypes sized array of matching usages - * inNumDeviceTypes - number of usage pages & usages - * - * Returns: Boolean - TRUE if the device config changed - */ - -Boolean HIDUpdateDeviceList(const UInt32 *inUsagePages, const UInt32 *inUsages, int inNumDeviceTypes) { - return ( HIDBuildMultiDeviceList(inUsagePages, inUsages, inNumDeviceTypes) ); -} - -/************************************************************************* - * - * HIDReleaseDeviceList( void ) - * - * Purpose: release list built by above functions - * - * Notes: MUST be called prior to application exit to properly release devices - * if not called( or app crashes ) devices can be recovered by pluging into different location in USB chain - * - * Inputs: none - * - * Returns: none - */ - -void HIDReleaseDeviceList(void) { - if ( gDeviceCFArrayRef ) { - CFRelease(gDeviceCFArrayRef); - gDeviceCFArrayRef = NULL; - } -} // HIDReleaseDeviceList - -/************************************************************************* - * - * HIDHaveDeviceList( void ) - * - * Purpose: does a device list exist? - * - * Inputs: none - * - * Returns: Boolean - TRUE if we have previously built a device list - */ - -Boolean HIDHaveDeviceList(void) { - return (NULL != gDeviceCFArrayRef); -} - -//************************************************************************* -// -// HIDRebuildDevices( ) -// -// Purpose: rebuilds the (internal) list of IOHIDDevices -// -// Inputs: none -// -// Returns: none -// - -void HIDRebuildDevices(void) { - // get the set of devices from the IOHID manager - CFSetRef devCFSetRef = IOHIDManagerCopyDevices(gIOHIDManagerRef); - if ( devCFSetRef ) { - // if the existing array isn't empty... - if ( gDeviceCFArrayRef ) { - // release it - CFRelease(gDeviceCFArrayRef); - } - - // create an empty array - gDeviceCFArrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - // now copy the set to the array - CFSetApplyFunction(devCFSetRef, CFSetApplierFunctionCopyToCFArray, (void *) gDeviceCFArrayRef); - // now sort the array by location ID's - CFIndex cnt = CFArrayGetCount(gDeviceCFArrayRef); - CFArraySortValues(gDeviceCFArrayRef, CFRangeMake(0, cnt), CFDeviceArrayComparatorFunction, NULL); - - // and release the set we copied from the IOHID manager - CFRelease(devCFSetRef); - } -} // HIDRebuildDevices - -// --------------------------------- - -// how many HID devices have been found -// returns 0 if no device list exist - -UInt32 HIDCountDevices(void) { - return ( CFArrayGetCount(gDeviceCFArrayRef) ); -} - -// --------------------------------- - -// how many elements does a specific device have -// returns 0 if device is invlaid or NULL - -UInt32 HIDCountDeviceElements(IOHIDDeviceRef inIOHIDDeviceRef, HIDElementTypeMask typeMask) { - int count = 0; - if ( inIOHIDDeviceRef ) { - assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); - - gElementCFArrayRef = IOHIDDeviceCopyMatchingElements(inIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone); - if ( gElementCFArrayRef ) { - CFIndex idx, cnt = CFArrayGetCount(gElementCFArrayRef); - for ( idx = 0; idx < cnt; idx++ ) { - IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(gElementCFArrayRef, idx); - if ( !tIOHIDElementRef ) { - continue; - } - - IOHIDElementType type = IOHIDElementGetType(tIOHIDElementRef); - - switch ( type ) { - case kIOHIDElementTypeInput_Misc: - case kIOHIDElementTypeInput_Button: - case kIOHIDElementTypeInput_Axis: - case kIOHIDElementTypeInput_ScanCodes: - { - if ( typeMask & kHIDElementTypeInput ) { - count++; - } - - break; - } - - case kIOHIDElementTypeOutput: - { - if ( typeMask & kHIDElementTypeOutput ) { - count++; - } - - break; - } - - case kIOHIDElementTypeFeature: - { - if ( typeMask & kHIDElementTypeFeature ) { - count++; - } - - break; - } - - case kIOHIDElementTypeCollection: - { - if ( typeMask & kHIDElementTypeCollection ) { - count++; - } - - break; - } - default: { - break; - } - } // switch ( type ) - - } // next idx - - CFRelease(gElementCFArrayRef); - gElementCFArrayRef = NULL; - } // if ( gElementCFArrayRef ) - - } // if ( inIOHIDDeviceRef ) - - return (count); -} /* HIDCountDeviceElements */ - -// --------------------------------- - -// get the first device in the device list -// returns NULL if no list exists or it's empty - -IOHIDDeviceRef HIDGetFirstDevice(void) { - IOHIDDeviceRef result = NULL; - - gDeviceIndex = 0; - if ( gDeviceCFArrayRef ) { - CFIndex count = CFArrayGetCount(gDeviceCFArrayRef); - if ( (gDeviceIndex >= 0) && (gDeviceIndex < count) ) { - result = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, gDeviceIndex); - } - } - - return (result); -} /* HIDGetFirstDevice */ - -// --------------------------------- - -// get next device in list given current device as parameter -// returns NULL if end of list - -IOHIDDeviceRef HIDGetNextDevice(IOHIDDeviceRef inIOHIDDeviceRef) { - IOHIDDeviceRef result = NULL; - if ( gDeviceCFArrayRef && inIOHIDDeviceRef ) { - CFIndex idx, cnt = CFArrayGetCount(gDeviceCFArrayRef); - // quick case to verify the current device index is valid for current device - if ( (gDeviceIndex >= 0) && (gDeviceIndex < cnt) ) { - result = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, gDeviceIndex); - if ( result && (result == inIOHIDDeviceRef) ) { - result = NULL; - gDeviceIndex++; // bump index - } else { - // previous index was invalid; - gDeviceIndex = -1; - // search for current device's index - for ( idx = 0; idx < cnt; idx++ ) { - result = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, idx); - if ( (result) && (result == inIOHIDDeviceRef) ) { - gDeviceIndex = idx + 1; // found valid index; bump to next one - break; - } - } - - result = NULL; - } - if ( (gDeviceIndex >= 0) && (gDeviceIndex < cnt) ) { - result = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDeviceCFArrayRef, gDeviceIndex); - } - } // if valid index - - } // if ( gDeviceCFArrayRef && inIOHIDDeviceRef ) - - return (result); -} /* HIDGetNextDevice */ - -// --------------------------------- - -// get the first element of device passed in as parameter -// returns NULL if no list exists or device does not exists or is NULL -IOHIDElementRef HIDGetFirstDeviceElement(IOHIDDeviceRef inIOHIDDeviceRef, HIDElementTypeMask typeMask) { - IOHIDElementRef result = NULL; - if ( inIOHIDDeviceRef ) { - assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); - - gElementCFArrayRef = IOHIDDeviceCopyMatchingElements(inIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone); - if ( gElementCFArrayRef ) { - CFIndex idx, cnt = CFArrayGetCount(gElementCFArrayRef); - for ( idx = 0; idx < cnt; idx++ ) { - IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(gElementCFArrayRef, idx); - if ( !tIOHIDElementRef ) { - continue; - } - - IOHIDElementType type = IOHIDElementGetType(tIOHIDElementRef); - - switch ( type ) { - case kIOHIDElementTypeInput_Misc: - case kIOHIDElementTypeInput_Button: - case kIOHIDElementTypeInput_Axis: - case kIOHIDElementTypeInput_ScanCodes: - { - if ( typeMask & kHIDElementTypeInput ) { - result = tIOHIDElementRef; - } - - break; - } - - case kIOHIDElementTypeOutput: - { - if ( typeMask & kHIDElementTypeOutput ) { - result = tIOHIDElementRef; - } - - break; - } - - case kIOHIDElementTypeFeature: - { - if ( typeMask & kHIDElementTypeFeature ) { - result = tIOHIDElementRef; - } - - break; - } - - case kIOHIDElementTypeCollection: - { - if ( typeMask & kHIDElementTypeCollection ) { - result = tIOHIDElementRef; - } - - break; - } - default: { - break; - } - } // switch ( type ) - if ( result ) { - break; // DONE! - } - } // next idx - - CFRelease(gElementCFArrayRef); - gElementCFArrayRef = NULL; - } // if ( gElementCFArrayRef ) - - } // if ( inIOHIDDeviceRef ) - - return (result); -} /* HIDGetFirstDeviceElement */ - -// --------------------------------- - -// get next element of given device in list given current element as parameter -// will walk down each collection then to next element or collection (depthwise traverse) -// returns NULL if end of list -// uses mask of HIDElementTypeMask to restrict element found -// use kHIDElementTypeIO to get previous HIDGetNextDeviceElement functionality -IOHIDElementRef HIDGetNextDeviceElement(IOHIDElementRef inIOHIDElementRef, HIDElementTypeMask typeMask) { - IOHIDElementRef result = NULL; - if ( inIOHIDElementRef ) { - assert( IOHIDElementGetTypeID() == CFGetTypeID(inIOHIDElementRef) ); - - IOHIDDeviceRef tIOHIDDeviceRef = IOHIDElementGetDevice(inIOHIDElementRef); - if ( tIOHIDDeviceRef ) { - Boolean found = FALSE; - - gElementCFArrayRef = IOHIDDeviceCopyMatchingElements(tIOHIDDeviceRef, NULL, kIOHIDOptionsTypeNone); - if ( gElementCFArrayRef ) { - CFIndex idx, cnt = CFArrayGetCount(gElementCFArrayRef); - for ( idx = 0; idx < cnt; idx++ ) { - IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(gElementCFArrayRef, idx); - if ( !tIOHIDElementRef ) { - continue; - } - if ( !found ) { - if ( inIOHIDElementRef == tIOHIDElementRef ) { - found = TRUE; - } - - continue; // next element - } else { - // we've found the current element; now find the next one of the right type - IOHIDElementType type = IOHIDElementGetType(tIOHIDElementRef); - - switch ( type ) { - case kIOHIDElementTypeInput_Misc: - case kIOHIDElementTypeInput_Button: - case kIOHIDElementTypeInput_Axis: - case kIOHIDElementTypeInput_ScanCodes: - { - if ( typeMask & kHIDElementTypeInput ) { - result = tIOHIDElementRef; - } - - break; - } - - case kIOHIDElementTypeOutput: - { - if ( typeMask & kHIDElementTypeOutput ) { - result = tIOHIDElementRef; - } - - break; - } - - case kIOHIDElementTypeFeature: - { - if ( typeMask & kHIDElementTypeFeature ) { - result = tIOHIDElementRef; - } - - break; - } - - case kIOHIDElementTypeCollection: - { - if ( typeMask & kHIDElementTypeCollection ) { - result = tIOHIDElementRef; - } - - break; - } - default: { - break; - } - } // switch ( type ) - if ( result ) { - break; // DONE! - } - } // if ( !found ) - - } // next idx - - CFRelease(gElementCFArrayRef); - gElementCFArrayRef = NULL; - } // if ( gElementCFArrayRef ) - - } // if ( inIOHIDDeviceRef ) - - } // if ( inIOHIDElementRef ) - - return (result); -} /* HIDGetNextDeviceElement */ - -#if 0 -// --------------------------------- -// get previous element of given device in list given current element as parameter -// this wlaks directly up the tree to the top element and does not search at each level -// returns NULL if beginning of list -// uses mask of HIDElementTypeMask to restrict element found -// use kHIDElementTypeIO to get non-collection elements -IOHIDElementRef HIDGetPreviousDeviceElement(IOHIDElementRef pElement, HIDElementTypeMask typeMask) { - IOHIDElementRef pPreviousElement = pElement->pPrevious; - - // walk back up tree to element prior - while ( pPreviousElement && !HIDMatchElementTypeMask(pPreviousElement->type, typeMask) ) { - pElement = pPreviousElement; // look at previous element - pPreviousElement = pElement->pPrevious; - } - - return (pPreviousElement); // return this element -} /* HIDGetPreviousDeviceElement */ - -#endif - -// utility routine to dump device info -void HIDDumpDeviceInfo(IOHIDDeviceRef inIOHIDDeviceRef) { - char cstring[256]; - - printf("Device: %p = { ", inIOHIDDeviceRef); - - char manufacturer[256] = ""; // name of manufacturer - CFStringRef tCFStringRef = IOHIDDevice_GetManufacturer(inIOHIDDeviceRef); - if ( tCFStringRef ) { - verify( CFStringGetCString(tCFStringRef, manufacturer, sizeof(manufacturer), kCFStringEncodingUTF8) ); - } - - char product[256] = ""; // name of product - tCFStringRef = IOHIDDevice_GetProduct(inIOHIDDeviceRef); - if ( tCFStringRef ) { - verify( CFStringGetCString(tCFStringRef, product, sizeof(product), kCFStringEncodingUTF8) ); - } - - printf("%s - %s, ", manufacturer, product); - - long vendorID = IOHIDDevice_GetVendorID(inIOHIDDeviceRef); - if ( vendorID ) { -#if 1 - printf(" vendorID: 0x%04lX, ", vendorID); -#else - if ( HIDGetVendorNameFromVendorID(vendorID, cstring) ) { - printf(" vendorID: 0x%04lX (\"%s\"), ", vendorID, cstring); - } else { - printf(" vendorID: 0x%04lX, ", vendorID); - } - -#endif - } - - long productID = IOHIDDevice_GetProductID(inIOHIDDeviceRef); - if ( productID ) { -#if 1 - printf(" productID: 0x%04lX, ", productID); -#else - if ( HIDGetProductNameFromVendorProductID(vendorID, productID, cstring) ) { - printf(" productID: 0x%04lX (\"%s\"), ", productID, cstring); - } else { - printf(" productID: 0x%04lX, ", productID); - } - -#endif - } - - uint32_t usagePage = IOHIDDevice_GetUsagePage(inIOHIDDeviceRef); - uint32_t usage = IOHIDDevice_GetUsage(inIOHIDDeviceRef); - if ( !usagePage || !usage ) { - usagePage = IOHIDDevice_GetPrimaryUsagePage(inIOHIDDeviceRef); - usage = IOHIDDevice_GetPrimaryUsage(inIOHIDDeviceRef); - } - - printf("usage: 0x%04lX:0x%04lX, ", (long unsigned int) usagePage, (long unsigned int) usage); - -#if 1 - tCFStringRef = HIDCopyUsageName(usagePage, usage); - if ( tCFStringRef ) { - verify( CFStringGetCString(tCFStringRef, cstring, sizeof(cstring), kCFStringEncodingUTF8) ); - printf("\"%s\", ", cstring); - CFRelease(tCFStringRef); - } - -#endif - -#if 1 - tCFStringRef = IOHIDDevice_GetTransport(inIOHIDDeviceRef); - if ( tCFStringRef ) { - verify( CFStringGetCString(tCFStringRef, cstring, sizeof(cstring), kCFStringEncodingUTF8) ); - printf("Transport: \"%s\", ", cstring); - } - - long vendorIDSource = IOHIDDevice_GetVendorIDSource(inIOHIDDeviceRef); - if ( vendorIDSource ) { - printf("VendorIDSource: %ld, ", vendorIDSource); - } - - long version = IOHIDDevice_GetVersionNumber(inIOHIDDeviceRef); - if ( version ) { - printf("version: %ld, ", version); - } - - tCFStringRef = IOHIDDevice_GetSerialNumber(inIOHIDDeviceRef); - if ( tCFStringRef ) { - verify( CFStringGetCString(tCFStringRef, cstring, sizeof(cstring), kCFStringEncodingUTF8) ); - printf("SerialNumber: \"%s\", ", cstring); - } - - long country = IOHIDDevice_GetCountryCode(inIOHIDDeviceRef); - if ( country ) { - printf("CountryCode: %ld, ", country); - } - - long locationID = IOHIDDevice_GetLocationID(inIOHIDDeviceRef); - if ( locationID ) { - printf("locationID: 0x%08lX, ", locationID); - } - -#if 0 - CFArrayRef pairs = IOHIDDevice_GetUsagePairs(inIOHIDDeviceRef); - if ( pairs ) { - CFIndex idx, cnt = CFArrayGetCount(pairs); - for ( idx = 0; idx < cnt; idx++ ) { - const void *pair = CFArrayGetValueAtIndex(pairs, idx); - CFShow(pair); - } - } - -#endif - long maxInputReportSize = IOHIDDevice_GetMaxInputReportSize(inIOHIDDeviceRef); - if ( maxInputReportSize ) { - printf("MaxInputReportSize: %ld, ", maxInputReportSize); - } - - long maxOutputReportSize = IOHIDDevice_GetMaxOutputReportSize(inIOHIDDeviceRef); - if ( maxOutputReportSize ) { - printf("MaxOutputReportSize: %ld, ", maxOutputReportSize); - } - - long maxFeatureReportSize = IOHIDDevice_GetMaxFeatureReportSize(inIOHIDDeviceRef); - if ( maxFeatureReportSize ) { - printf("MaxFeatureReportSize: %ld, ", maxOutputReportSize); - } - - long reportInterval = IOHIDDevice_GetReportInterval(inIOHIDDeviceRef); - if ( reportInterval ) { - printf("ReportInterval: %ld, ", reportInterval); - } - - IOHIDQueueRef queueRef = IOHIDDevice_GetQueue(inIOHIDDeviceRef); - if ( queueRef ) { - printf("queue: %p, ", queueRef); - } - - IOHIDTransactionRef transactionRef = IOHIDDevice_GetTransaction(inIOHIDDeviceRef); - if ( transactionRef ) { - printf("transaction: %p, ", transactionRef); - } - -#endif - printf("}\n"); - fflush(stdout); -} // HIDDumpDeviceInfo - -// utility routine to dump element info -void HIDDumpElementInfo(IOHIDElementRef inIOHIDElementRef) { - if ( inIOHIDElementRef ) { - printf(" Element: %p = { ", inIOHIDElementRef); -#if 0 - IOHIDDeviceRef tIOHIDDeviceRef = IOHIDElementGetDevice(inIOHIDElementRef); - printf("Device: %p, ", tIOHIDDeviceRef); -#endif - IOHIDElementRef parentIOHIDElementRef = IOHIDElementGetParent(inIOHIDElementRef); - printf("parent: %p, ", parentIOHIDElementRef); -#if 0 - CFArrayRef childrenCFArrayRef = IOHIDElementGetChildren(inIOHIDElementRef); - printf("children: %p: { ", childrenCFArrayRef); - fflush(stdout); - CFShow(childrenCFArrayRef); - fflush(stdout); - printf(" }, "); -#endif - IOHIDElementCookie tIOHIDElementCookie = IOHIDElementGetCookie(inIOHIDElementRef); - printf("cookie: %p, ", tIOHIDElementCookie); - - IOHIDElementType tIOHIDElementType = IOHIDElementGetType(inIOHIDElementRef); - - switch ( tIOHIDElementType ) { - case kIOHIDElementTypeInput_Misc: - { - printf("type: Misc, "); - break; - } - - case kIOHIDElementTypeInput_Button: - { - printf("type: Button, "); - break; - } - - case kIOHIDElementTypeInput_Axis: - { - printf("type: Axis, "); - break; - } - - case kIOHIDElementTypeInput_ScanCodes: - { - printf("type: ScanCodes, "); - break; - } - - case kIOHIDElementTypeOutput: - { - printf("type: Output, "); - break; - } - - case kIOHIDElementTypeFeature: - { - printf("type: Feature, "); - break; - } - - case kIOHIDElementTypeCollection: - { - IOHIDElementCollectionType tIOHIDElementCollectionType = IOHIDElementGetCollectionType(inIOHIDElementRef); - - switch ( tIOHIDElementCollectionType ) { - case kIOHIDElementCollectionTypePhysical: - { - printf("type: Physical Collection, "); - break; - } - - case kIOHIDElementCollectionTypeApplication: - { - printf("type: Application Collection, "); - break; - } - - case kIOHIDElementCollectionTypeLogical: - { - printf("type: Logical Collection, "); - break; - } - - case kIOHIDElementCollectionTypeReport: - { - printf("type: Report Collection, "); - break; - } - - case kIOHIDElementCollectionTypeNamedArray: - { - printf("type: Named Array Collection, "); - break; - } - - case kIOHIDElementCollectionTypeUsageSwitch: - { - printf("type: Usage Switch Collection, "); - break; - } - - case kIOHIDElementCollectionTypeUsageModifier: - { - printf("type: Usage Modifier Collection, "); - break; - } - - default: - { - printf("type: %p Collection, ", (void *) tIOHIDElementCollectionType); - break; - } - } // switch - - break; - } - - default: - { - printf("type: %p, ", (void *) tIOHIDElementType); - break; - } - } /* switch */ - - uint32_t usagePage = IOHIDElementGetUsagePage(inIOHIDElementRef); - uint32_t usage = IOHIDElementGetUsage(inIOHIDElementRef); - printf("usage: 0x%04lX:0x%04lX, ", (long unsigned int) usagePage, (long unsigned int) usage); -#if 1 - CFStringRef tCFStringRef = HIDCopyUsageName(usagePage, usage); - if ( tCFStringRef ) { - char usageString[256] = ""; - verify( CFStringGetCString(tCFStringRef, usageString, sizeof(usageString), kCFStringEncodingUTF8) ); - printf("\"%s\", ", usageString); - CFRelease(tCFStringRef); - } - -#endif - CFStringRef nameCFStringRef = IOHIDElementGetName(inIOHIDElementRef); - char buffer[256]; - if ( nameCFStringRef && CFStringGetCString(nameCFStringRef, buffer, sizeof(buffer), kCFStringEncodingUTF8) ) { - printf("name: %s, ", buffer); - } - - uint32_t reportID = IOHIDElementGetReportID(inIOHIDElementRef); - uint32_t reportSize = IOHIDElementGetReportSize(inIOHIDElementRef); - uint32_t reportCount = IOHIDElementGetReportCount(inIOHIDElementRef); - printf("report: { ID: %lu, Size: %lu, Count: %lu }, ", - (long unsigned int) reportID, (long unsigned int) reportSize, (long unsigned int) reportCount); - - uint32_t unit = IOHIDElementGetUnit(inIOHIDElementRef); - uint32_t unitExp = IOHIDElementGetUnitExponent(inIOHIDElementRef); - if ( unit || unitExp ) { - printf("unit: %lu * 10^%lu, ", (long unsigned int) unit, (long unsigned int) unitExp); - } - - CFIndex logicalMin = IOHIDElementGetLogicalMin(inIOHIDElementRef); - CFIndex logicalMax = IOHIDElementGetLogicalMax(inIOHIDElementRef); - if ( logicalMin != logicalMax ) { - printf("logical: {min: %ld, max: %ld}, ", logicalMin, logicalMax); - } - - CFIndex physicalMin = IOHIDElementGetPhysicalMin(inIOHIDElementRef); - CFIndex physicalMax = IOHIDElementGetPhysicalMax(inIOHIDElementRef); - if ( physicalMin != physicalMax ) { - printf("physical: {min: %ld, max: %ld}, ", physicalMin, physicalMax); - } - - Boolean isVirtual = IOHIDElementIsVirtual(inIOHIDElementRef); - if ( isVirtual ) { - printf("isVirtual, "); - } - - Boolean isRelative = IOHIDElementIsRelative(inIOHIDElementRef); - if ( isRelative ) { - printf("isRelative, "); - } - - Boolean isWrapping = IOHIDElementIsWrapping(inIOHIDElementRef); - if ( isWrapping ) { - printf("isWrapping, "); - } - - Boolean isArray = IOHIDElementIsArray(inIOHIDElementRef); - if ( isArray ) { - printf("isArray, "); - } - - Boolean isNonLinear = IOHIDElementIsNonLinear(inIOHIDElementRef); - if ( isNonLinear ) { - printf("isNonLinear, "); - } - - Boolean hasPreferredState = IOHIDElementHasPreferredState(inIOHIDElementRef); - if ( hasPreferredState ) { - printf("hasPreferredState, "); - } - - Boolean hasNullState = IOHIDElementHasNullState(inIOHIDElementRef); - if ( hasNullState ) { - printf("hasNullState, "); - } - - printf(" }\n"); - } -} // HIDDumpElementInfo - -void HIDDumpElementCalibrationInfo(IOHIDElementRef inIOHIDElementRef) { - printf(" Element: %p = { ", inIOHIDElementRef); - - CFIndex calMin = IOHIDElement_GetCalibrationMin(inIOHIDElementRef); - CFIndex calMax = IOHIDElement_GetCalibrationMax(inIOHIDElementRef); - printf("cal: {min: %ld, max: %ld}, ", calMin, calMax); - - CFIndex satMin = IOHIDElement_GetCalibrationSaturationMin(inIOHIDElementRef); - CFIndex satMax = IOHIDElement_GetCalibrationSaturationMax(inIOHIDElementRef); - printf("sat: {min: %ld, max: %ld}, ", satMin, satMax); - - CFIndex deadMin = IOHIDElement_GetCalibrationDeadZoneMin(inIOHIDElementRef); - CFIndex deadMax = IOHIDElement_GetCalibrationDeadZoneMax(inIOHIDElementRef); - printf("dead: {min: %ld, max: %ld}, ", deadMin, deadMax); - - double_t granularity = IOHIDElement_GetCalibrationGranularity(inIOHIDElementRef); - printf("granularity: %6.2f }\n", granularity); -} // HIDDumpElementCalibrationInfo - -//*************************************************** -#pragma mark - local ( static ) function implementations -//----------------------------------------------------- - -//************************************************************************* -// -// CFSetApplierFunctionCopyToCFArray( value, context ) -// -// Purpose: CFSetApplierFunction to copy the CFSet to a CFArray -// -// Notes: called one time for each item in the CFSet -// -// Inputs: value - the current element of the CFSet -// context - the CFMutableArrayRef we're adding the CFSet elements to -// -// Returns: nothing -// -static void CFSetApplierFunctionCopyToCFArray(const void *value, void *context) { - // printf( "%s: 0x%08lX\n", __PRETTY_FUNCTION__, (long unsigned int) value ); - CFArrayAppendValue( (CFMutableArrayRef) context, value ); -} // CFSetApplierFunctionCopyToCFArray - -// --------------------------------- -// used to sort the CFDevice array after copying it from the (unordered) (CF)set. -// we compare based on the location ID's since they're consistant (across boots & launches). -// -static CFComparisonResult CFDeviceArrayComparatorFunction(const void *val1, const void *val2, void *context) { -#pragma unused( context ) - CFComparisonResult result = kCFCompareEqualTo; - - long loc1 = IOHIDDevice_GetLocationID( (IOHIDDeviceRef) val1 ); - long loc2 = IOHIDDevice_GetLocationID( (IOHIDDeviceRef) val2 ); - if ( loc1 < loc2 ) { - result = kCFCompareLessThan; - } else if ( loc1 > loc2 ) { - result = kCFCompareGreaterThan; - } - - return (result); -} // CFDeviceArrayComparatorFunction - -//************************************************************************* -// -// hu_SetUpMatchingDictionary( inUsagePage, inUsage ) -// -// Purpose: builds a matching dictionary based on usage page and usage -// -// Notes: Only called by HIDBuildMultiDeviceList -// -// Inputs: inUsagePage - usage page -// inUsage - usages -// -// Returns: CFMutableDictionaryRef - the matching dictionary -// - -static CFMutableDictionaryRef hu_SetUpMatchingDictionary(UInt32 inUsagePage, UInt32 inUsage) { - // create a dictionary to add usage page/usages to - CFMutableDictionaryRef refHIDMatchDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if ( refHIDMatchDictionary ) { - if ( inUsagePage ) { - // Add key for device type to refine the matching dictionary. - CFNumberRef pageCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &inUsagePage); - if ( pageCFNumberRef ) { - CFDictionarySetValue(refHIDMatchDictionary, - CFSTR(kIOHIDPrimaryUsagePageKey), pageCFNumberRef); - CFRelease(pageCFNumberRef); - // note: the usage is only valid if the usage page is also defined - if ( inUsage ) { - CFNumberRef usageCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &inUsage); - if ( usageCFNumberRef ) { - CFDictionarySetValue(refHIDMatchDictionary, - CFSTR(kIOHIDPrimaryUsageKey), usageCFNumberRef); - CFRelease(usageCFNumberRef); - } else { - fprintf(stderr, "%s: CFNumberCreate( usage ) failed.", __PRETTY_FUNCTION__); - } - } - } else { - fprintf(stderr, "%s: CFNumberCreate( usage page ) failed.", __PRETTY_FUNCTION__); - } - } - } else { - fprintf(stderr, "%s: CFDictionaryCreateMutable failed.", __PRETTY_FUNCTION__); - } - - return (refHIDMatchDictionary); -} // hu_SetUpMatchingDictionary - -#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 diff --git a/src/cocoa/HID_Utilities_External.h b/src/cocoa/HID_Utilities_External.h deleted file mode 100644 index bd498bc51..000000000 --- a/src/cocoa/HID_Utilities_External.h +++ /dev/null @@ -1,417 +0,0 @@ -// File: HID_Utilities_External.h -// Abstract: External interface for HID Utilities, can be used with either library or source. -// Version: 2.0 -// -// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple -// Inc. ("Apple") in consideration of your agreement to the following -// terms, and your use, installation, modification or redistribution of -// this Apple software constitutes acceptance of these terms. If you do -// not agree with these terms, please do not use, install, modify or -// redistribute this Apple software. -// -// In consideration of your agreement to abide by the following terms, and -// subject to these terms, Apple grants you a personal, non-exclusive -// license, under Apple's copyrights in this original Apple software (the -// "Apple Software"), to use, reproduce, modify and redistribute the Apple -// Software, with or without modifications, in source and/or binary forms; -// provided that if you redistribute the Apple Software in its entirety and -// without modifications, you must retain this notice and the following -// text and disclaimers in all such redistributions of the Apple Software. -// Neither the name, trademarks, service marks or logos of Apple Inc. may -// be used to endorse or promote products derived from the Apple Software -// without specific prior written permission from Apple. Except as -// expressly stated in this notice, no other rights or licenses, express or -// implied, are granted by Apple herein, including but not limited to any -// patent rights that may be infringed by your derivative works or by other -// works in which the Apple Software may be incorporated. -// -// The Apple Software is provided by Apple on an "AS IS" basis. APPLE -// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION -// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS -// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND -// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. -// -// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL -// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, -// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED -// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), -// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Copyright (C) 2009 Apple Inc. All Rights Reserved. -// -//***************************************************** -#ifndef _HID_Utilities_External_h_ -#define _HID_Utilities_External_h_ - -// ================================== - -#ifdef __cplusplus -extern "C" { -#endif - -// ================================== - -//includes - -#include -#include "IOHIDLib_.h" - -// ================================== - -#ifndef _IOKIT_HID_IOHIDKEYS_H_ -/*! - @typedef IOHIDElementCookie - @abstract Abstract data type used as a unique identifier for an element. - */ -#ifdef __LP64__ -typedef uint32_t IOHIDElementCookie; -#else -typedef void *IOHIDElementCookie; -#endif -#endif - -// Device and Element Interfaces - -enum HIDElementTypeMask { - kHIDElementTypeInput = 1 << 1, - kHIDElementTypeOutput = 1 << 2, - kHIDElementTypeFeature = 1 << 3, - kHIDElementTypeCollection = 1 << 4, - kHIDElementTypeIO = kHIDElementTypeInput | kHIDElementTypeOutput | kHIDElementTypeFeature, - kHIDElementTypeAll = kHIDElementTypeIO | kHIDElementTypeCollection -}; -typedef enum HIDElementTypeMask HIDElementTypeMask; - -// ================================== - -//***************************************************** -#pragma mark - exported globals -//----------------------------------------------------- - -extern IOHIDManagerRef gIOHIDManagerRef; -extern CFMutableArrayRef gDeviceCFArrayRef; -extern CFArrayRef gElementCFArrayRef; - -//************************************************************************* -// -// HIDBuildMultiDeviceList( inUsagePages, inUsages, inNumDeviceTypes ) -// -// Purpose: builds list of devices with elements (allocates memory and captures devices) in which -// the devices could be of different types/usages list is allocated internally within HID -// Utilites and can be accessed via accessor functions structures within list are considered -// flat and user accessable, but not user modifiable can be called again to rebuild list to -// account for new devices (will do the right thing in case of disposing existing list) -// usagePage, usage are each a numDeviceTypes sized array of matching usage and usage pages -// returns true if succesful -// -// Inputs: inUsagePages - inNumDeviceTypes sized array of matching usage pages -// inUsages - inNumDeviceTypes sized array of matching usages -// inNumDeviceTypes - number of usage pages & usages -// -// Returns: Boolean - if successful -// -extern Boolean HIDBuildMultiDeviceList(const UInt32 *inUsagePages, const UInt32 *inUsages, int inNumDeviceTypes); - -// same as above but this uses a single usagePage and usage -extern Boolean HIDBuildDeviceList(UInt32 usagePage, UInt32 usage); - -// updates the current device list for any new/removed devices -// if this is called before HIDBuildDeviceList the it functions like HIDBuildMultiDeviceList -// usagePage, usage are each a numDeviceTypes sized array of matching usage and usage pages -// returns true if successful which means if any device were added or removed (the device config changed) -extern Boolean HIDUpdateDeviceList(const UInt32 *inUsagePages, const UInt32 *inUsages, int inNumDeviceTypes); - -// release list built by above function -// MUST be called prior to application exit to properly release devices -// if not called (or app crashes) devices can be recovered by pluging into different location in USB chain -extern void HIDReleaseDeviceList(void); - -//************************************************************************* -// -// HIDRebuildDevices( ) -// -// Purpose: rebuilds the (internal) list of devices -// -// Inputs: none -// -// Returns: none -// - -extern void HIDRebuildDevices(void); - -// does a device list exist -extern unsigned char HIDHaveDeviceList(void); - -// how many HID devices have been found -// returns 0 if no device list exist -extern UInt32 HIDCountDevices(void); - -// how many elements does a specific device have -// returns 0 if device is invalid or NULL -// uses mask of HIDElementTypeMask to restrict element found -// use kHIDElementTypeIO to get non-collection elements -extern UInt32 HIDCountDeviceElements(IOHIDDeviceRef inIOHIDDeviceRef, HIDElementTypeMask typeMask); - -// get the first device in the device list -// returns NULL if no list exists -extern IOHIDDeviceRef HIDGetFirstDevice(void); - -// get next device in list given current device as parameter -// returns NULL if end of list -extern IOHIDDeviceRef HIDGetNextDevice(IOHIDDeviceRef inIOHIDDeviceRef); - -// get the first element of device passed in as parameter -// returns NULL if no list exists or device does not exists or is NULL -// uses mask of HIDElementTypeMask to restrict element found -// use kHIDElementTypeIO to get previous HIDGetFirstDeviceElement functionality -extern IOHIDElementRef HIDGetFirstDeviceElement(IOHIDDeviceRef inIOHIDDeviceRef, HIDElementTypeMask typeMask); - -// get next element of given device in list given current element as parameter -// will walk down each collection then to next element or collection (depthwise traverse) -// returns NULL if end of list -// uses mask of HIDElementTypeMask to restrict element found -// use kHIDElementTypeIO to get previous HIDGetNextDeviceElement functionality -extern IOHIDElementRef HIDGetNextDeviceElement(IOHIDElementRef inIOHidElementRef, HIDElementTypeMask typeMask); - -// get previous element of given device in list given current element as parameter -// this walks directly up the tree to the top element and does not search at each level -// returns NULL if beginning of list -// uses mask of HIDElementTypeMask to restrict element found -// use kHIDElementTypeIO to get non-collection elements -extern IOHIDElementRef HIDGetPreviousDeviceElement(IOHIDElementRef inIOHidElementRef, HIDElementTypeMask typeMask); - -// returns C string type name given a type enumeration passed in as parameter( see IOHIDKeys.h ) -// returns empty string for invalid types -extern void HIDGetTypeName(IOHIDElementType inIOHIDElementType, char *outCStrName); - -//************************************************************************* -// -// HIDCopyUsageName( inUsagePage, inUsage ) -// -// Purpose: return a CFStringRef string for a given usage page & usage( see IOUSBHIDParser.h ) -// -// Notes: returns usage page and usage values in CFString form for unknown values -// -// Inputs: inUsagePage - the usage page -// inUsage - the usage -// -// Returns: CFStringRef - the resultant string -// - -extern CFStringRef HIDCopyUsageName(long inUsagePage, long inUsage); - -// ================================== - -// Element Event Queue and Value Interfaces - -enum { - kDefaultUserMin = 0, // default user min and max used for scaling - kDefaultUserMax = 255 -}; - -enum { - kDeviceQueueSize = 50 // this is wired kernel memory so should be set to as small as possible - // but should account for the maximum possible events in the queue - // USB updates will likely occur at 100 Hz so one must account for this rate of - // if states change quickly (updates are only posted on state changes) -}; - -// ================================== - -// queues specific element, performing any device queue set up required -extern int HIDQueueElement(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHidElementRef); - -// adds all elements to queue, performing any device queue set up required -extern int HIDQueueDevice(IOHIDDeviceRef inIOHIDDeviceRef); - -// removes element for queue, if last element in queue will release queue and device -extern int HIDDequeueElement(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHidElementRef); - -// completely removes all elements from queue and releases queue and device -extern int HIDDequeueDevice(IOHIDDeviceRef inIOHIDDeviceRef); - -// releases all device queues for quit or rebuild (must be called) -extern int HIDReleaseAllDeviceQueues(void); - -// returns true if an event is avialable for the element and fills out *pHIDEvent structure, returns false otherwise -// pHIDEvent is a poiner to a IOHIDEventStruct, using void here for compatibility, users can cast a required -extern unsigned char HIDGetEvent(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDValueRef *pIOHIDValueRef); - -// ================================== - -// Conguration and Save Interfaces - -enum { - kPercentMove = 10 // precent of overall range a element must move to register -}; - -typedef struct HID_info_struct { - int actionCookie; - // device - // need to add serial number when I have a test case - struct { - int vendorID, productID; - int locID; - uint32_t usagePage, usage; - } device; - // elements - struct { - uint32_t usagePage, usage; - int minReport, maxReport; - IOHIDElementCookie cookie; // always 32 bits - } element; -}HID_info_rec, *HID_info_ptr; - -// get vendor name from vendor ID -extern Boolean HIDGetVendorNameFromVendorID(long inVendorID, char *outCStrName); - -// get product name from vendor/product ID -extern Boolean HIDGetProductNameFromVendorProductID(long inVendorID, long inProductID, char *outCStrName); - -// get element name from vendor id/product id look up ( using element cookie ) -extern Boolean HIDGetElementNameFromVendorProductCookie(int inVendorID, - int inProductID, - IOHIDElementCookie inCookie, - char * outCStrName); - -// get element name from vendor id/product id look up ( using element usage page & usage ) -extern Boolean HIDGetElementNameFromVendorProductUsage(long inVendorID, - long inProductID, - long inUsagePage, - long inUsage, - char *inCStrName); - -// utility routines to dump device or element info -extern void HIDDumpDeviceInfo(IOHIDDeviceRef inIOHIDDeviceRef); -extern void HIDDumpElementInfo(IOHIDElementRef inIOHIDElementRef); -extern void HIDDumpElementCalibrationInfo(IOHIDElementRef inIOHIDElementRef); - -// polls single device's elements for a change greater than kPercentMove. Times out after given time -// returns 1 and pointer to element if found -// returns 0 and NULL for both parameters if not found -extern unsigned char HIDConfigureSingleDeviceAction(IOHIDDeviceRef inIOHIDDeviceRef, - IOHIDElementRef *outIOHIDElementRef, - float timeout); - -//************************************************************************* -// -// HIDConfigureAction( outDeviceRef, outElementRef, inTimeout ) -// -// Purpose: polls all devices and elements for a change greater than kPercentMove. -// Times out after given time returns 1 and pointer to device and element -// if found; returns 0 and NULL for both parameters if not found -// -// Inputs: outDeviceRef - address where to store the device -// outElementRef - address where to store the element -// inTimeout - the timeout -// Returns: Boolean - TRUE if successful -// outDeviceRef - the device -// outElementRef - the element -// - -extern Boolean HIDConfigureAction(IOHIDDeviceRef *outDeviceRef, IOHIDElementRef *outElementRef, float inTimeout); - -//************************************************************************* -// -// HIDSaveElementPref( inKeyCFStringRef, inAppCFStringRef, inDeviceRef, inElementRef ) -// -// Purpose: Save the device & element values into the specified key in the specified applications preferences -// -// Inputs: inKeyCFStringRef - the preference key -// inAppCFStringRef - the application identifier -// inDeviceRef - the device -// inElementRef - the element -// Returns: Boolean - if successful -// - -extern Boolean HIDSaveElementPref(const CFStringRef inKeyCFStringRef, - CFStringRef inAppCFStringRef, - IOHIDDeviceRef inDeviceRef, - IOHIDElementRef inElementRef); - -//************************************************************************* -// -// HIDRestoreElementPref( inKeyCFStringRef, inAppCFStringRef, outDeviceRef, outElementRef ) -// -// Purpose: Find the specified preference in the specified application -// -// Inputs: inKeyCFStringRef - the preference key -// inAppCFStringRef - the application identifier -// outDeviceRef - address where to restore the device -// outElementRef - address where to restore the element -// Returns: Boolean - if successful -// outDeviceRef - the device -// outElementRef - the element -// - -extern Boolean HIDRestoreElementPref(CFStringRef inKeyCFStringRef, - CFStringRef inAppCFStringRef, - IOHIDDeviceRef * outDeviceRef, - IOHIDElementRef *outElementRef); - -//************************************************************************* -// -// HIDFindDeviceAndElement( inSearchInfo, outFoundDevice, outFoundElement ) -// -// Purpose: find the closest matching device and element for this action -// -// Notes: matches device: serial, vendorID, productID, location, inUsagePage, usage -// matches element: cookie, inUsagePage, usage, -// -// Inputs: inSearchInfo - the device & element info we searching for -// outFoundDevice - the address of the best matching device -// outFoundElement - the address of the best matching element -// -// Returns: Boolean - TRUE if we find a match -// outFoundDevice - the best matching device -// outFoundElement - the best matching element -// - -extern Boolean HIDFindDeviceAndElement(const HID_info_rec *inSearchInfo, - IOHIDDeviceRef * outFoundDevice, - IOHIDElementRef * outFoundElement); - -// -- These are routines to use if the applcationwants HID Utilities to do the file handling -- -// Note: the FILE * is a MachO posix FILE and will not likely work directly with MW MSL FILE * type. - -// take input records, save required info -// assume file is open and at correct position. -void HIDSaveElementConfig(FILE *fileRef, IOHIDDeviceRef inIOHIDDeviceRef, IOHIDElementRef inIOHidElementRef, int actionCookie); - -// takes a file, reads one record (assume file position is correct and file is open) -// search for matching device -// return tIOHIDDeviceRef, tIOHIDElementRef and cookie for action -int HIDRestoreElementConfig(FILE *fileRef, IOHIDDeviceRef *outIOHIDDeviceRef, IOHIDElementRef *outIOHIDElementRef); - -// -- These are routines to use if the client wants to use their own file handling -- - -// Set up a config record for saving -// takes an input records, returns record user can save as they want -// Note: the save rec must be pre-allocated by the calling app and will be filled out -void HIDSetElementConfig(HID_info_ptr inHIDInfoPtr, - IOHIDDeviceRef inIOHIDDeviceRef, - IOHIDElementRef inIOHidElementRef, - int actionCookie); - -// Get matching element from config record -// takes a pre-allocated and filled out config record -// search for matching device -// return tIOHIDDeviceRef, tIOHIDElementRef and cookie for action -int HIDGetElementConfig(HID_info_ptr inHIDInfoPtr, IOHIDDeviceRef *outIOHIDDeviceRef, IOHIDElementRef *outIOHIDElementRef); - -// ================================== - -// Error reporter, can be set to report however the application desires -extern void HIDReportError(const char *strError); - -// Error with numeric code reporter, can be set to report however the application desires -extern void HIDReportErrorNum(const char *strError, int numError); - -#ifdef __cplusplus -} -#endif - -#endif // _HID_Utilities_External_h_ diff --git a/src/cocoa/IOHIDDevice_.c b/src/cocoa/IOHIDDevice_.c deleted file mode 100644 index 30c01dc7c..000000000 --- a/src/cocoa/IOHIDDevice_.c +++ /dev/null @@ -1,619 +0,0 @@ -// File: IOHIDDevice_.c -// Abstract: convieance functions for IOHIDDeviceGetProperty -// Version: 2.0 + 5.3 -// -// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple -// Inc. ("Apple") in consideration of your agreement to the following -// terms, and your use, installation, modification or redistribution of -// this Apple software constitutes acceptance of these terms. If you do -// not agree with these terms, please do not use, install, modify or -// redistribute this Apple software. -// -// In consideration of your agreement to abide by the following terms, and -// subject to these terms, Apple grants you a personal, non-exclusive -// license, under Apple's copyrights in this original Apple software (the -// "Apple Software"), to use, reproduce, modify and redistribute the Apple -// Software, with or without modifications, in source and/or binary forms; -// provided that if you redistribute the Apple Software in its entirety and -// without modifications, you must retain this notice and the following -// text and disclaimers in all such redistributions of the Apple Software. -// Neither the name, trademarks, service marks or logos of Apple Inc. may -// be used to endorse or promote products derived from the Apple Software -// without specific prior written permission from Apple. Except as -// expressly stated in this notice, no other rights or licenses, express or -// implied, are granted by Apple herein, including but not limited to any -// patent rights that may be infringed by your derivative works or by other -// works in which the Apple Software may be incorporated. -// -// The Apple Software is provided by Apple on an "AS IS" basis. APPLE -// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION -// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS -// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND -// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. -// -// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL -// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, -// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED -// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), -// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Copyright (C) 2009 Apple Inc. All Rights Reserved. -// -//***************************************************** - -#include - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 - -#pragma mark - includes & imports -//----------------------------------------------------- - -#include "IOHIDDevice_.h" - -//***************************************************** -#pragma mark - typedef's, struct's, enums, defines, etc. -//----------------------------------------------------- - -#define kIOHIDDevice_TransactionKey "DeviceTransactionRef" -#define kIOHIDDevice_QueueKey "DeviceQueueRef" - -//***************************************************** -#pragma mark - local (static) function prototypes -//----------------------------------------------------- - -static Boolean IOHIDDevice_GetUInt32Property(IOHIDDeviceRef inIOHIDDeviceRef, - CFStringRef inKey, - uint32_t * outValue); -// static void IOHIDDevice_SetUInt32Property(IOHIDDeviceRef inIOHIDDeviceRef, CFStringRef inKey, uint32_t inValue); - -static Boolean IOHIDDevice_GetPtrProperty(IOHIDDeviceRef inIOHIDDeviceRef, - CFStringRef inKey, - void ** outValue); -static void IOHIDDevice_SetPtrProperty(IOHIDDeviceRef inIOHIDDeviceRef, - CFStringRef inKey, - void * inValue); - -//***************************************************** -#pragma mark - exported globals -//----------------------------------------------------- - -//***************************************************** -#pragma mark - local (static) globals -//----------------------------------------------------- - -//***************************************************** -#pragma mark - exported function implementations -//----------------------------------------------------- - -//************************************************************************* -// -// HIDIsValidDevice( inIOHIDDeviceRef ) -// -// Purpose: validate this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: Boolean - TRUE if we find the device in our( internal ) device list -// - -Boolean HIDIsValidDevice(IOHIDDeviceRef inIOHIDDeviceRef) { - Boolean result = FALSE; // assume failure (pessimist!) - if ( inIOHIDDeviceRef ) { - if ( CFGetTypeID(inIOHIDDeviceRef) ==IOHIDDeviceGetTypeID() ) { - result = TRUE; - } - } - - return (result); -} // HIDIsValidDevice - -//************************************************************************* -// -// IOHIDDevice_GetTransport( inIOHIDDeviceRef ) -// -// Purpose: get the Transport CFString for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: CFStringRef - the Transport for this device -// - -CFStringRef IOHIDDevice_GetTransport(IOHIDDeviceRef inIOHIDDeviceRef) { - assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); - return ( IOHIDDeviceGetProperty( inIOHIDDeviceRef, CFSTR(kIOHIDTransportKey) ) ); -} - -//************************************************************************* -// -// IOHIDDevice_GetVendorID( inIOHIDDeviceRef ) -// -// Purpose: get the vendor ID for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: uint32_t - the vendor ID for this device -// - -uint32_t IOHIDDevice_GetVendorID(IOHIDDeviceRef inIOHIDDeviceRef) { - uint32_t result = 0; - (void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDVendorIDKey), &result); - return (result); -} // IOHIDDevice_GetVendorID - -//************************************************************************* -// -// IOHIDDevice_GetVendorIDSource( inIOHIDDeviceRef ) -// -// Purpose: get the VendorIDSource for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: uint32_t - the VendorIDSource for this device -// - -uint32_t IOHIDDevice_GetVendorIDSource(IOHIDDeviceRef inIOHIDDeviceRef) { - uint32_t result = 0; - (void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDVendorIDSourceKey), &result); - return (result); -} // IOHIDDevice_GetVendorIDSource - -//************************************************************************* -// -// IOHIDDevice_GetProductID( inIOHIDDeviceRef ) -// -// Purpose: get the product ID for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: uint32_t - the product ID for this device -// - -uint32_t IOHIDDevice_GetProductID(IOHIDDeviceRef inIOHIDDeviceRef) { - uint32_t result = 0; - (void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDProductIDKey), &result); - return (result); -} // IOHIDDevice_GetProductID - -//************************************************************************* -// -// IOHIDDevice_GetVersionNumber( inIOHIDDeviceRef ) -// -// Purpose: get the VersionNumber CFString for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: uint32_t - the VersionNumber for this device -// - -uint32_t IOHIDDevice_GetVersionNumber(IOHIDDeviceRef inIOHIDDeviceRef) { - uint32_t result = 0; - (void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDVersionNumberKey), &result); - return (result); -} // IOHIDDevice_GetVersionNumber - -//************************************************************************* -// -// IOHIDDevice_GetManufacturer( inIOHIDDeviceRef ) -// -// Purpose: get the Manufacturer CFString for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: CFStringRef - the Manufacturer for this device -// - -CFStringRef IOHIDDevice_GetManufacturer(IOHIDDeviceRef inIOHIDDeviceRef) { - assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); - return ( IOHIDDeviceGetProperty( inIOHIDDeviceRef, CFSTR(kIOHIDManufacturerKey) ) ); -} // IOHIDDevice_GetManufacturer - -//************************************************************************* -// -// IOHIDDevice_GetProduct( inIOHIDDeviceRef ) -// -// Purpose: get the Product CFString for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: CFStringRef - the Product for this device -// - -CFStringRef IOHIDDevice_GetProduct(IOHIDDeviceRef inIOHIDDeviceRef) { - assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); - return ( IOHIDDeviceGetProperty( inIOHIDDeviceRef, CFSTR(kIOHIDProductKey) ) ); -} // IOHIDDevice_GetProduct - -//************************************************************************* -// -// IOHIDDevice_GetSerialNumber( inIOHIDDeviceRef ) -// -// Purpose: get the SerialNumber CFString for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: CFStringRef - the SerialNumber for this device -// - -CFStringRef IOHIDDevice_GetSerialNumber(IOHIDDeviceRef inIOHIDDeviceRef) { - assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); - return ( IOHIDDeviceGetProperty( inIOHIDDeviceRef, CFSTR(kIOHIDSerialNumberKey) ) ); -} - -//************************************************************************* -// -// IOHIDDevice_GetCountryCode( inIOHIDDeviceRef ) -// -// Purpose: get the CountryCode CFString for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: uint32_t - the CountryCode for this device -// - -uint32_t IOHIDDevice_GetCountryCode(IOHIDDeviceRef inIOHIDDeviceRef) { - uint32_t result = 0; - (void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDCountryCodeKey), &result); - return (result); -} // IOHIDDevice_GetCountryCode - -//************************************************************************* -// -// IOHIDDevice_GetLocationID( inIOHIDDeviceRef ) -// -// Purpose: get the location ID for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: uint32_t - the location ID for this device -// - -uint32_t IOHIDDevice_GetLocationID(IOHIDDeviceRef inIOHIDDeviceRef) { - uint32_t result = 0; - (void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDLocationIDKey), &result); - return (result); -} // IOHIDDevice_GetLocationID - -//************************************************************************* -// -// IOHIDDevice_GetUsage( inIOHIDDeviceRef ) -// -// Purpose: get the usage for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: uint32_t - the usage for this device -// - -uint32_t IOHIDDevice_GetUsage(IOHIDDeviceRef inIOHIDDeviceRef) { - uint32_t result = 0; - (void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDDeviceUsageKey), &result); - return (result); -} // IOHIDDevice_GetUsage - -//************************************************************************* -// -// IOHIDDevice_GetUsagePage( inIOHIDDeviceRef ) -// -// Purpose: get the usage page for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: uint32_t - the usage page for this device -// - -uint32_t IOHIDDevice_GetUsagePage(IOHIDDeviceRef inIOHIDDeviceRef) { - uint32_t result = 0; - (void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDDeviceUsagePageKey), &result); - return (result); -} // IOHIDDevice_GetUsagePage - -//************************************************************************* -// -// IOHIDDevice_GetUsagePairs( inIOHIDDeviceRef ) -// -// Purpose: get the UsagePairs CFString for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: CFArrayRef - the UsagePairs for this device -// - -CFArrayRef IOHIDDevice_GetUsagePairs(IOHIDDeviceRef inIOHIDDeviceRef) { - assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); - return ( IOHIDDeviceGetProperty( inIOHIDDeviceRef, CFSTR(kIOHIDDeviceUsagePairsKey) ) ); -} - -//************************************************************************* -// -// IOHIDDevice_GetPrimaryUsage( inIOHIDDeviceRef ) -// -// Purpose: get the PrimaryUsage CFString for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: uint32_t - the PrimaryUsage for this device -// - -uint32_t IOHIDDevice_GetPrimaryUsage(IOHIDDeviceRef inIOHIDDeviceRef) { - uint32_t result = 0; - (void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDPrimaryUsageKey), &result); - return (result); -} // IOHIDDevice_GetPrimaryUsage - -//************************************************************************* -// -// IOHIDDevice_GetPrimaryUsagePage( inIOHIDDeviceRef ) -// -// Purpose: get the PrimaryUsagePage CFString for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: uint32_t - the PrimaryUsagePage for this device -// - -uint32_t IOHIDDevice_GetPrimaryUsagePage(IOHIDDeviceRef inIOHIDDeviceRef) { - uint32_t result = 0; - (void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDPrimaryUsagePageKey), &result); - return (result); -} // IOHIDDevice_GetPrimaryUsagePage - -//************************************************************************* -// -// IOHIDDevice_GetMaxInputReportSize( inIOHIDDeviceRef ) -// -// Purpose: get the MaxInputReportSize CFString for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: uint32_t - the MaxInputReportSize for this device -// - -uint32_t IOHIDDevice_GetMaxInputReportSize(IOHIDDeviceRef inIOHIDDeviceRef) { - uint32_t result = 0; - (void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDMaxInputReportSizeKey), &result); - return (result); -} // IOHIDDevice_GetMaxInputReportSize - -//************************************************************************* -// -// IOHIDDevice_GetMaxOutputReportSize( inIOHIDDeviceRef ) -// -// Purpose: get the MaxOutputReportSize for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: uint32_t - the MaxOutput for this device -// - -uint32_t IOHIDDevice_GetMaxOutputReportSize(IOHIDDeviceRef inIOHIDDeviceRef) { - uint32_t result = 0; - (void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDMaxOutputReportSizeKey), &result); - return (result); -} // IOHIDDevice_GetMaxOutputReportSize - -//************************************************************************* -// -// IOHIDDevice_GetMaxFeatureReportSize( inIOHIDDeviceRef ) -// -// Purpose: get the MaxFeatureReportSize for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: uint32_t - the MaxFeatureReportSize for this device -// - -uint32_t IOHIDDevice_GetMaxFeatureReportSize(IOHIDDeviceRef inIOHIDDeviceRef) { - uint32_t result = 0; - (void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDMaxFeatureReportSizeKey), &result); - return (result); -} // IOHIDDevice_GetMaxFeatureReportSize - -//************************************************************************* -// -// IOHIDDevice_GetReportInterval( inIOHIDDeviceRef ) -// -// Purpose: get the ReportInterval for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: uint32_t - the ReportInterval for this device -// -#ifndef kIOHIDReportIntervalKey -#define kIOHIDReportIntervalKey "ReportInterval" -#endif -uint32_t IOHIDDevice_GetReportInterval(IOHIDDeviceRef inIOHIDDeviceRef) { - uint32_t result = 0; - (void) IOHIDDevice_GetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDReportIntervalKey), &result); - return (result); -} // IOHIDDevice_GetReportInterval - -//************************************************************************* -// -// IOHIDDevice_GetQueue( inIOHIDDeviceRef ) -// -// Purpose: get the Queue for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: IOHIDQueueRef - the Queue for this device -// - -IOHIDQueueRef IOHIDDevice_GetQueue(IOHIDDeviceRef inIOHIDDeviceRef) { - IOHIDQueueRef result = 0; - (void) IOHIDDevice_GetPtrProperty(inIOHIDDeviceRef, CFSTR(kIOHIDDevice_QueueKey), (void *) &result); - if ( result ) { - assert( IOHIDQueueGetTypeID() == CFGetTypeID(result) ); - } - - return (result); -} // IOHIDDevice_GetQueue - -//************************************************************************* -// -// IOHIDDevice_SetQueue( inIOHIDDeviceRef, inQueueRef ) -// -// Purpose: Set the Queue for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// inQueueRef - the Queue reference -// -// Returns: nothing -// - -void IOHIDDevice_SetQueue(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDQueueRef inQueueRef) { - IOHIDDevice_SetPtrProperty(inIOHIDDeviceRef, CFSTR(kIOHIDDevice_QueueKey), inQueueRef); -} - -//************************************************************************* -// -// IOHIDDevice_GetTransaction( inIOHIDDeviceRef ) -// -// Purpose: get the Transaction for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// -// Returns: IOHIDTransactionRef - the Transaction for this device -// - -IOHIDTransactionRef IOHIDDevice_GetTransaction(IOHIDDeviceRef inIOHIDDeviceRef) { - IOHIDTransactionRef result = 0; - (void) IOHIDDevice_GetPtrProperty(inIOHIDDeviceRef, CFSTR(kIOHIDDevice_TransactionKey), (void *) &result); - return (result); -} // IOHIDDevice_GetTransaction - -//************************************************************************* -// -// IOHIDDevice_SetTransaction( inIOHIDDeviceRef, inTransactionRef ) -// -// Purpose: Set the Transaction for this device -// -// Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device -// inTransactionRef - the Transaction reference -// -// Returns: nothing -// - -void IOHIDDevice_SetTransaction(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDTransactionRef inTransactionRef) { - IOHIDDevice_SetPtrProperty(inIOHIDDeviceRef, CFSTR(kIOHIDDevice_TransactionKey), inTransactionRef); -} - -//***************************************************** -#pragma mark - local (static) function implementations -//----------------------------------------------------- - -//************************************************************************* -// -// IOHIDDevice_GetUInt32Property( inIOHIDDeviceRef, inKey, outValue ) -// -// Purpose: convieance function to return a uint32_t property of a device -// -// Inputs: inIOHIDDeviceRef - the device -// inKey - CFString for the -// outValue - address where to restore the element -// Returns: the action cookie -// outValue - the device -// - -static Boolean IOHIDDevice_GetUInt32Property(IOHIDDeviceRef inIOHIDDeviceRef, CFStringRef inKey, uint32_t *outValue) { - Boolean result = FALSE; - if ( inIOHIDDeviceRef ) { - assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); - - CFTypeRef tCFTypeRef = IOHIDDeviceGetProperty(inIOHIDDeviceRef, inKey); - if ( tCFTypeRef ) { - // if this is a number - if ( CFNumberGetTypeID() == CFGetTypeID(tCFTypeRef) ) { - // get it's value - result = CFNumberGetValue( (CFNumberRef) tCFTypeRef, kCFNumberSInt32Type, outValue ); - } - } - } - - return (result); -} // IOHIDDevice_GetUInt32Property - -//************************************************************************* -// -// IOHIDDevice_SetUInt32Property( inIOHIDDeviceRef, inKey, inValue ) -// -// Purpose: convieance function to set a long property of an Device -// -// Inputs: inIOHIDDeviceRef - the Device -// inKey - CFString for the key -// inValue - the value to set it to -// Returns: nothing -// -#if 0 // unused -static void IOHIDDevice_SetUInt32Property(IOHIDDeviceRef inIOHIDDeviceRef, CFStringRef inKey, uint32_t inValue) { - CFNumberRef tCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &inValue); - if ( tCFNumberRef ) { - IOHIDDeviceSetProperty(inIOHIDDeviceRef, inKey, tCFNumberRef); - CFRelease(tCFNumberRef); - } -} // IOHIDDevice_SetUInt32Property -#endif -//************************************************************************* -// -// IOHIDDevice_GetPtrProperty( inIOHIDDeviceRef, inKey, outValue ) -// -// Purpose: convieance function to return a pointer property of a device -// -// Inputs: inIOHIDDeviceRef - the device -// inKey - CFString for the -// outValue - address where to restore the element -// Returns: the action cookie -// outValue - the device -// - -static Boolean IOHIDDevice_GetPtrProperty(IOHIDDeviceRef inIOHIDDeviceRef, CFStringRef inKey, void **outValue) { - Boolean result = FALSE; - if ( inIOHIDDeviceRef ) { - assert( IOHIDDeviceGetTypeID() == CFGetTypeID(inIOHIDDeviceRef) ); - - CFTypeRef tCFTypeRef = IOHIDDeviceGetProperty(inIOHIDDeviceRef, inKey); - if ( tCFTypeRef ) { - // if this is a number - if ( CFNumberGetTypeID() == CFGetTypeID(tCFTypeRef) ) { - // get it's value -#ifdef __LP64__ - result = CFNumberGetValue( (CFNumberRef) tCFTypeRef, kCFNumberSInt64Type, outValue ); -#else - result = CFNumberGetValue( (CFNumberRef) tCFTypeRef, kCFNumberSInt32Type, outValue ); -#endif // ifdef __LP64__ - } - } - } - - return (result); -} // IOHIDDevice_GetPtrProperty - -//************************************************************************* -// -// IOHIDDevice_SetPtrProperty( inIOHIDDeviceRef, inKey, inValue ) -// -// Purpose: convieance function to set a long property of an Device -// -// Inputs: inIOHIDDeviceRef - the Device -// inKey - CFString for the key -// inValue - the value to set it to -// Returns: nothing -// - -static void IOHIDDevice_SetPtrProperty(IOHIDDeviceRef inIOHIDDeviceRef, CFStringRef inKey, void *inValue) { -#ifdef __LP64__ - CFNumberRef tCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &inValue); -#else - CFNumberRef tCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &inValue); -#endif // ifdef __LP64__ - if ( tCFNumberRef ) { - IOHIDDeviceSetProperty(inIOHIDDeviceRef, inKey, tCFNumberRef); - CFRelease(tCFNumberRef); - } -} // IOHIDDevice_SetPtrProperty - -//***************************************************** - -#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 diff --git a/src/cocoa/IOHIDDevice_.h b/src/cocoa/IOHIDDevice_.h deleted file mode 100644 index eebccd667..000000000 --- a/src/cocoa/IOHIDDevice_.h +++ /dev/null @@ -1,422 +0,0 @@ -// File: IOHIDDevice_.h -// Abstract: convieance functions for IOHIDDeviceGetProperty -// Version: 2.0 + 5.3 -// -// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple -// Inc. ("Apple") in consideration of your agreement to the following -// terms, and your use, installation, modification or redistribution of -// this Apple software constitutes acceptance of these terms. If you do -// not agree with these terms, please do not use, install, modify or -// redistribute this Apple software. -// -// In consideration of your agreement to abide by the following terms, and -// subject to these terms, Apple grants you a personal, non-exclusive -// license, under Apple's copyrights in this original Apple software (the -// "Apple Software"), to use, reproduce, modify and redistribute the Apple -// Software, with or without modifications, in source and/or binary forms; -// provided that if you redistribute the Apple Software in its entirety and -// without modifications, you must retain this notice and the following -// text and disclaimers in all such redistributions of the Apple Software. -// Neither the name, trademarks, service marks or logos of Apple Inc. may -// be used to endorse or promote products derived from the Apple Software -// without specific prior written permission from Apple. Except as -// expressly stated in this notice, no other rights or licenses, express or -// implied, are granted by Apple herein, including but not limited to any -// patent rights that may be infringed by your derivative works or by other -// works in which the Apple Software may be incorporated. -// -// The Apple Software is provided by Apple on an "AS IS" basis. APPLE -// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION -// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS -// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND -// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. -// -// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL -// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, -// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED -// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), -// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Copyright (C) 2014 Apple Inc. All Rights Reserved. -// -//***************************************************** -#ifndef __IOHIDDevice__ -#define __IOHIDDevice__ - -//***************************************************** -#pragma mark - includes & imports - -#include - -#include "IOHIDLib_.h" - -//***************************************************** -#if PRAGMA_ONCE -#pragma once -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if PRAGMA_IMPORT -#pragma import on -#endif - -#if PRAGMA_STRUCT_ALIGN -#pragma options align=mac68k -#elif PRAGMA_STRUCT_PACKPUSH -#pragma pack(push, 2) -#elif PRAGMA_STRUCT_PACK -#pragma pack(2) -#endif - - //***************************************************** -#pragma mark - typedef's, struct's, enums, defines, etc. - //----------------------------------------------------- - - //***************************************************** -#pragma mark - exported globals - //----------------------------------------------------- - - //***************************************************** -#pragma mark - exported function prototypes - //----------------------------------------------------- - - //************************************************************************* - // - // HIDIsValidDevice( inIOHIDDeviceRef ) - // - // Purpose: validate this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: Boolean - TRUE if we find the device in our( internal ) device list - // - - extern Boolean HIDIsValidDevice(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_GetTransport( inIOHIDDeviceRef ) - // - // Purpose: get the Transport CFString for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: CFStringRef - the Transport CFString for this device - // - - extern CFStringRef IOHIDDevice_GetTransport(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_GetVendorID( inIOHIDDeviceRef ) - // - // Purpose: get the vendor ID for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: uint32_t - the vendor ID for this device - // - - extern uint32_t IOHIDDevice_GetVendorID(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_GetVendorIDSource( inIOHIDDeviceRef ) - // - // Purpose: get the VendorIDSource for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: uint32_t - the VendorIDSource for this device - // - - extern uint32_t IOHIDDevice_GetVendorIDSource(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_GetProductID( inIOHIDDeviceRef ) - // - // Purpose: get the product ID for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: uint32_t - the product ID for this device - // - - extern uint32_t IOHIDDevice_GetProductID(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_GetVersionNumber( inIOHIDDeviceRef ) - // - // Purpose: get the VersionNumber CFString for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: uint32_t - the VersionNumber for this device - // - - extern uint32_t IOHIDDevice_GetVersionNumber(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_GetManufacturer( inIOHIDDeviceRef ) - // - // Purpose: get the Manufacturer CFString for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: CFStringRef - the Manufacturer CFString for this device - // - - extern CFStringRef IOHIDDevice_GetManufacturer(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_GetProduct( inIOHIDDeviceRef ) - // - // Purpose: get the Product CFString for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: CFStringRef - the Product CFString for this device - // - - extern CFStringRef IOHIDDevice_GetProduct(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_GetSerialNumber( inIOHIDDeviceRef ) - // - // Purpose: get the SerialNumber CFString for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: CFStringRef - the SerialNumber CFString for this device - // - - extern CFStringRef IOHIDDevice_GetSerialNumber(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_GetCountryCode( inIOHIDDeviceRef ) - // - // Purpose: get the CountryCode CFString for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: uint32_t - the CountryCode for this device - // - - extern uint32_t IOHIDDevice_GetCountryCode(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_GetLocationID( inIOHIDDeviceRef ) - // - // Purpose: get the location ID for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: uint32_t - the location ID for this device - // - - extern uint32_t IOHIDDevice_GetLocationID(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_GetUsage( inIOHIDDeviceRef ) - // - // Purpose: get the usage for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: uint32_t - the usage for this device - // - - extern uint32_t IOHIDDevice_GetUsage(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_GetUsagePage( inIOHIDDeviceRef ) - // - // Purpose: get the usage page for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: uint32_t - the usage page for this device - // - - extern uint32_t IOHIDDevice_GetUsagePage(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_GetUsagePairs( inIOHIDDeviceRef ) - // - // Purpose: get the UsagePairs CFString for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: CFArrayRef - the UsagePairs for this device - // - - extern CFArrayRef IOHIDDevice_GetUsagePairs(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_GetPrimaryUsage( inIOHIDDeviceRef ) - // - // Purpose: get the PrimaryUsage CFString for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: CFStringRef - the PrimaryUsage CFString for this device - // - - extern uint32_t IOHIDDevice_GetPrimaryUsage(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_GetPrimaryUsagePage( inIOHIDDeviceRef ) - // - // Purpose: get the PrimaryUsagePage CFString for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: CFStringRef - the PrimaryUsagePage CFString for this device - // - - extern uint32_t IOHIDDevice_GetPrimaryUsagePage(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_GetMaxInputReportSize( inIOHIDDeviceRef ) - // - // Purpose: get the MaxInputReportSize for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: uint32_t - the MaxInputReportSize for this device - // - - extern uint32_t IOHIDDevice_GetMaxInputReportSize(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_GetMaxOutputReportSize( inIOHIDDeviceRef ) - // - // Purpose: get the MaxOutputReportSize for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: uint32_t - the MaxOutputReportSize for this device - // - - extern uint32_t IOHIDDevice_GetMaxOutputReportSize(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_GetMaxFeatureReportSize( inIOHIDDeviceRef ) - // - // Purpose: get the MaxFeatureReportSize for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: uint32_t - the MaxFeatureReportSize for this device - // - - extern uint32_t IOHIDDevice_GetMaxFeatureReportSize(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_GetReportInterval( inIOHIDDeviceRef ) - // - // Purpose: get the ReportInterval for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: uint32_t - the ReportInterval for this device - // - - extern uint32_t IOHIDDevice_GetReportInterval(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_GetQueue( inIOHIDDeviceRef ) - // - // Purpose: get the Queue for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: IOHIDQueueRef - the Queue for this device - // - - extern IOHIDQueueRef IOHIDDevice_GetQueue(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_SetQueue( inIOHIDDeviceRef, inQueueRef ) - // - // Purpose: Set the Queue for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // inQueueRef - the Queue - // - // Returns: nothing - // - - extern void IOHIDDevice_SetQueue(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDQueueRef inQueueRef); - - //************************************************************************* - // - // IOHIDDevice_GetTransaction( inIOHIDDeviceRef ) - // - // Purpose: get the Transaction for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // - // Returns: IOHIDTransactionRef - the Transaction for this device - // - - extern IOHIDTransactionRef IOHIDDevice_GetTransaction(IOHIDDeviceRef inIOHIDDeviceRef); - - //************************************************************************* - // - // IOHIDDevice_SetTransaction( inIOHIDDeviceRef, inTransactionRef ) - // - // Purpose: Set the Transaction for this device - // - // Inputs: inIOHIDDeviceRef - the IDHIDDeviceRef for this device - // inTransactionRef - the Transaction - // - // Returns: nothing - // - - extern void IOHIDDevice_SetTransaction(IOHIDDeviceRef inIOHIDDeviceRef, IOHIDTransactionRef inTransactionRef); - - //***************************************************** -#if PRAGMA_STRUCT_ALIGN -#pragma options align=reset -#elif PRAGMA_STRUCT_PACKPUSH -#pragma pack(pop) -#elif PRAGMA_STRUCT_PACK -#pragma pack() -#endif - -#ifdef PRAGMA_IMPORT_OFF -#pragma import off -#elif PRAGMA_IMPORT -#pragma import reset -#endif - -#ifdef __cplusplus -} -#endif - -#endif // __IOHIDDevice__ // diff --git a/src/cocoa/IOHIDElement_.c b/src/cocoa/IOHIDElement_.c deleted file mode 100644 index 906d2926a..000000000 --- a/src/cocoa/IOHIDElement_.c +++ /dev/null @@ -1,509 +0,0 @@ -// File: IOHIDElement_.c -// Abstract: convieance functions for IOHIDElementGetProperty -// Version: 2.0 -// -// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple -// Inc. ("Apple") in consideration of your agreement to the following -// terms, and your use, installation, modification or redistribution of -// this Apple software constitutes acceptance of these terms. If you do -// not agree with these terms, please do not use, install, modify or -// redistribute this Apple software. -// -// In consideration of your agreement to abide by the following terms, and -// subject to these terms, Apple grants you a personal, non-exclusive -// license, under Apple's copyrights in this original Apple software (the -// "Apple Software"), to use, reproduce, modify and redistribute the Apple -// Software, with or without modifications, in source and/or binary forms; -// provided that if you redistribute the Apple Software in its entirety and -// without modifications, you must retain this notice and the following -// text and disclaimers in all such redistributions of the Apple Software. -// Neither the name, trademarks, service marks or logos of Apple Inc. may -// be used to endorse or promote products derived from the Apple Software -// without specific prior written permission from Apple. Except as -// expressly stated in this notice, no other rights or licenses, express or -// implied, are granted by Apple herein, including but not limited to any -// patent rights that may be infringed by your derivative works or by other -// works in which the Apple Software may be incorporated. -// -// The Apple Software is provided by Apple on an "AS IS" basis. APPLE -// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION -// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS -// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND -// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. -// -// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL -// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, -// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED -// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), -// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Copyright (C) 2009 Apple Inc. All Rights Reserved. -// -//***************************************************** - -#include - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 - -#pragma mark - includes & imports -//----------------------------------------------------- - -#include "IOHIDElement_.h" - -//***************************************************** -#pragma mark - typedef's, struct's, enums, defines, etc. -//----------------------------------------------------- - -//***************************************************** -#pragma mark - local (static) function prototypes -//----------------------------------------------------- - -// static Boolean IOHIDElement_GetLongProperty( IOHIDElementRef inElementRef, CFStringRef inKey, long * outValue ); -// static void IOHIDElement_SetLongProperty( IOHIDElementRef inElementRef, CFStringRef inKey, long inValue ); - -//***************************************************** -#pragma mark - exported globals -//----------------------------------------------------- - -//***************************************************** -#pragma mark - local (static) globals -//----------------------------------------------------- - -//***************************************************** -#pragma mark - exported function implementations -//----------------------------------------------------- - -//************************************************************************* -// -// HIDIsValidElement( inIOHIDElementRef ) -// -// Purpose: validate this element -// -// Inputs: inIOHIDElementRef - the element -// -// Returns: Boolean - TRUE if this is a valid element ref -// -Boolean HIDIsValidElement(IOHIDElementRef inIOHIDElementRef) { - Boolean result = FALSE; // assume failure (pessimist!) - if ( inIOHIDElementRef ) { - if ( CFGetTypeID(inIOHIDElementRef) ==IOHIDElementGetTypeID() ) { - result = TRUE; - } - } - - return (result); -} // HIDIsValidElement - -//************************************************************************* -// -// IOHIDElement_GetValue( inElementRef, inIOHIDValueScaleType ) -// -// Purpose: returns the current value for an element( polling ) -// -// Notes: will return 0 on error conditions which should be accounted for by application -// -// Inputs: inElementRef - the element -// inIOHIDValueScaleType - scale type ( calibrated or physical ) -// -// Returns: double - current value for element -// -double IOHIDElement_GetValue(IOHIDElementRef inElementRef, IOHIDValueScaleType inIOHIDValueScaleType) { - long result = 0; - IOHIDValueRef tIOHIDValueRef; - if ( kIOReturnSuccess == IOHIDDeviceGetValue(IOHIDElementGetDevice(inElementRef), inElementRef, &tIOHIDValueRef) ) { - result = IOHIDValueGetScaledValue(tIOHIDValueRef, inIOHIDValueScaleType); - } - - return (result); -} // IOHIDElement_GetValue - -//************************************************************************* -// -// IOHIDElement_GetCalibrationMin( inElementRef ) -// -// Purpose: get the minimum bounds for a calibrated value for this element -// -// Inputs: inElementRef - the IOHIDElementRef for this element -// -// Returns: CFIndex - the minimum Calibration value for this element -// - -CFIndex IOHIDElement_GetCalibrationMin(IOHIDElementRef inElementRef) { - CFIndex result; - if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationMinKey), &result) ) { - if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMaxKey), &result) ) { - result = 0x7FFFFFFF; - } - - IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationMinKey), result); - } - - return (result); -} // IOHIDElement_GetCalibrationMin - -//************************************************************************* -// -// IOHIDElement_SetCalibrationMin( inElementRef, inValue ) -// -// Purpose: set the minimum bounds for a calibrated value for this element -// -// Inputs: inElementRef - the IOHIDElementRef for this element -// inValue - the minimum bounds for a calibrated value for this element -// -// Returns: nothing -// - -void IOHIDElement_SetCalibrationMin(IOHIDElementRef inElementRef, CFIndex inValue) { - IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationMinKey), inValue); -} // IOHIDElement_SetCalibrationMin - -//************************************************************************* -// -// IOHIDElement_GetCalibrationMax( inElementRef ) -// -// Purpose: get the maximum bounds for a calibrated value for this element -// -// Inputs: inElementRef - the IOHIDElementRef for this element -// -// Returns: CFIndex - the maximum Calibration value for this element -// - -CFIndex IOHIDElement_GetCalibrationMax(IOHIDElementRef inElementRef) { - CFIndex result; - if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationMaxKey), &result) ) { - if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMinKey), &result) ) { - result = -0x7FFFFFFF; - } - - IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationMaxKey), result); - } - - return (result); -} // IOHIDElement_GetCalibrationMax - -//************************************************************************* -// -// IOHIDElement_SetCalibrationMax( inElementRef, inValue ) -// -// Purpose: set the maximum bounds for a calibrated value for this element -// -// Inputs: inElementRef - the IOHIDElementRef for this element -// inValue - the maximum Calibration value for this element -// -// Returns: nothing -// - -void IOHIDElement_SetCalibrationMax(IOHIDElementRef inElementRef, CFIndex inValue) { - IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationMaxKey), inValue); -} // IOHIDElement_SetCalibrationMax - -//************************************************************************* -// -// IOHIDElement_GetCalibrationSaturationMin( inElementRef ) -// -// Purpose: get the mininum tolerance to be used when calibrating a logical element value -// -// Inputs: inElementRef - the IOHIDElementRef for this element -// -// Returns: CFIndex - the maximum Calibration value for this element -// - -CFIndex IOHIDElement_GetCalibrationSaturationMin(IOHIDElementRef inElementRef) { - CFIndex result; - if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationSaturationMinKey), &result) ) { - if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMinKey), &result) ) { - result = -0x7FFFFFFF; - } - - IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationSaturationMinKey), result); - } - - return (result); -} // IOHIDElement_GetCalibrationSaturationMin - -//************************************************************************* -// -// IOHIDElement_SetCalibrationSaturationMin( inElementRef, inValue ) -// -// Purpose: set the mininum tolerance to be used when calibrating a logical element value -// -// Inputs: inElementRef - the IOHIDElementRef for this element -// inValue - the maximum Calibration value for this element -// -// Returns: nothing -// - -void IOHIDElement_SetCalibrationSaturationMin(IOHIDElementRef inElementRef, CFIndex inValue) { - IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationSaturationMinKey), inValue); -} // IOHIDElement_SetCalibrationSaturationMin - -//************************************************************************* -// -// IOHIDElement_GetCalibrationSaturationMax( inElementRef ) -// -// Purpose: get the maximum tolerance to be used when calibrating a logical element value -// -// Inputs: inElementRef - the IOHIDElementRef for this element -// -// Returns: CFIndex - the maximum Calibration value for this element -// - -CFIndex IOHIDElement_GetCalibrationSaturationMax(IOHIDElementRef inElementRef) { - CFIndex result; - if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationSaturationMaxKey), &result) ) { - if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMinKey), &result) ) { - result = -0x7FFFFFFF; - } - - IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationSaturationMaxKey), result); - } - - return (result); -} // IOHIDElement_GetCalibrationSaturationMax - -//************************************************************************* -// -// IOHIDElement_SetCalibrationSaturationMax( inElementRef, inValue ) -// -// Purpose: set the maximum tolerance to be used when calibrating a logical element value -// -// Inputs: inElementRef - the IOHIDElementRef for this element -// inValue - the maximum Calibration value for this element -// -// Returns: nothing -// - -void IOHIDElement_SetCalibrationSaturationMax(IOHIDElementRef inElementRef, CFIndex inValue) { - IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationSaturationMaxKey), inValue); -} // IOHIDElement_SetCalibrationSaturationMax - -//************************************************************************* -// -// IOHIDElement_GetCalibrationDeadZoneMin( inElementRef ) -// -// Purpose: get the minimum bounds near the midpoint of a logical value in which the value is ignored -// -// Inputs: inElementRef - the IOHIDElementRef for this element -// -// Returns: CFIndex - the maximum Calibration value for this element -// - -CFIndex IOHIDElement_GetCalibrationDeadZoneMin(IOHIDElementRef inElementRef) { - CFIndex result; - if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationDeadZoneMinKey), &result) ) { - if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMinKey), &result) ) { - result = -0x7FFFFFFF; - } - - IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationDeadZoneMinKey), result); - } - - return (result); -} // IOHIDElement_GetCalibrationDeadZoneMin - -//************************************************************************* -// -// IOHIDElement_SetCalibrationDeadZoneMin( inElementRef, inValue ) -// -// Purpose: set the minimum bounds near the midpoint of a logical value in which the value is ignored -// -// Inputs: inElementRef - the IOHIDElementRef for this element -// inValue - the maximum Calibration value for this element -// -// Returns: nothing -// - -void IOHIDElement_SetCalibrationDeadZoneMin(IOHIDElementRef inElementRef, CFIndex inValue) { - IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationDeadZoneMinKey), inValue); -} // IOHIDElement_SetCalibrationDeadZoneMin - -//************************************************************************* -// -// IOHIDElement_GetCalibrationDeadZoneMax( inElementRef ) -// -// Purpose: get the maximum bounds near the midpoint of a logical value in which the value is ignored -// -// Inputs: inElementRef - the IOHIDElementRef for this element -// -// Returns: CFIndex - the maximum Calibration value for this element -// - -CFIndex IOHIDElement_GetCalibrationDeadZoneMax(IOHIDElementRef inElementRef) { - CFIndex result; - if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationDeadZoneMaxKey), &result) ) { - if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMinKey), &result) ) { - result = -0x7FFFFFFF; - } - - IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationDeadZoneMaxKey), result); - } - - return (result); -} // IOHIDElement_GetCalibrationDeadZoneMax - -//************************************************************************* -// -// IOHIDElement_SetCalibrationDeadZoneMax( inElementRef, inValue ) -// -// Purpose: set the maximum bounds near the midpoint of a logical value in which the value is ignored -// -// Inputs: inElementRef - the IOHIDElementRef for this element -// inValue - the maximum Calibration value for this element -// -// Returns: nothing -// - -void IOHIDElement_SetCalibrationDeadZoneMax(IOHIDElementRef inElementRef, CFIndex inValue) { - IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationDeadZoneMaxKey), inValue); -} // IOHIDElement_SetCalibrationDeadZoneMax - -//************************************************************************* -// -// IOHIDElement_GetCalibrationGranularity( inElementRef ) -// -// Purpose: get the level of detail returned for a calibrated element value -// -// Inputs: inElementRef - the IOHIDElementRef for this element -// -// Returns: double_t - the maximum Calibration value for this element -// - -double_t IOHIDElement_GetCalibrationGranularity(IOHIDElementRef inElementRef) { - CFIndex result; - if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationGranularityKey), &result) ) { - if ( !IOHIDElement_GetLongProperty(inElementRef, CFSTR(kIOHIDElementMinKey), &result) ) { - result = -0x7FFFFFFF; - } - - IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationGranularityKey), result); - } - - return (result); -} // IOHIDElement_GetCalibrationGranularity - -//************************************************************************* -// -// IOHIDElement_SetCalibrationGranularity( inElementRef, inValue ) -// -// Purpose: set the level of detail returned for a calibrated element value -// -// Inputs: inElementRef - the IOHIDElementRef for this element -// inValue - the the level of detail for this element -// -// Returns: nothing -// - -void IOHIDElement_SetCalibrationGranularity(IOHIDElementRef inElementRef, double_t inValue) { - IOHIDElement_SetLongProperty(inElementRef, CFSTR(kIOHIDElementCalibrationGranularityKey), inValue); -} // IOHIDElement_SetCalibrationGranularity - -//************************************************************************* -// -// IOHIDElement_SetupCalibration( inElementRef ) -// -// Purpose: set default values for the element calibration parameters -// -// Inputs: inElementRef - the IOHIDElementRef for this element -// -// Returns: nothing -// -void IOHIDElement_SetupCalibration(IOHIDElementRef inIOHIDElementRef) { - // these are the min/max values returned by IOHIDValueGetScaledValue( v, kIOHIDValueScaleTypeCalibrated ); - IOHIDElement_SetCalibrationMin( inIOHIDElementRef, IOHIDElementGetLogicalMin(inIOHIDElementRef) ); - IOHIDElement_SetCalibrationMax( inIOHIDElementRef, IOHIDElementGetLogicalMax(inIOHIDElementRef) ); - - // this is the granularity of the values returned by IOHIDValueGetScaledValue( v, kIOHIDValueScaleTypeCalibrated ); - // for example if set to 0.1 the values returned will be multiples of 0.1 ( 0.1, 0.2, 0.3, etc. ) - IOHIDElement_SetCalibrationGranularity(inIOHIDElementRef, 0.); - - // these define the dead zone (like in the middel of joystick axis) - IOHIDElement_SetCalibrationDeadZoneMin(inIOHIDElementRef, 0); - IOHIDElement_SetCalibrationDeadZoneMax(inIOHIDElementRef, 0); -#if 1 - // get the current value of this element - double value = IOHIDElement_GetValue(inIOHIDElementRef, kIOHIDValueScaleTypePhysical); - // use it as our min/mas saturation - IOHIDElement_SetCalibrationSaturationMin(inIOHIDElementRef, value); - IOHIDElement_SetCalibrationSaturationMax(inIOHIDElementRef, value); -#else - // calculate the middle physical value we would expect from this element - CFIndex valueMin = IOHIDElementGetPhysicalMin(inIOHIDElementRef); - CFIndex valueMax = IOHIDElementGetPhysicalMax(inIOHIDElementRef); - CFIndex valueMid = (valueMin + valueMax) / 2; - - // use it as our min/mas saturation - // this value determines the min/max values that have been recieved from the device element - IOHIDElement_SetCalibrationSaturationMin(inIOHIDElementRef, valueMid); - IOHIDElement_SetCalibrationSaturationMax(inIOHIDElementRef, valueMid); - - // get the current value of this element - double value = IOHIDElement_GetValue(inIOHIDElementRef, kIOHIDValueScaleTypePhysical); - // and use it to adjust the current saturation values if it's outside their range - if ( value < IOHIDElement_GetCalibrationSaturationMin(inIOHIDElementRef) ) { - IOHIDElement_SetCalibrationSaturationMin(inIOHIDElementRef, value); - } - if ( value > IOHIDElement_GetCalibrationSaturationMax(inIOHIDElementRef) ) { - IOHIDElement_SetCalibrationSaturationMax(inIOHIDElementRef, value); - } - -#endif -} // IOHIDElement_SetupCalibration -//***************************************************** -#pragma mark - local (static) function implementations -//----------------------------------------------------- - -//************************************************************************* -// -// IOHIDElement_GetLongProperty( inElementRef, inKey, outValue ) -// -// Purpose: convieance function to return a long property of an element -// -// Inputs: inElementRef - the element -// inKey - CFString for the key -// outValue - address where to store the value -// Returns: Boolean - TRUE if successful -// outValue - the long property's value -// - -Boolean IOHIDElement_GetLongProperty(IOHIDElementRef inElementRef, CFStringRef inKey, long *outValue) { - Boolean result = FALSE; - - CFTypeRef tCFTypeRef = IOHIDElementGetProperty(inElementRef, inKey); - if ( tCFTypeRef ) { - // if this is a number - if ( CFNumberGetTypeID() == CFGetTypeID(tCFTypeRef) ) { - // get it's value - result = CFNumberGetValue( (CFNumberRef) tCFTypeRef, kCFNumberSInt32Type, outValue ); - } - } - - return (result); -} /* IOHIDElement_GetLongProperty */ - -//************************************************************************* -// -// IOHIDElement_SetLongProperty( inElementRef, inKey, inValue ) -// -// Purpose: convieance function to set a long property of an element -// -// Inputs: inElementRef - the element -// inKey - CFString for the key -// inValue - the value to set it to -// -// Returns: nothing -// - -void IOHIDElement_SetLongProperty(IOHIDElementRef inElementRef, CFStringRef inKey, long inValue) { - CFNumberRef tCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &inValue); - if ( tCFNumberRef ) { - IOHIDElementSetProperty(inElementRef, inKey, tCFNumberRef); - CFRelease(tCFNumberRef); - } -} // IOHIDElement_SetLongProperty - -//***************************************************** - -#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 diff --git a/src/cocoa/IOHIDElement_.h b/src/cocoa/IOHIDElement_.h deleted file mode 100644 index a8a631668..000000000 --- a/src/cocoa/IOHIDElement_.h +++ /dev/null @@ -1,339 +0,0 @@ -// File: IOHIDElement_.h -// Abstract: convieance functions for IOHIDElementGetProperty -// Version: 2.0 -// -// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple -// Inc. ("Apple") in consideration of your agreement to the following -// terms, and your use, installation, modification or redistribution of -// this Apple software constitutes acceptance of these terms. If you do -// not agree with these terms, please do not use, install, modify or -// redistribute this Apple software. -// -// In consideration of your agreement to abide by the following terms, and -// subject to these terms, Apple grants you a personal, non-exclusive -// license, under Apple's copyrights in this original Apple software (the -// "Apple Software"), to use, reproduce, modify and redistribute the Apple -// Software, with or without modifications, in source and/or binary forms; -// provided that if you redistribute the Apple Software in its entirety and -// without modifications, you must retain this notice and the following -// text and disclaimers in all such redistributions of the Apple Software. -// Neither the name, trademarks, service marks or logos of Apple Inc. may -// be used to endorse or promote products derived from the Apple Software -// without specific prior written permission from Apple. Except as -// expressly stated in this notice, no other rights or licenses, express or -// implied, are granted by Apple herein, including but not limited to any -// patent rights that may be infringed by your derivative works or by other -// works in which the Apple Software may be incorporated. -// -// The Apple Software is provided by Apple on an "AS IS" basis. APPLE -// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION -// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS -// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND -// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. -// -// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL -// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, -// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED -// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), -// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Copyright (C) 2009 Apple Inc. All Rights Reserved. -// -//***************************************************** -#ifndef __IOHIDElement___ -#define __IOHIDElement___ - -//***************************************************** -#pragma mark - includes & imports - -#include - -#include "IOHIDLib_.h" -//***************************************************** -#if PRAGMA_ONCE -#pragma once -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if PRAGMA_IMPORT -#pragma import on -#endif - -#if PRAGMA_STRUCT_ALIGN -#pragma options align=mac68k -#elif PRAGMA_STRUCT_PACKPUSH -#pragma pack(push, 2) -#elif PRAGMA_STRUCT_PACK -#pragma pack(2) -#endif - - //***************************************************** -#pragma mark - typedef's, struct's, enums, defines, etc. - //----------------------------------------------------- - - //***************************************************** -#pragma mark - exported globals - //----------------------------------------------------- - - //***************************************************** -#pragma mark - exported function prototypes - //----------------------------------------------------- - - //************************************************************************* - // - // HIDIsValidElement( inIOHIDElementRef ) - // - // Purpose: validate this element - // - // Inputs: inIOHIDElementRef - the element - // - // Returns: Boolean - TRUE if this is a valid element ref - // - extern Boolean HIDIsValidElement(IOHIDElementRef inIOHIDElementRef); - - //************************************************************************* - // - // IOHIDElement_GetValue( inElementRef, inIOHIDValueScaleType ) - // - // Purpose: returns the current value for an element( polling ) - // - // Notes: will return 0 on error conditions which should be accounted for by application - // - // Inputs: inElementRef - the element - // inIOHIDValueScaleType - scale type ( calibrated or physical ) - // - // Returns: double - current value for element - // - extern double IOHIDElement_GetValue(IOHIDElementRef inElementRef, IOHIDValueScaleType inIOHIDValueScaleType); - - //************************************************************************* - // - // IOHIDElement_GetCalibrationMin( inElementRef ) - // - // Purpose: get the minimum bounds for a calibrated value for this element - // - // Inputs: inElementRef - the IOHIDElementRef for this element - // - // Returns: CFIndex - the minimum Calibration value for this element - // - - extern CFIndex IOHIDElement_GetCalibrationMin(IOHIDElementRef inElementRef); - - //************************************************************************* - // - // IOHIDElement_SetCalibrationMin( inElementRef, inValue ) - // - // Purpose: set the minimum bounds for a calibrated value for this element - // - // Inputs: inElementRef - the IOHIDElementRef for this element - // inValue - the minimum bounds for a calibrated value for this element - // - // Returns: nothing - // - - extern void IOHIDElement_SetCalibrationMin(IOHIDElementRef inElementRef, CFIndex inValue); - - //************************************************************************* - // - // IOHIDElement_GetCalibrationMax( inElementRef ) - // - // Purpose: get the maximum bounds for a calibrated value for this element - // - // Inputs: inElementRef - the IOHIDElementRef for this element - // - // Returns: CFIndex - the maximum Calibration value for this element - // - - extern CFIndex IOHIDElement_GetCalibrationMax(IOHIDElementRef inElementRef); - - //************************************************************************* - // - // IOHIDElement_SetCalibrationMax( inElementRef, inValue ) - // - // Purpose: set the maximum bounds for a calibrated value for this element - // - // Inputs: inElementRef - the IOHIDElementRef for this element - // inValue - the maximum Calibration value for this element - // - // Returns: nothing - // - - extern void IOHIDElement_SetCalibrationMax(IOHIDElementRef inElementRef, CFIndex inValue); - - //************************************************************************* - // - // IOHIDElement_GetCalibrationSaturationMin( inElementRef ) - // - // Purpose: get the mininum tolerance to be used when calibrating a logical element value - // - // Inputs: inElementRef - the IOHIDElementRef for this element - // - // Returns: CFIndex - the maximum Calibration value for this element - // - - extern CFIndex IOHIDElement_GetCalibrationSaturationMin(IOHIDElementRef inElementRef); - - //************************************************************************* - // - // IOHIDElement_SetCalibrationSaturationMin( inElementRef, inValue ) - // - // Purpose: set the mininum tolerance to be used when calibrating a logical element value - // - // Inputs: inElementRef - the IOHIDElementRef for this element - // inValue - the maximum Calibration value for this element - // - // Returns: nothing - // - - extern void IOHIDElement_SetCalibrationSaturationMin(IOHIDElementRef inElementRef, CFIndex inValue); - - //************************************************************************* - // - // IOHIDElement_GetCalibrationSaturationMax( inElementRef ) - // - // Purpose: get the maximum tolerance to be used when calibrating a logical element value - // - // Inputs: inElementRef - the IOHIDElementRef for this element - // - // Returns: CFIndex - the maximum Calibration value for this element - // - - extern CFIndex IOHIDElement_GetCalibrationSaturationMax(IOHIDElementRef inElementRef); - - //************************************************************************* - // - // IOHIDElement_SetCalibrationSaturationMax( inElementRef, inValue ) - // - // Purpose: set the maximum tolerance to be used when calibrating a logical element value - // - // Inputs: inElementRef - the IOHIDElementRef for this element - // inValue - the maximum Calibration value for this element - // - // Returns: nothing - // - - extern void IOHIDElement_SetCalibrationSaturationMax(IOHIDElementRef inElementRef, CFIndex inValue); - - //************************************************************************* - // - // IOHIDElement_GetCalibrationDeadZoneMin( inElementRef ) - // - // Purpose: get the minimum bounds near the midpoint of a logical value in which the value is ignored - // - // Inputs: inElementRef - the IOHIDElementRef for this element - // - // Returns: CFIndex - the maximum Calibration value for this element - // - - extern CFIndex IOHIDElement_GetCalibrationDeadZoneMin(IOHIDElementRef inElementRef); - - //************************************************************************* - // - // IOHIDElement_SetCalibrationDeadZoneMin( inElementRef, inValue ) - // - // Purpose: set the minimum bounds near the midpoint of a logical value in which the value is ignored - // - // Inputs: inElementRef - the IOHIDElementRef for this element - // inValue - the maximum Calibration value for this element - // - // Returns: nothing - // - - extern void IOHIDElement_SetCalibrationDeadZoneMin(IOHIDElementRef inElementRef, CFIndex inValue); - - //************************************************************************* - // - // IOHIDElement_GetCalibrationDeadZoneMax( inElementRef ) - // - // Purpose: get the maximum bounds near the midpoint of a logical value in which the value is ignored - // - // Inputs: inElementRef - the IOHIDElementRef for this element - // - // Returns: CFIndex - the maximum Calibration value for this element - // - - extern CFIndex IOHIDElement_GetCalibrationDeadZoneMax(IOHIDElementRef inElementRef); - - //************************************************************************* - // - // IOHIDElement_SetCalibrationDeadZoneMax( inElementRef, inValue ) - // - // Purpose: set the maximum bounds near the midpoint of a logical value in which the value is ignored - // - // Inputs: inElementRef - the IOHIDElementRef for this element - // inValue - the maximum Calibration value for this element - // - // Returns: nothing - // - - extern void IOHIDElement_SetCalibrationDeadZoneMax(IOHIDElementRef inElementRef, CFIndex inValue); - - //************************************************************************* - // - // IOHIDElement_GetCalibrationGranularity( inElementRef ) - // - // Purpose: get the level of detail returned for a calibrated element value - // - // Inputs: inElementRef - the IOHIDElementRef for this element - // - // Returns: double_t - the maximum Calibration value for this element - // - - extern double_t IOHIDElement_GetCalibrationGranularity(IOHIDElementRef inElementRef); - - //************************************************************************* - // - // IOHIDElement_SetCalibrationGranularity( inElementRef, inValue ) - // - // Purpose: set the level of detail returned for a calibrated element value - // - // Inputs: inElementRef - the IOHIDElementRef for this element - // inValue - the the level of detail for this element - // - // Returns: nothing - // - - extern void IOHIDElement_SetCalibrationGranularity(IOHIDElementRef inElementRef, double_t inValue); - - //************************************************************************* - // - // IOHIDElement_SetupCalibration( inElementRef ) - // - // Purpose: set default values for the element calibration parameters - // - // Inputs: inElementRef - the IOHIDElementRef for this element - // - // Returns: nothing - // - - extern void IOHIDElement_SetupCalibration(IOHIDElementRef inIOHIDElementRef); - - extern Boolean IOHIDElement_GetLongProperty(IOHIDElementRef inElementRef, CFStringRef inKey, long *outValue); - extern void IOHIDElement_SetLongProperty(IOHIDElementRef inElementRef, CFStringRef inKey, long inValue); - - //***************************************************** -#if PRAGMA_STRUCT_ALIGN -#pragma options align=reset -#elif PRAGMA_STRUCT_PACKPUSH -#pragma pack(pop) -#elif PRAGMA_STRUCT_PACK -#pragma pack() -#endif - -#ifdef PRAGMA_IMPORT_OFF -#pragma import off -#elif PRAGMA_IMPORT -#pragma import reset -#endif - -#ifdef __cplusplus -} -#endif - -#endif // __IOHIDElement___ // diff --git a/src/cocoa/IOHIDLib_.h b/src/cocoa/IOHIDLib_.h deleted file mode 100644 index 38c6248ac..000000000 --- a/src/cocoa/IOHIDLib_.h +++ /dev/null @@ -1,111 +0,0 @@ -// File: IOHIDLib_.h -// Abstract: Single include file for all header files of IOHIDLib -// Version: 2.0 -// -// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple -// Inc. ("Apple") in consideration of your agreement to the following -// terms, and your use, installation, modification or redistribution of -// this Apple software constitutes acceptance of these terms. If you do -// not agree with these terms, please do not use, install, modify or -// redistribute this Apple software. -// -// In consideration of your agreement to abide by the following terms, and -// subject to these terms, Apple grants you a personal, non-exclusive -// license, under Apple's copyrights in this original Apple software (the -// "Apple Software"), to use, reproduce, modify and redistribute the Apple -// Software, with or without modifications, in source and/or binary forms; -// provided that if you redistribute the Apple Software in its entirety and -// without modifications, you must retain this notice and the following -// text and disclaimers in all such redistributions of the Apple Software. -// Neither the name, trademarks, service marks or logos of Apple Inc. may -// be used to endorse or promote products derived from the Apple Software -// without specific prior written permission from Apple. Except as -// expressly stated in this notice, no other rights or licenses, express or -// implied, are granted by Apple herein, including but not limited to any -// patent rights that may be infringed by your derivative works or by other -// works in which the Apple Software may be incorporated. -// -// The Apple Software is provided by Apple on an "AS IS" basis. APPLE -// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION -// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS -// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND -// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. -// -// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL -// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, -// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED -// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), -// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Copyright (C) 2009 Apple Inc. All Rights Reserved. -// -//***************************************************** -#ifndef __IOHIDLib___ -#define __IOHIDLib___ - -//***************************************************** -#pragma mark - includes & imports -//----------------------------------------------------- -#include - -#include "IOHIDDevice_.h" -#include "IOHIDElement_.h" - -#include "ImmrHIDUtilAddOn.h" - -//***************************************************** -#if PRAGMA_ONCE -#pragma once -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if PRAGMA_IMPORT -#pragma import on -#endif - -#if PRAGMA_STRUCT_ALIGN -#pragma options align=mac68k -#elif PRAGMA_STRUCT_PACKPUSH -#pragma pack(push, 2) -#elif PRAGMA_STRUCT_PACK -#pragma pack(2) -#endif - - //***************************************************** -#pragma mark - typedef's, struct's, enums, defines, etc. - //----------------------------------------------------- - - //***************************************************** -#pragma mark - exported globals - //----------------------------------------------------- - - //***************************************************** -#pragma mark - exported function prototypes - //----------------------------------------------------- - - //***************************************************** -#if PRAGMA_STRUCT_ALIGN -#pragma options align=reset -#elif PRAGMA_STRUCT_PACKPUSH -#pragma pack(pop) -#elif PRAGMA_STRUCT_PACK -#pragma pack() -#endif - -#ifdef PRAGMA_IMPORT_OFF -#pragma import off -#elif PRAGMA_IMPORT -#pragma import reset -#endif - -#ifdef __cplusplus -} -#endif - -#endif // __IOHIDLib___ diff --git a/src/cocoa/ImmrHIDUtilAddOn.c b/src/cocoa/ImmrHIDUtilAddOn.c deleted file mode 100644 index 4937d3687..000000000 --- a/src/cocoa/ImmrHIDUtilAddOn.c +++ /dev/null @@ -1,108 +0,0 @@ -// File: ImmrHIDUtilAddOn.c -// Abstract: Glue code to convert IOHIDDeviceRef's to (FFB) io_object_t's -// Version: 2.0 -// -// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple -// Inc. ("Apple") in consideration of your agreement to the following -// terms, and your use, installation, modification or redistribution of -// this Apple software constitutes acceptance of these terms. If you do -// not agree with these terms, please do not use, install, modify or -// redistribute this Apple software. -// -// In consideration of your agreement to abide by the following terms, and -// subject to these terms, Apple grants you a personal, non-exclusive -// license, under Apple's copyrights in this original Apple software (the -// "Apple Software"), to use, reproduce, modify and redistribute the Apple -// Software, with or without modifications, in source and/or binary forms; -// provided that if you redistribute the Apple Software in its entirety and -// without modifications, you must retain this notice and the following -// text and disclaimers in all such redistributions of the Apple Software. -// Neither the name, trademarks, service marks or logos of Apple Inc. may -// be used to endorse or promote products derived from the Apple Software -// without specific prior written permission from Apple. Except as -// expressly stated in this notice, no other rights or licenses, express or -// implied, are granted by Apple herein, including but not limited to any -// patent rights that may be infringed by your derivative works or by other -// works in which the Apple Software may be incorporated. -// -// The Apple Software is provided by Apple on an "AS IS" basis. APPLE -// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION -// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS -// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND -// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. -// -// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL -// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, -// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED -// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), -// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Copyright (C) 2009 Apple Inc. All Rights Reserved. -// -//***************************************************** - -#include - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 - -#include -#include - -#include "ImmrHIDUtilAddOn.h" - -//--------------------------------------------------------------------------------- -// -// AllocateHIDObjectFromIOHIDDeviceRef( ) -// -// returns: -// NULL, or acceptable io_object_t -// -//--------------------------------------------------------------------------------- -io_service_t AllocateHIDObjectFromIOHIDDeviceRef(IOHIDDeviceRef inIOHIDDeviceRef) { - io_service_t result = 0L; - if ( inIOHIDDeviceRef ) { - // Set up the matching criteria for the devices we're interested in. - // We are interested in instances of class IOHIDDevice. - // matchingDict is consumed below( in IOServiceGetMatchingService ) - // so we have no leak here. - CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOHIDDeviceKey); - if ( matchingDict ) { - // Add a key for locationID to our matching dictionary. This works for matching to - // IOHIDDevices, so we will only look for a device attached to that particular port - // on the machine. - CFTypeRef tCFTypeRef = IOHIDDeviceGetProperty( inIOHIDDeviceRef, CFSTR(kIOHIDLocationIDKey) ); - if ( tCFTypeRef ) { - CFDictionaryAddValue(matchingDict, CFSTR(kIOHIDLocationIDKey), tCFTypeRef); - // CFRelease( tCFTypeRef ); // don't release objects that we "Get". - - // IOServiceGetMatchingService assumes that we already know that there is only one device - // that matches. This way we don't have to do the whole iteration dance to look at each - // device that matches. This is a new API in 10.2 - result = IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict); - } - - // Note: We're not leaking the matchingDict. - // One reference is consumed by IOServiceGetMatchingServices - } - } - - return (result); -} // AllocateHIDObjectFromIOHIDDeviceRef - -//--------------------------------------------------------------------------------- -// -// FreeHIDObject( ) -// -//--------------------------------------------------------------------------------- -bool FreeHIDObject(io_service_t inHIDObject) { - kern_return_t kr; - - kr = IOObjectRelease(inHIDObject); - - return (kIOReturnSuccess == kr); -} // FreeHIDObject - -#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 diff --git a/src/cocoa/ImmrHIDUtilAddOn.h b/src/cocoa/ImmrHIDUtilAddOn.h deleted file mode 100644 index 72de752e3..000000000 --- a/src/cocoa/ImmrHIDUtilAddOn.h +++ /dev/null @@ -1,50 +0,0 @@ -// File: ImmrHIDUtilAddOn.h -// Abstract: Glue code to convert IOHIDDeviceRef's to (FFB) io_object_t's -// Version: 2.0 -// -// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple -// Inc. ("Apple") in consideration of your agreement to the following -// terms, and your use, installation, modification or redistribution of -// this Apple software constitutes acceptance of these terms. If you do -// not agree with these terms, please do not use, install, modify or -// redistribute this Apple software. -// -// In consideration of your agreement to abide by the following terms, and -// subject to these terms, Apple grants you a personal, non-exclusive -// license, under Apple's copyrights in this original Apple software (the -// "Apple Software"), to use, reproduce, modify and redistribute the Apple -// Software, with or without modifications, in source and/or binary forms; -// provided that if you redistribute the Apple Software in its entirety and -// without modifications, you must retain this notice and the following -// text and disclaimers in all such redistributions of the Apple Software. -// Neither the name, trademarks, service marks or logos of Apple Inc. may -// be used to endorse or promote products derived from the Apple Software -// without specific prior written permission from Apple. Except as -// expressly stated in this notice, no other rights or licenses, express or -// implied, are granted by Apple herein, including but not limited to any -// patent rights that may be infringed by your derivative works or by other -// works in which the Apple Software may be incorporated. -// -// The Apple Software is provided by Apple on an "AS IS" basis. APPLE -// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION -// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS -// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND -// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. -// -// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL -// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, -// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED -// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), -// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Copyright (C) 2009 Apple Inc. All Rights Reserved. -// -//***************************************************** -#include -#include - -extern io_service_t AllocateHIDObjectFromIOHIDDeviceRef(IOHIDDeviceRef inIOHIDDeviceRef); -extern bool FreeHIDObject(io_object_t inHIDObject); diff --git a/src/cocoa/i_backend_cocoa.mm b/src/cocoa/i_backend_cocoa.mm deleted file mode 100644 index 9085d92db..000000000 --- a/src/cocoa/i_backend_cocoa.mm +++ /dev/null @@ -1,2179 +0,0 @@ -/* - ** i_backend_cocoa.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 -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -// Avoid collision between DObject class and Objective-C -#define Class ObjectClass - -#include "bitmap.h" -#include "c_console.h" -#include "c_dispatch.h" -#include "cmdlib.h" -#include "d_event.h" -#include "d_gui.h" -#include "dikeys.h" -#include "doomdef.h" -#include "doomstat.h" -#include "s_sound.h" -#include "textures.h" -#include "v_video.h" -#include "version.h" -#include "i_rbopts.h" -#include "i_osversion.h" - -#undef Class - - -#define ZD_UNUSED(VARIABLE) ((void)(VARIABLE)) - - -// --------------------------------------------------------------------------- - - -// 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 - - -// --------------------------------------------------------------------------- - - -RenderBufferOptions rbOpts; - -EXTERN_CVAR(Bool, fullscreen) -EXTERN_CVAR(Bool, vid_hidpi) - -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; - } -} - -bool GUICapture; - - -extern int paused, chatmodeon; -extern constate_e ConsoleState; - -EXTERN_CVAR(Int, m_use_mouse); - -void I_ShutdownJoysticks(); - - -namespace -{ - -const int ARGC_MAX = 64; - -int s_argc; -char* s_argv[ARGC_MAX]; - -TArray s_argvStorage; - -bool s_restartedFromWADPicker; - - -bool s_nativeMouse = true; - -// TODO: remove this magic! -size_t s_skipMouseMoves; - -NSCursor* s_cursor; - - -void CheckGUICapture() -{ - const bool wantCapture = (MENU_Off == menuactive) - ? (c_down == ConsoleState || c_falling == ConsoleState || chatmodeon) - : (menuactive == MENU_On || menuactive == MENU_OnNoPause); - - 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 SetNativeMouse(bool wantNative) -{ - if (wantNative != s_nativeMouse) - { - s_nativeMouse = wantNative; - - if (!wantNative) - { - CenterCursor(); - } - - CGAssociateMouseAndMouseCursorPosition(wantNative); - - if (wantNative) - { - [NSCursor unhide]; - } - else - { - [NSCursor hide]; - } - } -} - -void CheckNativeMouse() -{ - 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); - } - - SetNativeMouse(wantNative); -} - -} // unnamed namespace - - -// see cocoa/i_joystick.cpp -void I_ProcessJoysticks(); - - -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() -{ - -} - - -// --------------------------------------------------------------------------- - - -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); -} - -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); -} - -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([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 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); - } - } -} - - -bool 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; -} - -NSSize GetRealContentViewSize(const NSWindow* const window) -{ - const NSView* view = [window contentView]; - const NSSize frameSize = [view frame].size; - - // TODO: figure out why [NSView frame] returns different values in "fullscreen" and in window - // In "fullscreen" the result is multiplied by [NSScreen backingScaleFactor], but not in window - - return (vid_hidpi && !fullscreen) - ? [view convertSizeToBacking:frameSize] - : frameSize; -} - - -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 = IsHiDPISupported() - ? [view convertPointToBacking:windowPos] - : [view convertPoint:windowPos fromView:nil]; - - const CGFloat frameHeight = GetRealContentViewSize(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 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 = std::min(KEY_MOUSE1 + [theEvent buttonNumber], NSInteger(KEY_MOUSE8)); - - D_PostEvent(&event); - } -} - - -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 ProcessMouseMoveEvent(NSEvent* theEvent) -{ - if (GUICapture) - { - ProcessMouseMoveInMenu(theEvent); - } - else - { - ProcessMouseMoveInGame(theEvent); - } -} - - -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); -} - - -const Uint16 BYTES_PER_PIXEL = 4; - -} // unnamed namespace - - -// --------------------------------------------------------------------------- - - -namespace -{ - const NSInteger LEVEL_FULLSCREEN = NSMainMenuWindowLevel + 1; - const NSInteger LEVEL_WINDOWED = NSNormalWindowLevel; - - const NSUInteger STYLE_MASK_FULLSCREEN = NSBorderlessWindowMask; - const NSUInteger STYLE_MASK_WINDOWED = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask; -} - - -// --------------------------------------------------------------------------- - - -@interface FullscreenWindow : NSWindow -{ - -} - -- (bool)canBecomeKeyWindow; - -- (void)setLevel:(NSInteger)level; -- (void)setStyleMask:(NSUInteger)styleMask; - -@end - - -// --------------------------------------------------------------------------- - - -@interface FullscreenView : NSOpenGLView -{ - -} - -- (void)resetCursorRects; - -@end - - -@implementation FullscreenView - -- (void)resetCursorRects -{ - [super resetCursorRects]; - [self addCursorRect: [self bounds] - cursor: s_cursor]; -} - -@end - - -// --------------------------------------------------------------------------- - - -@interface ApplicationController : NSResponder -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 - -#endif -{ -@private - FullscreenWindow* m_window; - - uint8_t* m_softwareRenderingBuffer; - GLuint m_softwareRenderingTexture; - - int m_multisample; - - int m_width; - int m_height; - bool m_fullscreen; - bool m_hiDPI; - - bool m_openGLInitialized; -} - -- (id)init; -- (void)dealloc; - -- (void)keyDown:(NSEvent*)theEvent; -- (void)keyUp:(NSEvent*)theEvent; - -- (void)applicationDidBecomeActive:(NSNotification*)aNotification; -- (void)applicationWillResignActive:(NSNotification*)aNotification; - -- (void)applicationDidFinishLaunching:(NSNotification*)aNotification; - -- (void)applicationWillTerminate:(NSNotification*)aNotification; - -- (BOOL)application:(NSApplication*)theApplication openFile:(NSString*)filename; - -- (int)multisample; -- (void)setMultisample:(int)multisample; - -- (void)changeVideoResolution:(bool)fullscreen width:(int)width height:(int)height useHiDPI:(bool)hiDPI; -- (void)useHiDPI:(bool)hiDPI; - -- (void)setupSoftwareRenderingWithWidth:(int)width height:(int)height; -- (void*)softwareRenderingBuffer; - -- (void)processEvents:(NSTimer*)timer; - -- (void)invalidateCursorRects; - -- (void)setMainWindowVisible:(bool)visible; - -- (void)setWindowStyleMask:(NSUInteger)styleMask; - -@end - - -static ApplicationController* appCtrl; - - -// --------------------------------------------------------------------------- - - -@implementation FullscreenWindow - -static bool s_fullscreenNewAPI; - -+ (void)initialize -{ - // The following value shoud be equal to NSAppKitVersionNumber10_6 - // and it's hard-coded in order to build on earlier SDKs - s_fullscreenNewAPI = NSAppKitVersionNumber >= 1038; -} - -- (bool)canBecomeKeyWindow -{ - return true; -} - -- (void)setLevel:(NSInteger)level -{ - if (s_fullscreenNewAPI) - { - [super setLevel:level]; - } - else - { - // Old Carbon-based way to make fullscreen window above dock and menu - // It's supported on 64-bit, but on 10.6 and later the following is preferred: - // [NSWindow setLevel:NSMainMenuWindowLevel + 1] - - const SystemUIMode mode = LEVEL_FULLSCREEN == level - ? kUIModeAllHidden - : kUIModeNormal; - SetSystemUIMode(mode, 0); - } -} - -- (void)setStyleMask:(NSUInteger)styleMask -{ - if (s_fullscreenNewAPI) - { - [super setStyleMask:styleMask]; - } - else - { - [appCtrl setWindowStyleMask:styleMask]; - } -} - -@end - - -// --------------------------------------------------------------------------- - - -@implementation ApplicationController - -- (id)init -{ - self = [super init]; - - m_window = nil; - - m_softwareRenderingBuffer = NULL; - m_softwareRenderingTexture = 0; - - m_multisample = 0; - - m_width = -1; - m_height = -1; - m_fullscreen = false; - m_hiDPI = false; - - m_openGLInitialized = false; - - return self; -} - -- (void)dealloc -{ - delete[] m_softwareRenderingBuffer; - - glBindTexture(GL_TEXTURE_2D, 0); - glDeleteTextures(1, &m_softwareRenderingTexture); - - [m_window release]; - - [super dealloc]; -} - - -- (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(SDL_main(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)applicationWillTerminate:(NSNotification*)aNotification -{ - ZD_UNUSED(aNotification); - - // Hide window as nothing will be rendered at this point - [m_window orderOut:nil]; - - I_ShutdownJoysticks(); -} - - -- (int)multisample -{ - return m_multisample; -} - -- (void)setMultisample:(int)multisample -{ - m_multisample = multisample; -} - - -- (FullscreenWindow*)createWindow:(NSUInteger)styleMask -{ - FullscreenWindow* window = [[FullscreenWindow alloc] initWithContentRect:NSMakeRect(0, 0, 640, 480) - styleMask:styleMask - backing:NSBackingStoreBuffered - defer:NO]; - [window setOpaque:YES]; - [window makeFirstResponder:self]; - [window setAcceptsMouseMovedEvents:YES]; - - return window; -} - -- (void)initializeOpenGL -{ - if (m_openGLInitialized) - { - return; - } - - m_window = [self createWindow:STYLE_MASK_WINDOWED]; - - // Create OpenGL context and view - - NSOpenGLPixelFormatAttribute attributes[16]; - size_t i = 0; - - attributes[i++] = NSOpenGLPFADoubleBuffer; - attributes[i++] = NSOpenGLPFAColorSize; - attributes[i++] = NSOpenGLPixelFormatAttribute(32); - attributes[i++] = NSOpenGLPFADepthSize; - attributes[i++] = NSOpenGLPixelFormatAttribute(24); - attributes[i++] = NSOpenGLPFAStencilSize; - attributes[i++] = NSOpenGLPixelFormatAttribute(8); - - if (m_multisample) - { - attributes[i++] = NSOpenGLPFAMultisample; - attributes[i++] = NSOpenGLPFASampleBuffers; - attributes[i++] = NSOpenGLPixelFormatAttribute(1); - attributes[i++] = NSOpenGLPFASamples; - attributes[i++] = NSOpenGLPixelFormatAttribute(m_multisample); - } - - attributes[i] = NSOpenGLPixelFormatAttribute(0); - - NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; - - const NSRect contentRect = [m_window contentRectForFrameRect:[m_window frame]]; - NSOpenGLView* glView = [[FullscreenView alloc] initWithFrame:contentRect - pixelFormat:pixelFormat]; - [[glView openGLContext] makeCurrentContext]; - - [m_window setContentView:glView]; - - m_openGLInitialized = true; -} - -- (void)setFullscreenModeWidth:(int)width height:(int)height -{ - NSScreen* screen = [m_window screen]; - - const NSRect screenFrame = [screen frame]; - const NSRect displayRect = vid_hidpi - ? [screen convertRectToBacking:screenFrame] - : screenFrame; - - const float displayWidth = displayRect.size.width; - const float displayHeight = displayRect.size.height; - - const float pixelScaleFactorX = displayWidth / static_cast(width ); - const float pixelScaleFactorY = displayHeight / static_cast(height); - - rbOpts.pixelScale = std::min(pixelScaleFactorX, pixelScaleFactorY); - - rbOpts.width = width * rbOpts.pixelScale; - rbOpts.height = height * rbOpts.pixelScale; - - rbOpts.shiftX = (displayWidth - rbOpts.width ) / 2.0f; - rbOpts.shiftY = (displayHeight - rbOpts.height) / 2.0f; - - if (!m_fullscreen) - { - [m_window setLevel:LEVEL_FULLSCREEN]; - [m_window setStyleMask:STYLE_MASK_FULLSCREEN]; - [m_window setHidesOnDeactivate:YES]; - } - - [m_window setFrame:displayRect display:YES]; - [m_window setFrameOrigin:NSMakePoint(0.0f, 0.0f)]; -} - -- (void)setWindowedModeWidth:(int)width height:(int)height -{ - rbOpts.pixelScale = 1.0f; - - rbOpts.width = static_cast(width ); - rbOpts.height = static_cast(height); - - rbOpts.shiftX = 0.0f; - rbOpts.shiftY = 0.0f; - - const NSSize windowPixelSize = NSMakeSize(width, height); - const NSSize windowSize = vid_hidpi - ? [[m_window contentView] convertSizeFromBacking:windowPixelSize] - : windowPixelSize; - - if (m_fullscreen) - { - [m_window setLevel:LEVEL_WINDOWED]; - [m_window setStyleMask:STYLE_MASK_WINDOWED]; - [m_window setHidesOnDeactivate:NO]; - } - - [m_window setContentSize:windowSize]; - [m_window center]; - - NSButton* closeButton = [m_window standardWindowButton:NSWindowCloseButton]; - [closeButton setAction:@selector(terminate:)]; - [closeButton setTarget:NSApp]; -} - -- (void)changeVideoResolution:(bool)fullscreen width:(int)width height:(int)height useHiDPI:(bool)hiDPI -{ - if (fullscreen == m_fullscreen - && width == m_width - && height == m_height - && hiDPI == m_hiDPI) - { - return; - } - - [self initializeOpenGL]; - - if (IsHiDPISupported()) - { - NSOpenGLView* const glView = [m_window contentView]; - [glView setWantsBestResolutionOpenGLSurface:hiDPI]; - } - - if (fullscreen) - { - [self setFullscreenModeWidth:width height:height]; - } - else - { - [self setWindowedModeWidth:width height:height]; - } - - rbOpts.dirty = true; - - const NSSize viewSize = GetRealContentViewSize(m_window); - - glViewport(0, 0, static_cast(viewSize.width), static_cast(viewSize.height)); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - - CGLFlushDrawable(CGLGetCurrentContext()); - - static NSString* const TITLE_STRING = - [NSString stringWithFormat:@"%s %s", GAMESIG, GetVersionString()]; - [m_window setTitle:TITLE_STRING]; - - if (![m_window isKeyWindow]) - { - [m_window makeKeyAndOrderFront:nil]; - } - - m_fullscreen = fullscreen; - m_width = width; - m_height = height; - m_hiDPI = hiDPI; -} - -- (void)useHiDPI:(bool)hiDPI -{ - if (!m_openGLInitialized) - { - return; - } - - [self changeVideoResolution:m_fullscreen - width:m_width - height:m_height - useHiDPI:hiDPI]; -} - - -- (void)setupSoftwareRenderingWithWidth:(int)width height:(int)height -{ - if (0 == m_softwareRenderingTexture) - { - glEnable(GL_TEXTURE_RECTANGLE_ARB); - - glGenTextures(1, &m_softwareRenderingTexture); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_softwareRenderingTexture); - glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); - - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - - delete[] m_softwareRenderingBuffer; - m_softwareRenderingBuffer = new uint8_t[width * height * BYTES_PER_PIXEL]; - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0.0, width, height, 0.0, -1.0, 1.0); -} - -- (void*)softwareRenderingBuffer -{ - return m_softwareRenderingBuffer; -} - - -- (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; - } - - 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; - } - - [NSApp sendEvent:event]; - } - - [NSApp updateWindows]; - - [pool release]; -} - - -- (void)invalidateCursorRects -{ - [m_window invalidateCursorRectsForView:[m_window contentView]]; -} - - -- (void)setMainWindowVisible:(bool)visible -{ - if (visible) - { - [m_window orderFront:nil]; - } - else - { - [m_window orderOut:nil]; - } -} - - -- (void)setWindowStyleMask:(NSUInteger)styleMask -{ - // Before 10.6 it's impossible to change window's style mask - // To workaround this new window should be created with required style mask - // This method should not be called when building for Snow Leopard or newer - - FullscreenWindow* tempWindow = [self createWindow:styleMask]; - [tempWindow setContentView:[m_window contentView]]; - - [m_window close]; - m_window = tempWindow; -} - -@end - - -// --------------------------------------------------------------------------- - - -CUSTOM_CVAR(Bool, vid_hidpi, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -{ - if (IsHiDPISupported()) - { - [appCtrl useHiDPI:self]; - } - else if (0 != self) - { - self = 0; - } -} - - -// --------------------------------------------------------------------------- - - -void I_SetMainWindowVisible(bool visible) -{ - [appCtrl setMainWindowVisible:visible]; - - SetNativeMouse(!visible); -} - - -// --------------------------------------------------------------------------- - - -bool I_SetCursor(FTexture* cursorpic) -{ - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - - if (NULL == cursorpic || FTexture::TEX_Null == cursorpic->UseType) - { - s_cursor = [NSCursor arrowCursor]; - } - else - { - // Create bitmap image representation - - const NSInteger imageWidth = cursorpic->GetWidth(); - const NSInteger imageHeight = cursorpic->GetHeight(); - const NSInteger imagePitch = imageWidth * 4; - - NSBitmapImageRep* bitmapImageRep = [NSBitmapImageRep alloc]; - [bitmapImageRep initWithBitmapDataPlanes:NULL - pixelsWide:imageWidth - pixelsHigh:imageHeight - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:imagePitch - bitsPerPixel:0]; - - // Load bitmap data to representation - - BYTE* buffer = [bitmapImageRep bitmapData]; - memset(buffer, 0, imagePitch * imageHeight); - - FBitmap bitmap(buffer, imagePitch, imageWidth, imageHeight); - cursorpic->CopyTrueColorPixels(&bitmap, 0, 0); - - // Swap red and blue components in each pixel - - for (size_t i = 0; i < size_t(imageWidth * imageHeight); ++i) - { - const size_t offset = i * 4; - - const BYTE temp = buffer[offset ]; - buffer[offset ] = buffer[offset + 2]; - buffer[offset + 2] = temp; - } - - // Create image from representation and set it as cursor - - NSData* imageData = [bitmapImageRep representationUsingType:NSPNGFileType - properties:nil]; - NSImage* cursorImage = [[NSImage alloc] initWithData:imageData]; - - s_cursor = [[NSCursor alloc] initWithImage:cursorImage - hotSpot:NSMakePoint(0.0f, 0.0f)]; - } - - [appCtrl invalidateCursorRects]; - - [pool release]; - - return true; -} - - -// --------------------------------------------------------------------------- - - -const char* I_GetBackEndName() -{ - return "Native Cocoa"; -} - - -FString OSX_FindApplicationSupport() -{ - NSURL *url = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:nil]; - if(url == nil) - return FString(); - return [[url path] UTF8String]; -} - -// --------------------------------------------------------------------------- - - -extern "C" -{ - -struct SDL_mutex -{ - pthread_mutex_t mutex; -}; - - -SDL_mutex* SDL_CreateMutex() -{ - pthread_mutexattr_t attributes; - pthread_mutexattr_init(&attributes); - pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE); - - SDL_mutex* result = new SDL_mutex; - - if (0 != pthread_mutex_init(&result->mutex, &attributes)) - { - delete result; - result = NULL; - } - - pthread_mutexattr_destroy(&attributes); - - return result; -} - -int SDL_mutexP(SDL_mutex* mutex) -{ - return pthread_mutex_lock(&mutex->mutex); -} - -int SDL_mutexV(SDL_mutex* mutex) -{ - return pthread_mutex_unlock(&mutex->mutex); -} - -void SDL_DestroyMutex(SDL_mutex* mutex) -{ - pthread_mutex_destroy(&mutex->mutex); - delete mutex; -} - - -static timeval s_startTicks; - -uint32_t SDL_GetTicks() -{ - timeval now; - gettimeofday(&now, NULL); - - const uint32_t ticks = - (now.tv_sec - s_startTicks.tv_sec ) * 1000 - + (now.tv_usec - s_startTicks.tv_usec) / 1000; - - return ticks; -} - - -int SDL_Init(Uint32 flags) -{ - ZD_UNUSED(flags); - - return 0; -} - -void SDL_Quit() -{ - if (NULL != appCtrl) - { - [NSApp setDelegate:nil]; - [NSApp deactivate]; - - [appCtrl release]; - appCtrl = NULL; - } -} - - -char* SDL_GetError() -{ - static char empty[] = {0}; - return empty; -} - - -char* SDL_VideoDriverName(char* namebuf, int maxlen) -{ - return strncpy(namebuf, "Native OpenGL", maxlen); -} - -const SDL_VideoInfo* SDL_GetVideoInfo() -{ - // NOTE: Only required fields are assigned - - static SDL_PixelFormat pixelFormat; - memset(&pixelFormat, 0, sizeof(pixelFormat)); - - pixelFormat.BitsPerPixel = 32; - - static SDL_VideoInfo videoInfo; - memset(&videoInfo, 0, sizeof(videoInfo)); - - const NSRect displayRect = [[NSScreen mainScreen] frame]; - - videoInfo.current_w = displayRect.size.width; - videoInfo.current_h = displayRect.size.height; - videoInfo.vfmt = &pixelFormat; - - return &videoInfo; -} - -SDL_Rect** SDL_ListModes(SDL_PixelFormat* format, Uint32 flags) -{ - ZD_UNUSED(format); - ZD_UNUSED(flags); - - static std::vector resolutions; - - if (resolutions.empty()) - { -#define DEFINE_RESOLUTION(WIDTH, HEIGHT) \ - static SDL_Rect resolution_##WIDTH##_##HEIGHT = { 0, 0, WIDTH, HEIGHT }; \ - resolutions.push_back(&resolution_##WIDTH##_##HEIGHT); - - DEFINE_RESOLUTION( 640, 480); - DEFINE_RESOLUTION( 720, 480); - DEFINE_RESOLUTION( 800, 480); - DEFINE_RESOLUTION( 800, 600); - DEFINE_RESOLUTION(1024, 600); - DEFINE_RESOLUTION(1024, 640); - DEFINE_RESOLUTION(1024, 768); - DEFINE_RESOLUTION(1152, 720); - DEFINE_RESOLUTION(1152, 864); - DEFINE_RESOLUTION(1280, 720); - DEFINE_RESOLUTION(1280, 768); - DEFINE_RESOLUTION(1280, 800); - DEFINE_RESOLUTION(1280, 854); - DEFINE_RESOLUTION(1280, 960); - DEFINE_RESOLUTION(1280, 1024); - DEFINE_RESOLUTION(1366, 768); - DEFINE_RESOLUTION(1400, 1050); - DEFINE_RESOLUTION(1440, 900); - DEFINE_RESOLUTION(1440, 960); - DEFINE_RESOLUTION(1440, 1080); - DEFINE_RESOLUTION(1600, 900); - DEFINE_RESOLUTION(1600, 1200); - DEFINE_RESOLUTION(1680, 1050); - DEFINE_RESOLUTION(1920, 1080); - DEFINE_RESOLUTION(1920, 1200); - DEFINE_RESOLUTION(2048, 1080); - DEFINE_RESOLUTION(2048, 1536); - DEFINE_RESOLUTION(2560, 1080); - DEFINE_RESOLUTION(2560, 1440); - DEFINE_RESOLUTION(2560, 1600); - DEFINE_RESOLUTION(2560, 2048); - DEFINE_RESOLUTION(2880, 1800); - DEFINE_RESOLUTION(3200, 1800); - DEFINE_RESOLUTION(3440, 1440); - DEFINE_RESOLUTION(3840, 2160); - DEFINE_RESOLUTION(3840, 2400); - DEFINE_RESOLUTION(4096, 2160); - DEFINE_RESOLUTION(5120, 2880); - -#undef DEFINE_RESOLUTION - - resolutions.push_back(NULL); - } - - return &resolutions[0]; -} - -int SDL_ShowCursor(int) -{ - // Does nothing - return 0; -} - - -static SDL_PixelFormat* GetPixelFormat() -{ - static SDL_PixelFormat result; - - result.palette = NULL; - result.BitsPerPixel = BYTES_PER_PIXEL * 8; - result.BytesPerPixel = BYTES_PER_PIXEL; - result.Rloss = 0; - result.Gloss = 0; - result.Bloss = 0; - result.Aloss = 8; - result.Rshift = 8; - result.Gshift = 16; - result.Bshift = 24; - result.Ashift = 0; - result.Rmask = 0x000000FF; - result.Gmask = 0x0000FF00; - result.Bmask = 0x00FF0000; - result.Amask = 0xFF000000; - result.colorkey = 0; - result.alpha = 0xFF; - - return &result; -} - - -SDL_Surface* SDL_SetVideoMode(int width, int height, int, Uint32 flags) -{ - [appCtrl changeVideoResolution:(SDL_FULLSCREEN & flags) - width:width - height:height - useHiDPI:vid_hidpi]; - - static SDL_Surface result; - - if (!(SDL_OPENGL & flags)) - { - [appCtrl setupSoftwareRenderingWithWidth:width - height:height]; - } - - result.flags = flags; - result.format = GetPixelFormat(); - result.w = width; - result.h = height; - result.pitch = width * BYTES_PER_PIXEL; - result.pixels = [appCtrl softwareRenderingBuffer]; - result.refcount = 1; - - result.clip_rect.x = 0; - result.clip_rect.y = 0; - result.clip_rect.w = width; - result.clip_rect.h = height; - - return &result; -} - - -void SDL_WM_SetCaption(const char* title, const char* icon) -{ - ZD_UNUSED(title); - ZD_UNUSED(icon); - - // Window title is set in SDL_SetVideoMode() -} - -int SDL_WM_ToggleFullScreen(SDL_Surface* surface) -{ - if (surface->flags & SDL_FULLSCREEN) - { - surface->flags &= ~SDL_FULLSCREEN; - } - else - { - surface->flags |= SDL_FULLSCREEN; - } - - [appCtrl changeVideoResolution:(SDL_FULLSCREEN & surface->flags) - width:surface->w - height:surface->h - useHiDPI:vid_hidpi]; - - return 1; -} - - -void SDL_GL_SwapBuffers() -{ - [[NSOpenGLContext currentContext] flushBuffer]; -} - -int SDL_GL_SetAttribute(SDL_GLattr attr, int value) -{ - if (SDL_GL_MULTISAMPLESAMPLES == attr) - { - [appCtrl setMultisample:value]; - } - - // Not interested in other attributes - - return 0; -} - - -int SDL_LockSurface(SDL_Surface* surface) -{ - ZD_UNUSED(surface); - - return 0; -} - -void SDL_UnlockSurface(SDL_Surface* surface) -{ - ZD_UNUSED(surface); -} - -int SDL_BlitSurface(SDL_Surface* src, SDL_Rect* srcrect, SDL_Surface* dst, SDL_Rect* dstrect) -{ - ZD_UNUSED(src); - ZD_UNUSED(srcrect); - ZD_UNUSED(dst); - ZD_UNUSED(dstrect); - - return 0; -} - - -int SDL_Flip(SDL_Surface* screen) -{ - assert(NULL != screen); - - if (rbOpts.dirty) - { - glViewport(rbOpts.shiftX, rbOpts.shiftY, rbOpts.width, rbOpts.height); - - // TODO: Figure out why the following glClear() call is needed - // to avoid drawing of garbage in fullscreen mode when - // in-game's aspect ratio is different from display one - glClear(GL_COLOR_BUFFER_BIT); - - rbOpts.dirty = false; - } - - const int width = screen->w; - const int height = screen->h; - -#ifdef __LITTLE_ENDIAN__ - static const GLenum format = GL_RGBA; -#else // __BIG_ENDIAN__ - static const GLenum format = GL_ABGR_EXT; -#endif // __LITTLE_ENDIAN__ - - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, - width, height, 0, format, GL_UNSIGNED_BYTE, screen->pixels); - - glBegin(GL_QUADS); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - glTexCoord2f(0.0f, 0.0f); - glVertex2f(0.0f, 0.0f); - glTexCoord2f(width, 0.0f); - glVertex2f(width, 0.0f); - glTexCoord2f(width, height); - glVertex2f(width, height); - glTexCoord2f(0.0f, height); - glVertex2f(0.0f, height); - glEnd(); - - glFlush(); - - SDL_GL_SwapBuffers(); - - return 0; -} - -int SDL_SetPalette(SDL_Surface* surface, int flags, SDL_Color* colors, int firstcolor, int ncolors) -{ - ZD_UNUSED(surface); - ZD_UNUSED(flags); - ZD_UNUSED(colors); - ZD_UNUSED(firstcolor); - ZD_UNUSED(ncolors); - - return 0; -} - -} // extern "C" - - -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(alloca(size)); - - if (0 == sysctl(mib, 2, version, &size, NULL, 0)) - { - sscanf(version, "%hu.%hu.%hu", - &result.major, &result.minor, &result.bugfix); - } - } - - return result; -} - -} // unnamed namespace - - -const DarwinVersion darwinVersion = GetDarwinVersion(); - - -#ifdef main -#undef main -#endif // main - -int main(int argc, char** argv) -{ - gettimeofday(&s_startTicks, NULL); - - 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(); - - appCtrl = [ApplicationController new]; - [NSApp setDelegate:appCtrl]; - - [NSApp run]; - - [pool release]; - - return EXIT_SUCCESS; -} diff --git a/src/cocoa/i_joystick.cpp b/src/cocoa/i_joystick.cpp deleted file mode 100644 index 9940c6ca8..000000000 --- a/src/cocoa/i_joystick.cpp +++ /dev/null @@ -1,830 +0,0 @@ -/* - ** i_joystick.cpp - ** - **--------------------------------------------------------------------------- - ** 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 "m_joy.h" - -#include - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 - -#include "HID_Utilities_External.h" - -#include "d_event.h" -#include "doomdef.h" -#include "templates.h" -#include "i_osversion.h" - - -namespace -{ - -FString ToFString( const CFStringRef string ) -{ - if ( NULL == string ) - { - return FString(); - } - - const CFIndex stringLength = CFStringGetLength( string ); - - if ( 0 == stringLength ) - { - return FString(); - } - - const size_t bufferSize = CFStringGetMaximumSizeForEncoding( stringLength, kCFStringEncodingUTF8 ) + 1; - - char buffer[ bufferSize ]; - memset( buffer, 0, bufferSize ); - - CFStringGetCString( string, buffer, bufferSize, kCFStringEncodingUTF8 ); - - return FString( buffer ); -} - - -class IOKitJoystick : public IJoystickConfig -{ -public: - explicit IOKitJoystick( IOHIDDeviceRef device ); - virtual ~IOKitJoystick(); - - virtual FString GetName(); - virtual float GetSensitivity(); - virtual void SetSensitivity( float scale ); - - virtual int GetNumAxes(); - virtual float GetAxisDeadZone( int axis ); - virtual EJoyAxis GetAxisMap( int axis ); - virtual const char* GetAxisName( int axis ); - virtual float GetAxisScale( int axis ); - - virtual void SetAxisDeadZone( int axis, float deadZone ); - virtual void SetAxisMap( int axis, EJoyAxis gameAxis ); - virtual void SetAxisScale( int axis, float scale ); - - virtual bool IsSensitivityDefault(); - virtual bool IsAxisDeadZoneDefault( int axis ); - virtual bool IsAxisMapDefault( int axis ); - virtual bool IsAxisScaleDefault( int axis ); - - virtual void SetDefaultConfig(); - virtual FString GetIdentifier(); - - void AddAxes( float axes[ NUM_JOYAXIS ] ) const; - - void Update(); - -private: - IOHIDDeviceRef m_device; - - float m_sensitivity; - - struct AxisInfo - { - char name[ 64 ]; - - float value; - - float deadZone; - float defaultDeadZone; - float sensitivity; - float defaultSensitivity; - - EJoyAxis gameAxis; - EJoyAxis defaultGameAxis; - - IOHIDElementRef element; - }; - - TArray< AxisInfo > m_axes; - - TArray< IOHIDElementRef > m_buttons; - TArray< IOHIDElementRef > m_POVs; - - - static const float DEFAULT_DEADZONE; - static const float DEFAULT_SENSITIVITY; - - - bool ProcessAxis ( const IOHIDValueRef value ); - bool ProcessButton( const IOHIDValueRef value ); - bool ProcessPOV ( const IOHIDValueRef value ); - -}; - - -const float IOKitJoystick::DEFAULT_DEADZONE = 0.25f; -const float IOKitJoystick::DEFAULT_SENSITIVITY = 1.0f; - - -IOKitJoystick::IOKitJoystick( IOHIDDeviceRef device ) -: m_device( device ) -, m_sensitivity( DEFAULT_SENSITIVITY ) -{ - assert(NULL != device); - assert(IOHIDDeviceGetTypeID() == CFGetTypeID(device)); - - CFArrayRef elements = IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone); - assert(NULL != elements); - assert(CFArrayGetTypeID() == CFGetTypeID(elements)); - - for (CFIndex i = 0, count = CFArrayGetCount(elements); i < count; ++i) - { - const IOHIDElementRef element = - static_cast(const_cast(CFArrayGetValueAtIndex(elements, i))); - assert(NULL != element); - assert(IOHIDElementGetTypeID() == CFGetTypeID(element)); - - const uint32_t usagePage = IOHIDElementGetUsagePage( element ); - - if ( kHIDPage_GenericDesktop == usagePage ) - { - const uint32_t usage = IOHIDElementGetUsage( element ); - - if ( kHIDUsage_GD_Slider == usage - || kHIDUsage_GD_X == usage || kHIDUsage_GD_Y == usage || kHIDUsage_GD_Z == usage - || kHIDUsage_GD_Rx == usage || kHIDUsage_GD_Ry == usage || kHIDUsage_GD_Rz == usage ) - { - AxisInfo axis; - memset( &axis, 0, sizeof( axis ) ); - - if ( const CFStringRef name = IOHIDElementGetName( element ) ) - { - CFStringGetCString( name, axis.name, sizeof( axis.name ) - 1, kCFStringEncodingUTF8 ); - } - else - { - snprintf( axis.name, sizeof( axis.name ), "Axis %i", m_axes.Size() + 1 ); - } - - axis.element = element; - - m_axes.Push( axis ); - - IOHIDElement_SetCalibrationMin( element, -1 ); - IOHIDElement_SetCalibrationMax( element, 1 ); - - HIDQueueElement( m_device, element ); - } - else if ( kHIDUsage_GD_Hatswitch == usage && m_POVs.Size() < 4 ) - { - m_POVs.Push( element ); - - HIDQueueElement( m_device, element ); - } - } - else if ( kHIDPage_Button == usagePage ) - { - m_buttons.Push( element ); - - HIDQueueElement( m_device, element ); - } - } - - CFRelease(elements); - - SetDefaultConfig(); -} - -IOKitJoystick::~IOKitJoystick() -{ - M_SaveJoystickConfig( this ); -} - - -FString IOKitJoystick::GetName() -{ - FString result; - - result += ToFString( IOHIDDevice_GetManufacturer( m_device ) ); - result += " "; - result += ToFString( IOHIDDevice_GetProduct( m_device ) ); - - return result; -} - - -float IOKitJoystick::GetSensitivity() -{ - return m_sensitivity; -} - -void IOKitJoystick::SetSensitivity( float scale ) -{ - m_sensitivity = scale; -} - - -int IOKitJoystick::GetNumAxes() -{ - return static_cast< int >( m_axes.Size() ); -} - -#define IS_AXIS_VALID ( static_cast< unsigned int >( axis ) < m_axes.Size() ) - -float IOKitJoystick::GetAxisDeadZone( int axis ) -{ - return IS_AXIS_VALID ? m_axes[ axis ].deadZone : 0.0f; -} - -EJoyAxis IOKitJoystick::GetAxisMap( int axis ) -{ - return IS_AXIS_VALID ? m_axes[ axis ].gameAxis : JOYAXIS_None; -} - -const char* IOKitJoystick::GetAxisName( int axis ) -{ - return IS_AXIS_VALID ? m_axes[ axis ].name : "Invalid"; -} - -float IOKitJoystick::GetAxisScale( int axis ) -{ - return IS_AXIS_VALID ? m_axes[ axis ].sensitivity : 0.0f; -} - -void IOKitJoystick::SetAxisDeadZone( int axis, float deadZone ) -{ - if ( IS_AXIS_VALID ) - { - m_axes[ axis ].deadZone = clamp( deadZone, 0.0f, 1.0f ); - } -} - -void IOKitJoystick::SetAxisMap( int axis, EJoyAxis gameAxis ) -{ - if ( IS_AXIS_VALID ) - { - m_axes[ axis ].gameAxis = ( gameAxis > JOYAXIS_None && gameAxis < NUM_JOYAXIS ) - ? gameAxis - : JOYAXIS_None; - } -} - -void IOKitJoystick::SetAxisScale( int axis, float scale ) -{ - if ( IS_AXIS_VALID ) - { - m_axes[ axis ].sensitivity = scale; - } -} - - -bool IOKitJoystick::IsSensitivityDefault() -{ - return DEFAULT_SENSITIVITY == m_sensitivity; -} - -bool IOKitJoystick::IsAxisDeadZoneDefault( int axis ) -{ - return IS_AXIS_VALID - ? ( m_axes[ axis ].deadZone == m_axes[ axis ].defaultDeadZone ) - : true; -} - -bool IOKitJoystick::IsAxisMapDefault( int axis ) -{ - return IS_AXIS_VALID - ? ( m_axes[ axis ].gameAxis == m_axes[ axis ].defaultGameAxis ) - : true; -} - -bool IOKitJoystick::IsAxisScaleDefault( int axis ) -{ - return IS_AXIS_VALID - ? ( m_axes[ axis ].sensitivity == m_axes[ axis ].defaultSensitivity ) - : true; -} - -#undef IS_AXIS_VALID - -void IOKitJoystick::SetDefaultConfig() -{ - m_sensitivity = DEFAULT_SENSITIVITY; - - const size_t axisCount = m_axes.Size(); - - for ( size_t i = 0; i < axisCount; ++i ) - { - m_axes[i].deadZone = DEFAULT_DEADZONE; - m_axes[i].sensitivity = DEFAULT_SENSITIVITY; - m_axes[i].gameAxis = JOYAXIS_None; - } - - // Two axes? Horizontal is yaw and vertical is forward. - - if ( 2 == axisCount) - { - m_axes[0].gameAxis = JOYAXIS_Yaw; - m_axes[1].gameAxis = JOYAXIS_Forward; - } - - // Three axes? First two are movement, third is yaw. - - else if ( axisCount >= 3 ) - { - m_axes[0].gameAxis = JOYAXIS_Side; - m_axes[1].gameAxis = JOYAXIS_Forward; - m_axes[2].gameAxis = JOYAXIS_Yaw; - - // Four axes? First two are movement, last two are looking around. - - if ( axisCount >= 4 ) - { - m_axes[3].gameAxis = JOYAXIS_Pitch; -// ??? m_axes[3].sensitivity = 0.75f; - - // Five axes? Use the fifth one for moving up and down. - - if ( axisCount >= 5 ) - { - m_axes[4].gameAxis = JOYAXIS_Up; - } - } - } - - // If there is only one axis, then we make no assumptions about how - // the user might want to use it. - - // Preserve defaults for config saving. - - for ( size_t i = 0; i < axisCount; ++i ) - { - m_axes[i].defaultDeadZone = m_axes[i].deadZone; - m_axes[i].defaultSensitivity = m_axes[i].sensitivity; - m_axes[i].defaultGameAxis = m_axes[i].gameAxis; - } -} - - -FString IOKitJoystick::GetIdentifier() -{ - char identifier[ 32 ] = {0}; - - snprintf( identifier, sizeof( identifier ), "VID_%04x_PID_%04x", - IOHIDDevice_GetVendorID( m_device ), IOHIDDevice_GetProductID( m_device ) ); - - return FString( identifier ); -} - - -void IOKitJoystick::AddAxes( float axes[ NUM_JOYAXIS ] ) const -{ - for ( size_t i = 0, count = m_axes.Size(); i < count; ++i ) - { - const EJoyAxis axis = m_axes[i].gameAxis; - - if ( JOYAXIS_None == axis ) - { - continue; - } - - axes[ axis ] -= m_axes[i].value; - } -} - - -void IOKitJoystick::Update() -{ - IOHIDValueRef value = NULL; - - while ( HIDGetEvent( m_device, &value ) && NULL != value ) - { - ProcessAxis( value ) || ProcessButton( value ) || ProcessPOV( value ); - - CFRelease( value ); - } -} - - -bool IOKitJoystick::ProcessAxis( const IOHIDValueRef value ) -{ - const IOHIDElementRef element = IOHIDValueGetElement( value ); - - if ( NULL == element ) - { - return false; - } - - for ( size_t i = 0, count = m_axes.Size(); i < count; ++i ) - { - if ( element != m_axes[i].element ) - { - continue; - } - - AxisInfo& axis = m_axes[i]; - - const double scaledValue = IOHIDValueGetScaledValue( value, kIOHIDValueScaleTypeCalibrated ); - const double filteredValue = Joy_RemoveDeadZone( scaledValue, axis.deadZone, NULL ); - - axis.value = static_cast< float >( filteredValue * m_sensitivity * axis.sensitivity ); - - return true; - } - - return false; -} - -bool IOKitJoystick::ProcessButton( const IOHIDValueRef value ) -{ - const IOHIDElementRef element = IOHIDValueGetElement( value ); - - if ( NULL == element ) - { - return false; - } - - for ( size_t i = 0, count = m_buttons.Size(); i < count; ++i ) - { - if ( element != m_buttons[i] ) - { - continue; - } - - const int newButton = IOHIDValueGetIntegerValue( value ) & 1; - const int oldButton = ~newButton; - - Joy_GenerateButtonEvents( oldButton, newButton, 1, - static_cast< int >( KEY_FIRSTJOYBUTTON + i ) ); - - return true; - } - - return false; -} - -bool IOKitJoystick::ProcessPOV( const IOHIDValueRef value ) -{ - const IOHIDElementRef element = IOHIDValueGetElement( value ); - - if ( NULL == element ) - { - return false; - } - - for ( size_t i = 0, count = m_POVs.Size(); i < count; ++i ) - { - if ( element != m_POVs[i] ) - { - continue; - } - - const CFIndex direction = IOHIDValueGetIntegerValue( value ); - - // Default values is for Up/North - int oldButtons = 0; - int newButtons = 1; - int numButtons = 1; - int baseButton = KEY_JOYPOV1_UP; - - switch ( direction ) - { - case 0: // N - break; - - case 1: // NE - newButtons = 3; - numButtons = 2; - break; - - case 2: // E - baseButton = KEY_JOYPOV1_RIGHT; - break; - - case 3: // SE - newButtons = 3; - numButtons = 2; - baseButton = KEY_JOYPOV1_RIGHT; - break; - - case 4: // S - baseButton = KEY_JOYPOV1_DOWN; - break; - - case 5: // SW - newButtons = 3; - numButtons = 2; - baseButton = KEY_JOYPOV1_DOWN; - break; - - case 6: // W - baseButton = KEY_JOYPOV1_LEFT; - break; - - case 7: // NW - newButtons = 9; // UP and LEFT - numButtons = 4; - break; - - default: - // release all four directions - oldButtons = 15; - newButtons = 0; - numButtons = 4; - break; - } - - Joy_GenerateButtonEvents( oldButtons, newButtons, numButtons, - static_cast< int >( baseButton + i * 4 ) ); - } - - return false; -} - - -// --------------------------------------------------------------------------- - - -class IOKitJoystickManager -{ -public: - IOKitJoystickManager(); - ~IOKitJoystickManager(); - - void GetJoysticks( TArray< IJoystickConfig* >& joysticks ) const; - - void AddAxes( float axes[ NUM_JOYAXIS ] ) const; - - // Updates axes/buttons states - void Update(); - - // Rebuilds device list - void Rescan(); - -private: - TArray< IOKitJoystick* > m_joysticks; - - static void OnDeviceChanged( void* context, IOReturn result, void* sender, IOHIDDeviceRef device ); - - void ReleaseJoysticks(); - - void EnableCallbacks(); - void DisableCallbacks(); - -}; - - -IOKitJoystickManager::IOKitJoystickManager() -{ - Rescan(); -} - -IOKitJoystickManager::~IOKitJoystickManager() -{ - ReleaseJoysticks(); - DisableCallbacks(); - - HIDReleaseDeviceList(); -} - - -void IOKitJoystickManager::GetJoysticks( TArray< IJoystickConfig* >& joysticks ) const -{ - const size_t joystickCount = m_joysticks.Size(); - - joysticks.Resize( joystickCount ); - - for ( size_t i = 0; i < joystickCount; ++i ) - { - M_LoadJoystickConfig( m_joysticks[i] ); - - joysticks[i] = m_joysticks[i]; - } -} - -void IOKitJoystickManager::AddAxes( float axes[ NUM_JOYAXIS ] ) const -{ - for ( size_t i = 0, count = m_joysticks.Size(); i < count; ++i ) - { - m_joysticks[i]->AddAxes( axes ); - } -} - - -void IOKitJoystickManager::Update() -{ - for ( size_t i = 0, count = m_joysticks.Size(); i < count; ++i ) - { - m_joysticks[i]->Update(); - } -} - - -void IOKitJoystickManager::Rescan() -{ - ReleaseJoysticks(); - DisableCallbacks(); - - const int usageCount = 2; - - const UInt32 usagePages[ usageCount ] = - { - kHIDPage_GenericDesktop, - kHIDPage_GenericDesktop - }; - - const UInt32 usages[ usageCount ] = - { - kHIDUsage_GD_Joystick, - kHIDUsage_GD_GamePad - }; - - if ( HIDUpdateDeviceList( usagePages, usages, usageCount ) ) - { - IOHIDDeviceRef device = HIDGetFirstDevice(); - - while ( NULL != device ) - { - IOKitJoystick* joystick = new IOKitJoystick( device ); - m_joysticks.Push( joystick ); - - device = HIDGetNextDevice( device ); - } - } - else - { - Printf( "IOKitJoystickManager: Failed to build gamepad/joystick device list.\n" ); - } - - EnableCallbacks(); -} - - -void IOKitJoystickManager::OnDeviceChanged( void* context, IOReturn result, void* sender, IOHIDDeviceRef device ) -{ - event_t event; - - memset( &event, 0, sizeof( event ) ); - event.type = EV_DeviceChange; - - D_PostEvent( &event ); -} - - -void IOKitJoystickManager::ReleaseJoysticks() -{ - for ( size_t i = 0, count = m_joysticks.Size(); i < count; ++i ) - { - delete m_joysticks[i]; - } - - m_joysticks.Clear(); -} - - -void IOKitJoystickManager::EnableCallbacks() -{ - if ( NULL == gIOHIDManagerRef ) - { - return; - } - - IOHIDManagerRegisterDeviceMatchingCallback( gIOHIDManagerRef, OnDeviceChanged, this ); - IOHIDManagerRegisterDeviceRemovalCallback ( gIOHIDManagerRef, OnDeviceChanged, this ); - IOHIDManagerScheduleWithRunLoop( gIOHIDManagerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode ); -} - -void IOKitJoystickManager::DisableCallbacks() -{ - if ( NULL == gIOHIDManagerRef ) - { - return; - } - - IOHIDManagerUnscheduleFromRunLoop( gIOHIDManagerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode ); - IOHIDManagerRegisterDeviceMatchingCallback( gIOHIDManagerRef, NULL, NULL ); - IOHIDManagerRegisterDeviceRemovalCallback ( gIOHIDManagerRef, NULL, NULL ); -} - - -IOKitJoystickManager* s_joystickManager; - - -} // unnamed namespace - - -// --------------------------------------------------------------------------- - - -void I_StartupJoysticks() -{ - // HID Manager API is available on 10.5 (Darwin 9.x) or newer - - if (darwinVersion.major >= 9) - { - s_joystickManager = new IOKitJoystickManager; - } -} - -void I_ShutdownJoysticks() -{ - delete s_joystickManager; -} - -void I_GetJoysticks( TArray< IJoystickConfig* >& sticks ) -{ - if ( NULL != s_joystickManager ) - { - s_joystickManager->GetJoysticks( sticks ); - } -} - -void I_GetAxes( float axes[ NUM_JOYAXIS ] ) -{ - for ( size_t i = 0; i < NUM_JOYAXIS; ++i ) - { - axes[i] = 0.0f; - } - - if ( use_joystick && NULL != s_joystickManager ) - { - s_joystickManager->AddAxes( axes ); - } -} - -IJoystickConfig* I_UpdateDeviceList() -{ - if ( use_joystick && NULL != s_joystickManager ) - { - s_joystickManager->Rescan(); - } - - return NULL; -} - - -// --------------------------------------------------------------------------- - - -void I_ProcessJoysticks() -{ - if ( use_joystick && NULL != s_joystickManager ) - { - s_joystickManager->Update(); - } -} - -#else // prior to 10.5 - -void I_StartupJoysticks() -{ -} - -void I_ShutdownJoysticks() -{ -} - -void I_GetJoysticks(TArray& sticks) -{ - sticks.Clear(); -} - -void I_GetAxes(float axes[NUM_JOYAXIS]) -{ - for (size_t i = 0; i < NUM_JOYAXIS; ++i) - { - axes[i] = 0.0f; - } -} - -IJoystickConfig *I_UpdateDeviceList() -{ - return NULL; -} - -void I_ProcessJoysticks() -{ -} - -#endif // 10.5 or higher diff --git a/src/ct_chat.cpp b/src/ct_chat.cpp index c0b73d3c0..78efab9d0 100644 --- a/src/ct_chat.cpp +++ b/src/ct_chat.cpp @@ -343,6 +343,10 @@ static void CT_ClearChatMessage () static void ShoveChatStr (const char *str, BYTE who) { + // Don't send empty messages + if (str == NULL || str[0] == '\0') + return; + FString substBuff; if (str[0] == '/' && diff --git a/src/d_main.cpp b/src/d_main.cpp index 82f2f3ab3..321b118a4 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2275,6 +2275,8 @@ void D_DoomMain (void) execFiles = Args->GatherFiles ("-exec"); D_MultiExec (execFiles, true); + C_ExecCmdLineParams (); // [RH] do all +set commands on the command line + CopyFiles(allwads, pwads); // Since this function will never leave we must delete this array here manually. @@ -2290,7 +2292,8 @@ void D_DoomMain (void) // Now that wads are loaded, define mod-specific cvars. ParseCVarInfo(); - C_ExecCmdLineParams (); // [RH] do all +set commands on the command line + // Try setting previously unknown cvars again, as a CVARINFO may have made them known. + C_ExecStoredSets(); // [RH] Initialize localizable strings. GStrings.LoadStrings (false); diff --git a/src/d_net.cpp b/src/d_net.cpp index a7ec870e0..b08c79c5f 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -185,7 +185,7 @@ static struct TicSpecial size_t used[BACKUPTICS]; BYTE *streamptr; size_t streamoffs; - int specialsize; + size_t specialsize; int lastmaketic; bool okay; @@ -224,11 +224,11 @@ static struct TicSpecial } // Make more room for special commands. - void GetMoreSpace () + void GetMoreSpace (size_t needed) { int i; - specialsize <<= 1; + specialsize = MAX(specialsize * 2, needed + 30); DPrintf ("Expanding special size to %d\n", specialsize); @@ -240,8 +240,8 @@ static struct TicSpecial void CheckSpace (size_t needed) { - if (streamoffs >= specialsize - needed) - GetMoreSpace (); + if (streamoffs + needed >= specialsize) + GetMoreSpace (streamoffs + needed); streamoffs += needed; } @@ -669,25 +669,38 @@ void PlayerIsGone (int netnode, int netconsole) { int i; - if (!nodeingame[netnode]) - return; + if (nodeingame[netnode]) + { + for (i = netnode + 1; i < doomcom.numnodes; ++i) + { + if (nodeingame[i]) + break; + } + if (i == doomcom.numnodes) + { + doomcom.numnodes = netnode; + } - for (i = netnode + 1; i < doomcom.numnodes; ++i) - { - if (nodeingame[i]) - break; + if (playeringame[netconsole]) + { + players[netconsole].playerstate = PST_GONE; + } + nodeingame[netnode] = false; + nodejustleft[netnode] = false; } - if (i == doomcom.numnodes) + else if (nodejustleft[netnode]) // Packet Server { - doomcom.numnodes = netnode; + if (netnode + 1 == doomcom.numnodes) + { + doomcom.numnodes = netnode; + } + if (playeringame[netconsole]) + { + players[netconsole].playerstate = PST_GONE; + } + nodejustleft[netnode] = false; } - - if (playeringame[netconsole]) - { - players[netconsole].playerstate = PST_GONE; - } - nodeingame[netnode] = false; - nodejustleft[netnode] = false; + else return; if (netconsole == Net_Arbitrator) { @@ -790,7 +803,6 @@ void GetPackets (void) else { nodeingame[netnode] = false; - playeringame[netconsole] = false; nodejustleft[netnode] = true; } continue; @@ -1064,16 +1076,16 @@ void NetUpdate (void) if (consoleplayer == Net_Arbitrator) { - for (j = 0; j < doomcom.numnodes; j++) - { - if (nodeingame[j] && NetMode == NET_PacketServer) - { - count++; - } - } - if (NetMode == NET_PacketServer) { + for (j = 0; j < MAXPLAYERS; j++) + { + if (playeringame[j] && players[j].Bot == NULL) + { + count++; + } + } + // The loop above added the local player to the count a second time, // and it also added the player being sent the packet to the count. count -= 2; @@ -1203,12 +1215,15 @@ void NetUpdate (void) netbuffer[0] |= NCMD_MULTI; netbuffer[k++] = count; - for (l = 1, j = 0; j < doomcom.numnodes; j++) + if (NetMode == NET_PacketServer) { - if (nodeingame[j] && j != i && j != nodeforplayer[consoleplayer] && NetMode == NET_PacketServer) + for (l = 1, j = 0; j < MAXPLAYERS; j++) { - playerbytes[l++] = playerfornode[j]; - netbuffer[k++] = playerfornode[j]; + if (playeringame[j] && players[j].Bot == NULL && j != playerfornode[i] && j != consoleplayer) + { + playerbytes[l++] = j; + netbuffer[k++] = j; + } } } } diff --git a/src/g_doom/a_archvile.cpp b/src/g_doom/a_archvile.cpp index 1700191d2..5e3f4f433 100644 --- a/src/g_doom/a_archvile.cpp +++ b/src/g_doom/a_archvile.cpp @@ -160,6 +160,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_VileAttack) P_RadiusAttack (fire, self, blastdmg, blastrad, dmgtype, 0); } - target->velz = Scale(thrust, 1000, target->Mass); + if (!(target->flags7 & MF7_DONTTHRUST)) + { + target->velz = Scale(thrust, 1000, target->Mass); + } return 0; } diff --git a/src/g_level.cpp b/src/g_level.cpp index 761ea4f48..713847b05 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1287,6 +1287,7 @@ void G_InitLevelLocals () level.teamdamage = teamdamage; level.flags = 0; level.flags2 = 0; + level.flags3 = 0; info = FindLevelInfo (level.MapName); @@ -1340,6 +1341,7 @@ void G_InitLevelLocals () level.clusterflags = clus ? clus->flags : 0; level.flags |= info->flags; level.flags2 |= info->flags2; + level.flags3 |= info->flags3; level.levelnum = info->levelnum; level.Music = info->Music; level.musicorder = info->musicorder; diff --git a/src/g_level.h b/src/g_level.h index c51c5372b..4aa23f5f6 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -214,6 +214,9 @@ enum ELevelFlags LEVEL2_ENDGAME = 0x20000000, // This is an epilogue level that cannot be quit. LEVEL2_NOAUTOSAVEHINT = 0x40000000, // tell the game that an autosave for this level does not need to be kept LEVEL2_FORGETSTATE = 0x80000000, // forget this map's state in a hub + + // More flags! + LEVEL3_FORCEFAKECONTRAST = 0x00000001, // forces fake contrast even with fog enabled }; @@ -283,6 +286,8 @@ struct level_info_t int sucktime; DWORD flags; DWORD flags2; + DWORD flags3; + FString Music; FString LevelName; SBYTE WallVertLight, WallHorizLight; @@ -396,6 +401,7 @@ struct FLevelLocals DWORD flags; DWORD flags2; + DWORD flags3; DWORD fadeto; // The color the palette fades to (usually black) DWORD outsidefog; // The fog for sectors with sky ceilings diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index 96accfb09..783e51a99 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -1190,6 +1190,9 @@ enum EMIType MITYPE_SETFLAG2, MITYPE_CLRFLAG2, MITYPE_SCFLAGS2, + MITYPE_SETFLAG3, + MITYPE_CLRFLAG3, + MITYPE_SCFLAGS3, MITYPE_COMPATFLAG, }; @@ -1275,6 +1278,7 @@ MapFlagHandlers[] = { "rememberstate", MITYPE_CLRFLAG2, LEVEL2_FORGETSTATE, 0 }, { "unfreezesingleplayerconversations",MITYPE_SETFLAG2, LEVEL2_CONV_SINGLE_UNFREEZE, 0 }, { "spawnwithweaponraised", MITYPE_SETFLAG2, LEVEL2_PRERAISEWEAPON, 0 }, + { "forcefakecontrast", MITYPE_SETFLAG3, LEVEL3_FORCEFAKECONTRAST, 0 }, { "nobotnodes", MITYPE_IGNORE, 0, 0 }, // Skulltag option: nobotnodes { "compat_shorttex", MITYPE_COMPATFLAG, COMPATF_SHORTTEX, 0 }, { "compat_stairs", MITYPE_COMPATFLAG, COMPATF_STAIRINDEX, 0 }, @@ -1372,6 +1376,20 @@ void FMapInfoParser::ParseMapDefinition(level_info_t &info) info.flags2 = (info.flags2 & handler->data2) | handler->data1; break; + case MITYPE_SETFLAG3: + info.flags3 |= handler->data1; + info.flags3 |= handler->data2; + break; + + case MITYPE_CLRFLAG3: + info.flags3 &= ~handler->data1; + info.flags3 |= handler->data2; + break; + + case MITYPE_SCFLAGS3: + info.flags3 = (info.flags3 & handler->data2) | handler->data1; + break; + case MITYPE_COMPATFLAG: { int set = 1; diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index e001af470..14ead016e 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -529,27 +529,29 @@ bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *mor { AMorphedMonster *fakeme = static_cast(actor); AActor *realme = fakeme->UnmorphedMe; - if ((fakeme->UnmorphTime) && - (fakeme->MorphStyle & MORPH_UNDOBYDEATH) && - (realme)) + if (realme != NULL) { - int realstyle = fakeme->MorphStyle; - int realhealth = fakeme->health; - if (P_UndoMonsterMorph(fakeme, !!(fakeme->MorphStyle & MORPH_UNDOBYDEATHFORCED))) + if ((fakeme->UnmorphTime) && + (fakeme->MorphStyle & MORPH_UNDOBYDEATH)) { - *morphed = realme; - *morphedstyle = realstyle; - *morphedhealth = realhealth; - return true; + int realstyle = fakeme->MorphStyle; + int realhealth = fakeme->health; + if (P_UndoMonsterMorph(fakeme, !!(fakeme->MorphStyle & MORPH_UNDOBYDEATHFORCED))) + { + *morphed = realme; + *morphedstyle = realstyle; + *morphedhealth = realhealth; + return true; + } + } + if (realme->flags4 & MF4_BOSSDEATH) + { + realme->health = 0; // make sure that A_BossDeath considers it dead. + // FIXME: Use the caller's stack once the whole chain is scriptable. + VMFrameStack stack; + VMValue params[3] = { realme, realme, VMValue(NULL, ATAG_STATE) }; + stack.Call(A_BossDeath_VMPtr, params, countof(params), NULL, 0, NULL); } - } - if (realme->flags4 & MF4_BOSSDEATH) - { - realme->health = 0; // make sure that A_BossDeath considers it dead. - // FIXME: Use the caller's stack once the whole chain is scriptable. - VMFrameStack stack; - VMValue params[3] = { realme, realme, VMValue(NULL, ATAG_STATE) }; - stack.Call(A_BossDeath_VMPtr, params, countof(params), NULL, 0, NULL); } fakeme->flags3 |= MF3_STAYMORPHED; // moved here from AMorphedMonster::Die() return false; diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index a738a5aad..791021ae8 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -1215,7 +1215,11 @@ public: if(Scaled) { if(cx != 0 || cy != 0) + { screen->VirtualToRealCoords(dcx, dcy, tmp, tmp, script->resW, script->resH, true); + if (cx == 0) dcx = 0; + if (cy == 0) dcy = 0; + } if(cr != 0 || cb != 0 || clearDontDraw) screen->VirtualToRealCoords(dcr, dcb, tmp, tmp, script->resW, script->resH, true); screen->VirtualToRealCoords(dx, dy, w, h, script->resW, script->resH, true); @@ -1276,8 +1280,8 @@ public: // We can't use DTA_HUDRules since it forces a width and height. // Translation: No high res. - bool xright = rx < 0; - bool ybot = ry < 0; + bool xright = *x < 0 && !x.RelCenter(); + bool ybot = *y < 0 && !y.RelCenter(); w = (forceWidth < 0 ? texture->GetScaledWidthDouble() : forceWidth); h = (forceHeight < 0 ? texture->GetScaledHeightDouble() : forceHeight); diff --git a/src/g_strife/a_loremaster.cpp b/src/g_strife/a_loremaster.cpp index bee14f6eb..e457ffc4d 100644 --- a/src/g_strife/a_loremaster.cpp +++ b/src/g_strife/a_loremaster.cpp @@ -14,27 +14,27 @@ class ALoreShot : public AActor { DECLARE_CLASS (ALoreShot, AActor) public: - int DoSpecialDamage (AActor *target, int damage, FName damagetype); + int DoSpecialDamage (AActor *victim, int damage, FName damagetype); }; IMPLEMENT_CLASS (ALoreShot) -int ALoreShot::DoSpecialDamage (AActor *target, int damage, FName damagetype) +int ALoreShot::DoSpecialDamage (AActor *victim, int damage, FName damagetype) { FVector3 thrust; - if (this->target != NULL) + if (victim != NULL && target != NULL && !(victim->flags7 & MF7_DONTTHRUST)) { - thrust.X = float(this->target->x - target->x); - thrust.Y = float(this->target->y - target->y); - thrust.Z = float(this->target->z - target->z); + thrust.X = float(target->x - victim->x); + thrust.Y = float(target->y - victim->y); + thrust.Z = float(target->z - victim->z); thrust.MakeUnit(); - thrust *= float((255*50*FRACUNIT) / (target->Mass ? target->Mass : 1)); + thrust *= float((255*50*FRACUNIT) / (victim->Mass ? victim->Mass : 1)); - target->velx += fixed_t(thrust.X); - target->vely += fixed_t(thrust.Y); - target->velz += fixed_t(thrust.Z); + victim->velx += fixed_t(thrust.X); + victim->vely += fixed_t(thrust.Y); + victim->velz += fixed_t(thrust.Z); } return damage; } diff --git a/src/g_strife/strife_sbar.cpp b/src/g_strife/strife_sbar.cpp index 7e00906cf..b7372f977 100644 --- a/src/g_strife/strife_sbar.cpp +++ b/src/g_strife/strife_sbar.cpp @@ -601,7 +601,7 @@ private: screen->DrawText(SmallFont2, CR_UNTRANSLATED, left + 210 * xscale, top + 8 * yscale, buff, DTA_CleanNoMove, true, TAG_DONE); - if (CPlayer->LogText != NULL) + if (CPlayer->LogText.IsNotEmpty()) { FBrokenLines *lines = V_BreakLines(SmallFont2, 272, CPlayer->LogText); for (i = 0; lines[i].Width >= 0; ++i) diff --git a/src/menu/listmenu.cpp b/src/menu/listmenu.cpp index 53b4fee22..402c1d5e9 100644 --- a/src/menu/listmenu.cpp +++ b/src/menu/listmenu.cpp @@ -300,7 +300,12 @@ void FListMenuItem::DrawSelector(int xofs, int yofs, FTextureID tex) if ((DMenu::MenuTime%8) < 6) { screen->DrawText(ConFont, OptionSettings.mFontColorSelection, - mXpos + xofs, mYpos + yofs, "\xd", DTA_Clean, true, TAG_DONE); + (mXpos + xofs - 160) * CleanXfac + screen->GetWidth() / 2, + (mYpos + yofs - 100) * CleanYfac + screen->GetHeight() / 2, + "\xd", + DTA_CellX, 8 * CleanXfac, + DTA_CellY, 8 * CleanYfac, + TAG_DONE); } } else diff --git a/src/menu/videomenu.cpp b/src/menu/videomenu.cpp index 1d1d02383..5e44bbfd4 100644 --- a/src/menu/videomenu.cpp +++ b/src/menu/videomenu.cpp @@ -247,8 +247,12 @@ static void BuildModesList (int hiwidth, int hiheight, int hi_bits) if (Video != NULL) { while ((haveMode = Video->NextMode (&width, &height, &letterbox)) && - (ratiomatch >= 0 && CheckRatio (width, height) != ratiomatch)) + ratiomatch >= 0) { + int ratio; + CheckRatio (width, height, &ratio); + if (ratio == ratiomatch) + break; } } diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index d13e46204..fc35409dc 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -968,10 +968,12 @@ CCMD (dump3df) fixed_t height=ffloors[i]->top.plane->ZatPoint(CenterSpot(sector)); fixed_t bheight=ffloors[i]->bottom.plane->ZatPoint(CenterSpot(sector)); + IGNORE_FORMAT_PRE Printf("FFloor %d @ top = %f (model = %d), bottom = %f (model = %d), flags = %B, alpha = %d %s %s\n", i, height / 65536., ffloors[i]->top.model->sectornum, bheight / 65536., ffloors[i]->bottom.model->sectornum, ffloors[i]->flags, ffloors[i]->alpha, (ffloors[i]->flags&FF_EXISTS)? "Exists":"", (ffloors[i]->flags&FF_DYNAMIC)? "Dynamic":""); + IGNORE_FORMAT_POST } } } diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 043f33cdc..28a536adb 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -2393,7 +2393,7 @@ void FBehavior::LoadScriptsDirectory () int size = LittleLong(scripts.dw[1]); if (size >= 6) { - int script_num = LittleShort(scripts.w[4]); + int script_num = LittleShort(scripts.sw[4]); ScriptPtr *ptr = const_cast(FindScript(script_num)); if (ptr != NULL) { @@ -4439,6 +4439,9 @@ enum EACSFunctions ACSF_CanRaiseActor, ACSF_SetActorTeleFog, // 86 ACSF_SwapActorTeleFog, + ACSF_SetActorRoll, + ACSF_ChangeActorRoll, + ACSF_GetActorRoll, /* Zandronum's - these must be skipped when we reach 99! -100:ResetMap(0), @@ -4743,6 +4746,27 @@ static void SetActorPitch(AActor *activator, int tid, int angle, bool interpolat } } +static void SetActorRoll(AActor *activator, int tid, int angle, bool interpolate) +{ + if (tid == 0) + { + if (activator != NULL) + { + activator->SetRoll(angle << 16, interpolate); + } + } + else + { + FActorIterator iterator(tid); + AActor *actor; + + while ((actor = iterator.Next())) + { + actor->SetRoll(angle << 16, interpolate); + } + } +} + static void SetActorTeleFog(AActor *activator, int tid, FName telefogsrc, FName telefogdest) { //Simply put, if it doesn't exist, it won't change. One can use "" in this scenario. @@ -5824,6 +5848,26 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) } break; + // [Nash] Actor roll functions. Let's roll! + case ACSF_SetActorRoll: + actor = SingleActorFromTID(args[0], activator); + if (actor != NULL) + { + actor->SetRoll(args[1] << 16, false); + } + return 0; + + case ACSF_ChangeActorRoll: + if (argCount >= 2) + { + SetActorRoll(activator, args[0], args[1], argCount > 2 ? !!args[2] : false); + } + break; + + case ACSF_GetActorRoll: + actor = SingleActorFromTID(args[0], activator); + return actor != NULL? actor->roll >> 16 : 0; + default: break; } @@ -7488,22 +7532,9 @@ scriptwait: break; case PCD_PRINTBINARY: -#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 6)))) || defined(__clang__) -#define HAS_DIAGNOSTIC_PRAGMA -#endif -#ifdef HAS_DIAGNOSTIC_PRAGMA -#pragma GCC diagnostic push -#ifdef __clang__ -#pragma GCC diagnostic ignored "-Wformat-invalid-specifier" -#else -#pragma GCC diagnostic ignored "-Wformat=" -#endif -#pragma GCC diagnostic ignored "-Wformat-extra-args" -#endif + IGNORE_FORMAT_PRE work.AppendFormat ("%B", STACK(1)); -#ifdef HAS_DIAGNOSTIC_PRAGMA -#pragma GCC diagnostic pop -#endif + IGNORE_FORMAT_POST --sp; break; diff --git a/src/p_enemy.h b/src/p_enemy.h index 02ac1ab0c..facf16a3b 100644 --- a/src/p_enemy.h +++ b/src/p_enemy.h @@ -72,7 +72,8 @@ DECLARE_ACTION(A_FreezeDeathChunks) void A_BossDeath(AActor *self); void A_Chase(VMFrameStack *stack, AActor *self); -void A_FaceTarget (AActor *actor, angle_t max_turn = 0, angle_t max_pitch = ANGLE_270); +void A_FaceTarget(AActor *actor, angle_t max_turn = 0, angle_t max_pitch = ANGLE_270); +void A_Face(AActor *self, AActor *other, angle_t max_turn = 0, angle_t max_pitch = ANGLE_270); bool A_RaiseMobj (AActor *, fixed_t speed); bool A_SinkMobj (AActor *, fixed_t speed); diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 24cdb0c0b..1a2e20b52 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1273,7 +1273,10 @@ int P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage, if (!(flags & DMG_NO_ARMOR) && player->mo->Inventory != NULL) { int newdam = damage; - player->mo->Inventory->AbsorbDamage(damage, mod, newdam); + if (damage > 0) + { + player->mo->Inventory->AbsorbDamage(damage, mod, newdam); + } if (damage < TELEFRAG_DAMAGE) { // if we are telefragging don't let the damage value go below that magic value. Some further checks would fail otherwise. diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index c8588a5b6..6b865878f 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -519,19 +519,19 @@ FUNC(LS_Generic_Stairs) FUNC(LS_Pillar_Build) // Pillar_Build (tag, speed, height) { - return EV_DoPillar (DPillar::pillarBuild, arg0, SPEED(arg1), arg2*FRACUNIT, 0, -1, false); + return EV_DoPillar (DPillar::pillarBuild, ln, arg0, SPEED(arg1), arg2*FRACUNIT, 0, -1, false); } FUNC(LS_Pillar_BuildAndCrush) // Pillar_BuildAndCrush (tag, speed, height, crush, crushtype) { - return EV_DoPillar (DPillar::pillarBuild, arg0, SPEED(arg1), arg2*FRACUNIT, 0, arg3, CRUSHTYPE(arg4)); + return EV_DoPillar (DPillar::pillarBuild, ln, arg0, SPEED(arg1), arg2*FRACUNIT, 0, arg3, CRUSHTYPE(arg4)); } FUNC(LS_Pillar_Open) // Pillar_Open (tag, speed, f_height, c_height) { - return EV_DoPillar (DPillar::pillarOpen, arg0, SPEED(arg1), arg2*FRACUNIT, arg3*FRACUNIT, -1, false); + return EV_DoPillar (DPillar::pillarOpen, ln, arg0, SPEED(arg1), arg2*FRACUNIT, arg3*FRACUNIT, -1, false); } FUNC(LS_Ceiling_LowerByValue) diff --git a/src/p_local.h b/src/p_local.h index 8a3c7eddb..3c0d20179 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -133,7 +133,7 @@ enum EPuffFlags PF_NORANDOMZ = 16 }; -AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags = 0); +AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags = 0, AActor *vict = NULL); void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, angle_t dir, int damage, AActor *originator); void P_BloodSplatter (fixed_t x, fixed_t y, fixed_t z, AActor *originator); void P_BloodSplatter2 (fixed_t x, fixed_t y, fixed_t z, AActor *originator); diff --git a/src/p_map.cpp b/src/p_map.cpp index 940c70752..7357a63ac 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -887,6 +887,20 @@ bool PIT_CheckLine(line_t *ld, const FBoundingBox &box, FCheckPosition &tm) return true; } + +//========================================================================== +// +// Isolated to keep the code readable and fix the logic +// +//========================================================================== + +static bool CheckRipLevel(AActor *victim, AActor *projectile) +{ + if (victim->RipLevelMin > 0 && projectile->RipperLevel < victim->RipLevelMin) return false; + if (victim->RipLevelMax > 0 && projectile->RipperLevel > victim->RipLevelMax) return false; + return true; +} + //========================================================================== // // PIT_CheckThing @@ -1207,7 +1221,8 @@ bool PIT_CheckThing(AActor *thing, FCheckPosition &tm) { return true; } - if (tm.DoRipping && !(thing->flags5 & MF5_DONTRIP)) + + if ((tm.DoRipping && !(thing->flags5 & MF5_DONTRIP)) && CheckRipLevel(thing, tm.thing)) { if (!(tm.thing->flags6 & MF6_NOBOSSRIP) || !(thing->flags2 & MF2_BOSS)) { @@ -3761,14 +3776,7 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, puffFlags |= PF_HITTHINGBLEED; // We must pass the unreplaced puff type here - puff = P_SpawnPuff(t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, puffFlags | PF_HITTHING); - } - - if (puffDefaults != NULL && trace.Actor != NULL && puff != NULL) - { - if (puffDefaults->flags7 && MF7_HITTARGET) puff->target = trace.Actor; - if (puffDefaults->flags7 && MF7_HITMASTER) puff->master = trace.Actor; - if (puffDefaults->flags7 && MF7_HITTRACER) puff->tracer = trace.Actor; + puff = P_SpawnPuff(t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, puffFlags | PF_HITTHING, trace.Actor); } // Allow puffs to inflict poison damage, so that hitscans can poison, too. @@ -4214,14 +4222,9 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i } if (spawnpuff) { - P_SpawnPuff(source, puffclass, x, y, z, (source->angle + angleoffset) - ANG90, 1, puffflags); - } - if (hitactor != NULL && puffDefaults != NULL && thepuff != NULL) - { - if (puffDefaults->flags7 & MF7_HITTARGET) thepuff->target = hitactor; - if (puffDefaults->flags7 & MF7_HITMASTER) thepuff->master = hitactor; - if (puffDefaults->flags7 & MF7_HITTRACER) thepuff->tracer = hitactor; + P_SpawnPuff(source, puffclass, x, y, z, (source->angle + angleoffset) - ANG90, 1, puffflags, hitactor); } + if (puffDefaults && puffDefaults->PoisonDamage > 0 && puffDefaults->PoisonDuration != INT_MIN) { P_PoisonMobj(hitactor, thepuff ? thepuff : source, source, puffDefaults->PoisonDamage, puffDefaults->PoisonDuration, puffDefaults->PoisonPeriod, puffDefaults->PoisonDamageType); @@ -4282,7 +4285,7 @@ CVAR(Float, chase_dist, 90.f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) void P_AimCamera(AActor *t1, fixed_t &CameraX, fixed_t &CameraY, fixed_t &CameraZ, sector_t *&CameraSector) { - fixed_t distance = (fixed_t)(chase_dist * FRACUNIT); + fixed_t distance = (fixed_t)(clamp(chase_dist, 0, 30000) * FRACUNIT); angle_t angle = (t1->angle - ANG180) >> ANGLETOFINESHIFT; angle_t pitch = (angle_t)(t1->pitch) >> ANGLETOFINESHIFT; FTraceResults trace; @@ -4292,7 +4295,7 @@ void P_AimCamera(AActor *t1, fixed_t &CameraX, fixed_t &CameraY, fixed_t &Camera vy = FixedMul(finecosine[pitch], finesine[angle]); vz = finesine[pitch]; - sz = t1->z - t1->floorclip + t1->height + (fixed_t)(chase_height * FRACUNIT); + sz = t1->z - t1->floorclip + t1->height + (fixed_t)(clamp(chase_height, -1000, 1000) * FRACUNIT); if (Trace(t1->x, t1->y, sz, t1->Sector, vx, vy, vz, distance, 0, 0, NULL, trace) && @@ -4768,7 +4771,7 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo points *= thing->GetClass()->RDFactor / (float)FRACUNIT; // points and bombdamage should be the same sign - if ((points * bombdamage) > 0 && P_CheckSight(thing, bombspot, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)) + if (((bombspot->flags7 & MF7_CAUSEPAIN) || (points * bombdamage) > 0) && P_CheckSight(thing, bombspot, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)) { // OK to damage; target is in direct path double velz; double thrust; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 8fa060456..b434b314b 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -423,6 +423,13 @@ void AActor::Serialize (FArchive &arc) arc << TeleFogSourceType << TeleFogDestType; } + if (SaveVersion >= 4518) + { + arc << RipperLevel + << RipLevelMin + << RipLevelMax; + } + { FString tagstr; if (arc.IsStoring() && Tag != NULL && Tag->Len() > 0) tagstr = *Tag; @@ -2056,48 +2063,46 @@ fixed_t P_XYMovement (AActor *mo, fixed_t scrollx, fixed_t scrolly) // Don't change the angle if there's THRUREFLECT on the monster. if (!(BlockingMobj->flags7 & MF7_THRUREFLECT)) { - int dir; - angle_t delta; - - if (BlockingMobj->flags7 & MF7_MIRRORREFLECT) - angle = mo->angle + ANG180; - else - angle = R_PointToAngle2(BlockingMobj->x, BlockingMobj->y, mo->x, mo->y); - + //int dir; + //angle_t delta; + angle = R_PointToAngle2(BlockingMobj->x, BlockingMobj->y, mo->x, mo->y); + bool dontReflect = (mo->AdjustReflectionAngle(BlockingMobj, angle)); // Change angle for deflection/reflection - // AIMREFLECT calls precedence so make sure not to bother with adjusting here if declared. - if (!(BlockingMobj->flags7 & MF7_AIMREFLECT) && (mo->AdjustReflectionAngle(BlockingMobj, angle))) - { - goto explode; - } - // Reflect the missile along angle - if (BlockingMobj->flags7 & MF7_AIMREFLECT) + if (!dontReflect) { - dir = P_FaceMobj(mo, mo->target, &delta); - if (dir) - { // Turn clockwise - mo->angle += delta; + bool tg = (mo->target != NULL); + bool blockingtg = (BlockingMobj->target != NULL); + if (BlockingMobj->flags7 & MF7_AIMREFLECT && (tg || blockingtg)) + { + AActor *origin; + if (tg) + origin = mo->target; + else if (blockingtg) + origin = BlockingMobj->target; + + float speed = (float)(mo->Speed); + //dest->x - source->x + FVector3 velocity(origin->x - mo->x, origin->y - mo->y, (origin->z + (origin->height/2)) - mo->z); + velocity.Resize(speed); + mo->velx = (fixed_t)(velocity.X); + mo->vely = (fixed_t)(velocity.Y); + mo->velz = (fixed_t)(velocity.Z); } else - { // Turn counter clockwise - mo->angle -= delta; + { + + mo->angle = angle; + angle >>= ANGLETOFINESHIFT; + mo->velx = FixedMul(mo->Speed >> 1, finecosine[angle]); + mo->vely = FixedMul(mo->Speed >> 1, finesine[angle]); + mo->velz = -mo->velz / 2; } - angle = mo->angle >> ANGLETOFINESHIFT; - mo->velx = FixedMul(mo->Speed, finecosine[angle]); - mo->vely = FixedMul(mo->Speed, finesine[angle]); - mo->velz = -mo->velz; } else { - mo->angle = angle; - angle >>= ANGLETOFINESHIFT; - mo->velx = FixedMul(mo->Speed >> 1, finecosine[angle]); - mo->vely = FixedMul(mo->Speed >> 1, finesine[angle]); - mo->velz = -mo->velz / 2; - } - - + goto explode; + } } if (mo->flags2 & MF2_SEEKERMISSILE) { @@ -3036,8 +3041,10 @@ bool AActor::AdjustReflectionAngle (AActor *thing, angle_t &angle) if (flags2 & MF2_DONTREFLECT) return true; if (thing->flags7 & MF7_THRUREFLECT) return false; + if (thing->flags7 & MF7_MIRRORREFLECT) + angle += ANGLE_180; // Change angle for reflection - if (thing->flags4&MF4_SHIELDREFLECT) + else if (thing->flags4&MF4_SHIELDREFLECT) { // Shield reflection (from the Centaur if (abs (angle - thing->angle)>>24 > 45) @@ -3060,6 +3067,13 @@ bool AActor::AdjustReflectionAngle (AActor *thing, angle_t &angle) else angle -= ANG45; } + else if (thing->flags7 & MF7_AIMREFLECT) + { + if (this->target != NULL) + A_Face(this, this->target); + else if (thing->target != NULL) + A_Face(this, thing->target); + } else angle += ANGLE_1 * ((pr_reflect()%16)-8); return false; @@ -3167,6 +3181,18 @@ void AActor::SetAngle(angle_t ang, bool interpolate) } } +void AActor::SetRoll(angle_t r, bool interpolate) +{ + if (r != roll) + { + roll = r; + if (player != NULL && interpolate) + { + player->cheats |= CF_INTERPVIEW; + } + } +} + // // P_MobjThinker // @@ -5029,7 +5055,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) // P_SpawnPuff // -AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags) +AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y, fixed_t z, angle_t dir, int updown, int flags, AActor *vict) { AActor *puff; @@ -5039,9 +5065,24 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, fixed_t x, fixed_t y puff = Spawn (pufftype, x, y, z, ALLOW_REPLACE); if (puff == NULL) return NULL; + if ((puff->flags4 & MF4_RANDOMIZE) && puff->tics > 0) + { + puff->tics -= pr_spawnpuff() & 3; + if (puff->tics < 1) + puff->tics = 1; + } + + //Moved puff creation and target/master/tracer setting to here. + if (puff && vict) + { + if (puff->flags7 & MF7_HITTARGET) puff->target = vict; + if (puff->flags7 & MF7_HITMASTER) puff->master = vict; + if (puff->flags7 & MF7_HITTRACER) puff->tracer = vict; + } // [BB] If the puff came from a player, set the target of the puff to this player. if ( puff && (puff->flags5 & MF5_PUFFGETSOWNER)) puff->target = source; + if (source != NULL) puff->angle = R_PointToAngle2(x, y, source->x, source->y); diff --git a/src/p_pillar.cpp b/src/p_pillar.cpp index 1f77c7c7b..809542949 100644 --- a/src/p_pillar.cpp +++ b/src/p_pillar.cpp @@ -212,16 +212,28 @@ DPillar::DPillar (sector_t *sector, EPillar type, fixed_t speed, } } -bool EV_DoPillar (DPillar::EPillar type, int tag, fixed_t speed, fixed_t height, - fixed_t height2, int crush, bool hexencrush) +bool EV_DoPillar (DPillar::EPillar type, line_t *line, int tag, + fixed_t speed, fixed_t height, fixed_t height2, int crush, bool hexencrush) { + int secnum; + sector_t *sec; bool rtn = false; - int secnum = -1; - while ((secnum = P_FindSectorFromTag (tag, secnum)) >= 0) + // check if a manual trigger; if so do just the sector on the backside + if (tag == 0) { - sector_t *sec = §ors[secnum]; + if (!line || !(sec = line->backsector)) + return rtn; + secnum = (int)(sec-sectors); + goto manual_pillar; + } + secnum = -1; + while (tag && (secnum = P_FindSectorFromTag (tag, secnum)) >= 0) + { + sec = §ors[secnum]; + +manual_pillar: if (sec->PlaneMoving(sector_t::floor) || sec->PlaneMoving(sector_t::ceiling)) continue; diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index a677420f5..119d92a9c 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -566,7 +566,7 @@ void P_SerializePolyobjs (FArchive &arc) I_Error ("UnarchivePolyobjs: Invalid polyobj tag"); } arc << angle; - po->RotatePolyobj (angle); + po->RotatePolyobj (angle, true); arc << deltaX << deltaY << po->interpolation; deltaX -= po->StartSpot.x; deltaY -= po->StartSpot.y; diff --git a/src/p_sectors.cpp b/src/p_sectors.cpp index 699350839..904c76c1b 100644 --- a/src/p_sectors.cpp +++ b/src/p_sectors.cpp @@ -965,7 +965,7 @@ int side_t::GetLightLevel (bool foggy, int baselight, bool noabsolute, int *pfak *pfakecontrast = 0; } - if (!foggy) // Don't do relative lighting in foggy sectors + if (!foggy || level.flags3 & LEVEL3_FORCEFAKECONTRAST) // Don't do relative lighting in foggy sectors { if (!(Flags & WALLF_NOFAKECONTRAST) && r_fakecontrast != 0) { diff --git a/src/p_spec.h b/src/p_spec.h index e653fe3b1..7e717029a 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -515,8 +515,8 @@ private: DPillar (); }; -bool EV_DoPillar (DPillar::EPillar type, int tag, fixed_t speed, fixed_t height, - fixed_t height2, int crush, bool hexencrush); +bool EV_DoPillar (DPillar::EPillar type, line_t *line, int tag, + fixed_t speed, fixed_t height, fixed_t height2, int crush, bool hexencrush); // // P_DOORS diff --git a/src/p_terrain.h b/src/p_terrain.h index 01cbab80b..7cf9ac387 100644 --- a/src/p_terrain.h +++ b/src/p_terrain.h @@ -49,11 +49,13 @@ public: WORD operator [](FTextureID tex) const { + if ((unsigned)tex.GetIndex() >= Types.Size()) return DefaultTerrainType; WORD type = Types[tex.GetIndex()]; return type == 0xffff? DefaultTerrainType : type; } WORD operator [](int texnum) const { + if ((unsigned)texnum >= Types.Size()) return DefaultTerrainType; WORD type = Types[texnum]; return type == 0xffff? DefaultTerrainType : type; } diff --git a/src/p_user.cpp b/src/p_user.cpp index 0e3ae7d60..41924beb4 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1444,7 +1444,7 @@ void APlayerPawn::Die (AActor *source, AActor *inflictor, int dmgflags) weap->SpawnState != ::GetDefault()->SpawnState) { item = P_DropItem (this, weap->GetClass(), -1, 256); - if (item != NULL) + if (item != NULL && item->IsKindOf(RUNTIME_CLASS(AWeapon))) { if (weap->AmmoGive1 && weap->Ammo1) { diff --git a/src/po_man.cpp b/src/po_man.cpp index e19acc53a..c6e273a0f 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -1051,7 +1051,7 @@ static void RotatePt (int an, fixed_t *x, fixed_t *y, fixed_t startSpotX, fixed_ // //========================================================================== -bool FPolyObj::RotatePolyobj (angle_t angle) +bool FPolyObj::RotatePolyobj (angle_t angle, bool fromsave) { int an; bool blocked; @@ -1073,23 +1073,27 @@ bool FPolyObj::RotatePolyobj (angle_t angle) validcount++; UpdateBBox(); - for(unsigned i=0;i < Sidedefs.Size(); i++) + // If we are loading a savegame we do not really want to damage actors and be blocked by them. This can also cause crashes when trying to damage incompletely deserialized player pawns. + if (!fromsave) { - if (CheckMobjBlocking(Sidedefs[i])) + for (unsigned i = 0; i < Sidedefs.Size(); i++) { - blocked = true; + if (CheckMobjBlocking(Sidedefs[i])) + { + blocked = true; + } } - } - if (blocked) - { - for(unsigned i=0;i < Vertices.Size(); i++) + if (blocked) { - Vertices[i]->x = PrevPts[i].x; - Vertices[i]->y = PrevPts[i].y; + for(unsigned i=0;i < Vertices.Size(); i++) + { + Vertices[i]->x = PrevPts[i].x; + Vertices[i]->y = PrevPts[i].y; + } + UpdateBBox(); + LinkPolyobj(); + return false; } - UpdateBBox(); - LinkPolyobj(); - return false; } this->angle += angle; LinkPolyobj(); diff --git a/src/po_man.h b/src/po_man.h index 70ab9d360..9e81cc266 100644 --- a/src/po_man.h +++ b/src/po_man.h @@ -74,7 +74,7 @@ struct FPolyObj int GetMirror(); bool MovePolyobj (int x, int y, bool force = false); - bool RotatePolyobj (angle_t angle); + bool RotatePolyobj (angle_t angle, bool fromsave = false); void ClosestPoint(fixed_t fx, fixed_t fy, fixed_t &ox, fixed_t &oy, side_t **side) const; void LinkPolyobj (); void RecalcActorFloorCeil(FBoundingBox bounds) const; diff --git a/src/cocoa/i_rbopts.h b/src/posix/cocoa/critsec.cpp similarity index 75% rename from src/cocoa/i_rbopts.h rename to src/posix/cocoa/critsec.cpp index 40a9ff17a..cbf112491 100644 --- a/src/cocoa/i_rbopts.h +++ b/src/posix/cocoa/critsec.cpp @@ -1,5 +1,5 @@ /* - ** i_rbopts.h + ** critsec.cpp ** **--------------------------------------------------------------------------- ** Copyright 2014 Alexey Lysiuk @@ -31,22 +31,32 @@ ** */ -#ifndef SRC_COCOA_I_RBOPTS_H_INCLUDED -#define SRC_COCOA_I_RBOPTS_H_INCLUDED +#include "critsec.h" -struct RenderBufferOptions +// TODO: add error handling + +FCriticalSection::FCriticalSection() { - float pixelScale; + pthread_mutexattr_t attributes; + pthread_mutexattr_init(&attributes); + pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE); - float shiftX; - float shiftY; + pthread_mutex_init(&m_mutex, &attributes); - float width; - float height; + pthread_mutexattr_destroy(&attributes); +} - bool dirty; -}; +FCriticalSection::~FCriticalSection() +{ + pthread_mutex_destroy(&m_mutex); +} -extern RenderBufferOptions rbOpts; +void FCriticalSection::Enter() +{ + pthread_mutex_lock(&m_mutex); +} -#endif // SRC_COCOA_I_RBOPTS_H_INCLUDED +void FCriticalSection::Leave() +{ + pthread_mutex_unlock(&m_mutex); +} diff --git a/src/cocoa/i_osversion.h b/src/posix/cocoa/critsec.h old mode 100755 new mode 100644 similarity index 86% rename from src/cocoa/i_osversion.h rename to src/posix/cocoa/critsec.h index 5e6ac6d20..7940dfe32 --- a/src/cocoa/i_osversion.h +++ b/src/posix/cocoa/critsec.h @@ -1,8 +1,8 @@ /* - ** i_osversion.h + ** critsec.h ** **--------------------------------------------------------------------------- - ** Copyright 2012-2014 Alexey Lysiuk + ** Copyright 2014 Alexey Lysiuk ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -31,13 +31,23 @@ ** */ -#include +#ifndef CRITSEC_H +#define CRITSEC_H -struct DarwinVersion +#include + +class FCriticalSection { - uint16_t major; - uint16_t minor; - uint16_t bugfix; +public: + FCriticalSection(); + ~FCriticalSection(); + + void Enter(); + void Leave(); + +private: + pthread_mutex_t m_mutex; + }; -extern const DarwinVersion darwinVersion; +#endif diff --git a/src/posix/cocoa/i_common.h b/src/posix/cocoa/i_common.h new file mode 100644 index 000000000..081466e87 --- /dev/null +++ b/src/posix/cocoa/i_common.h @@ -0,0 +1,168 @@ +/* + ** i_common.h + ** + **--------------------------------------------------------------------------- + ** 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. + **--------------------------------------------------------------------------- + ** + */ + +#import + + +struct RenderBufferOptions +{ + float pixelScale; + + float shiftX; + float shiftY; + + float width; + float height; + + bool dirty; +}; + +extern RenderBufferOptions rbOpts; + + +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_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 +}; + +#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 diff --git a/src/posix/cocoa/i_input.mm b/src/posix/cocoa/i_input.mm new file mode 100644 index 000000000..5e0c5f1c8 --- /dev/null +++ b/src/posix/cocoa/i_input.mm @@ -0,0 +1,740 @@ +/* + ** i_input.mm + ** + **--------------------------------------------------------------------------- + ** 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 "i_common.h" + +#import + +// 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" + +#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([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(posX); + outEvent->data2 = static_cast(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; + } +} diff --git a/src/posix/cocoa/i_joystick.cpp b/src/posix/cocoa/i_joystick.cpp new file mode 100644 index 000000000..9b9487cf6 --- /dev/null +++ b/src/posix/cocoa/i_joystick.cpp @@ -0,0 +1,1252 @@ +/* + ** i_joystick.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 +#include +#include +#include +#include + +#include "d_event.h" +#include "doomdef.h" +#include "i_system.h" +#include "m_argv.h" +#include "m_joy.h" +#include "templates.h" +#include "v_text.h" + + +EXTERN_CVAR(Bool, joy_axespolling) + + +namespace +{ + +FString ToFString(const CFStringRef string) +{ + if (NULL == string) + { + return FString(); + } + + const CFIndex stringLength = CFStringGetLength(string); + + if (0 == stringLength) + { + return FString(); + } + + const size_t bufferSize = CFStringGetMaximumSizeForEncoding(stringLength, kCFStringEncodingUTF8) + 1; + + char buffer[bufferSize]; + memset(buffer, 0, bufferSize); + + CFStringGetCString(string, buffer, bufferSize, kCFStringEncodingUTF8); + + return FString(buffer); +} + + +// --------------------------------------------------------------------------- + + +class IOKitJoystick : public IJoystickConfig +{ +public: + explicit IOKitJoystick(io_object_t device); + virtual ~IOKitJoystick(); + + virtual FString GetName(); + virtual float GetSensitivity(); + virtual void SetSensitivity(float scale); + + virtual int GetNumAxes(); + virtual float GetAxisDeadZone(int axis); + virtual EJoyAxis GetAxisMap(int axis); + virtual const char* GetAxisName(int axis); + virtual float GetAxisScale(int axis); + + virtual void SetAxisDeadZone(int axis, float deadZone); + virtual void SetAxisMap(int axis, EJoyAxis gameAxis); + virtual void SetAxisScale(int axis, float scale); + + virtual bool IsSensitivityDefault(); + virtual bool IsAxisDeadZoneDefault(int axis); + virtual bool IsAxisMapDefault(int axis); + virtual bool IsAxisScaleDefault(int axis); + + virtual void SetDefaultConfig(); + virtual FString GetIdentifier(); + + void AddAxes(float axes[NUM_JOYAXIS]) const; + + void Update(); + + void UseAxesPolling(bool axesPolling); + + io_object_t* GetNotificationPtr(); + +private: + IOHIDDeviceInterface** m_interface; + IOHIDQueueInterface** m_queue; + + FString m_name; + FString m_identifier; + + float m_sensitivity; + + struct AnalogAxis + { + IOHIDElementCookie cookie; + + char name[64]; + + float value; + + int32_t minValue; + int32_t maxValue; + + float deadZone; + float defaultDeadZone; + float sensitivity; + float defaultSensitivity; + + EJoyAxis gameAxis; + EJoyAxis defaultGameAxis; + + AnalogAxis() + { + memset(this, 0, sizeof *this); + } + }; + + TArray m_axes; + + struct DigitalButton + { + IOHIDElementCookie cookie; + int32_t value; + + DigitalButton(const IOHIDElementCookie cookie) + : cookie(cookie) + { } + }; + + TArray m_buttons; + TArray m_POVs; + + bool m_useAxesPolling; + + io_object_t m_notification; + + + static const float DEFAULT_DEADZONE; + static const float DEFAULT_SENSITIVITY; + + void ProcessAxes(); + bool ProcessAxis (const IOHIDEventStruct& event); + bool ProcessButton(const IOHIDEventStruct& event); + bool ProcessPOV (const IOHIDEventStruct& event); + + void GatherDeviceInfo(io_object_t device, CFDictionaryRef properties); + + static void GatherElementsHandler(const void* value, void* parameter); + void GatherCollectionElements(CFDictionaryRef properties); + + void AddAxis(CFDictionaryRef element); + void AddButton(CFDictionaryRef element); + void AddPOV(CFDictionaryRef element); + + void AddToQueue(IOHIDElementCookie cookie); + void RemoveFromQueue(IOHIDElementCookie cookie); +}; + + +const float IOKitJoystick::DEFAULT_DEADZONE = 0.25f; +const float IOKitJoystick::DEFAULT_SENSITIVITY = 1.0f; + + +IOHIDDeviceInterface** CreateDeviceInterface(const io_object_t device) +{ + IOCFPlugInInterface** plugInInterface = NULL; + SInt32 score = 0; + + const kern_return_t pluginResult = IOCreatePlugInInterfaceForService(device, + kIOHIDDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score); + + IOHIDDeviceInterface** interface = NULL; + + if (KERN_SUCCESS == pluginResult) + { + // Call a method of the intermediate plug-in to create the device interface + + const HRESULT queryResult = (*plugInInterface)->QueryInterface(plugInInterface, + CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), reinterpret_cast(&interface)); + + IODestroyPlugInInterface(plugInInterface); // [?] or maybe (*plugInInterface)->Release(plugInInterface); + + if (S_OK == queryResult) + { + const IOReturn openResult = (*interface)->open(interface, 0); + + if (kIOReturnSuccess != openResult) + { + (*interface)->Release(interface); + + Printf(TEXTCOLOR_RED "IOHIDDeviceInterface::open() failed with code 0x%08X\n", openResult); + return NULL; + } + } + else + { + Printf(TEXTCOLOR_RED "IOCFPlugInInterface::QueryInterface() failed with code 0x%08X\n", + static_cast(queryResult)); + return NULL; + } + } + else + { + Printf(TEXTCOLOR_RED "IOCreatePlugInInterfaceForService() failed with code %i\n", pluginResult); + return NULL; + } + + return interface; +} + +IOHIDQueueInterface** CreateDeviceQueue(IOHIDDeviceInterface** const interface) +{ + if (NULL == interface) + { + return NULL; + } + + IOHIDQueueInterface** queue = (*interface)->allocQueue(interface); + + if (NULL == queue) + { + Printf(TEXTCOLOR_RED "IOHIDDeviceInterface::allocQueue() failed\n"); + return NULL; + } + + static const uint32_t QUEUE_FLAGS = 0; + static const uint32_t QUEUE_DEPTH = 0; + + const IOReturn queueResult = (*queue)->create(queue, QUEUE_FLAGS, QUEUE_DEPTH); + + if (kIOReturnSuccess != queueResult) + { + (*queue)->Release(queue); + + Printf(TEXTCOLOR_RED "IOHIDQueueInterface::create() failed with code 0x%08X\n", queueResult); + return NULL; + } + + return queue; +} + + +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) + { + return; + } + + CFMutableDictionaryRef properties = NULL; + const kern_return_t propertiesResult = + IORegistryEntryCreateCFProperties(device, &properties, kCFAllocatorDefault, kNilOptions); + + if (KERN_SUCCESS != propertiesResult || NULL == properties) + { + Printf(TEXTCOLOR_RED "IORegistryEntryCreateCFProperties() failed with code %i\n", propertiesResult); + return; + } + + GatherDeviceInfo(device, properties); + GatherCollectionElements(properties); + + CFRelease(properties); + + UseAxesPolling(joy_axespolling); + + (*m_queue)->start(m_queue); + + SetDefaultConfig(); +} + +IOKitJoystick::~IOKitJoystick() +{ + M_SaveJoystickConfig(this); + + if (0 != m_notification) + { + IOObjectRelease(m_notification); + } + + if (NULL != m_queue) + { + (*m_queue)->stop(m_queue); + (*m_queue)->dispose(m_queue); + (*m_queue)->Release(m_queue); + } + + if (NULL != m_interface) + { + (*m_interface)->close(m_interface); + (*m_interface)->Release(m_interface); + } +} + + +FString IOKitJoystick::GetName() +{ + return m_name; +} + + +float IOKitJoystick::GetSensitivity() +{ + return m_sensitivity; +} + +void IOKitJoystick::SetSensitivity(float scale) +{ + m_sensitivity = scale; +} + + +int IOKitJoystick::GetNumAxes() +{ + return static_cast(m_axes.Size()); +} + +#define IS_AXIS_VALID (static_cast(axis) < m_axes.Size()) + +float IOKitJoystick::GetAxisDeadZone(int axis) +{ + return IS_AXIS_VALID ? m_axes[axis].deadZone : 0.0f; +} + +EJoyAxis IOKitJoystick::GetAxisMap(int axis) +{ + return IS_AXIS_VALID ? m_axes[axis].gameAxis : JOYAXIS_None; +} + +const char* IOKitJoystick::GetAxisName(int axis) +{ + return IS_AXIS_VALID ? m_axes[axis].name : "Invalid"; +} + +float IOKitJoystick::GetAxisScale(int axis) +{ + return IS_AXIS_VALID ? m_axes[axis].sensitivity : 0.0f; +} + +void IOKitJoystick::SetAxisDeadZone(int axis, float deadZone) +{ + if (IS_AXIS_VALID) + { + m_axes[axis].deadZone = clamp(deadZone, 0.0f, 1.0f); + } +} + +void IOKitJoystick::SetAxisMap(int axis, EJoyAxis gameAxis) +{ + if (IS_AXIS_VALID) + { + m_axes[axis].gameAxis = (gameAxis> JOYAXIS_None && gameAxis = 3) + { + m_axes[0].gameAxis = JOYAXIS_Side; + m_axes[1].gameAxis = JOYAXIS_Forward; + m_axes[2].gameAxis = JOYAXIS_Yaw; + + // Four axes? First two are movement, last two are looking around. + + if (axisCount >= 4) + { + m_axes[3].gameAxis = JOYAXIS_Pitch; +// ??? m_axes[3].sensitivity = 0.75f; + + // Five axes? Use the fifth one for moving up and down. + + if (axisCount >= 5) + { + m_axes[4].gameAxis = JOYAXIS_Up; + } + } + } + + // If there is only one axis, then we make no assumptions about how + // the user might want to use it. + + // Preserve defaults for config saving. + + for (size_t i = 0; i < axisCount; ++i) + { + m_axes[i].defaultDeadZone = m_axes[i].deadZone; + m_axes[i].defaultSensitivity = m_axes[i].sensitivity; + m_axes[i].defaultGameAxis = m_axes[i].gameAxis; + } +} + + +FString IOKitJoystick::GetIdentifier() +{ + return m_identifier; +} + + +void IOKitJoystick::AddAxes(float axes[NUM_JOYAXIS]) const +{ + for (size_t i = 0, count = m_axes.Size(); i < count; ++i) + { + const EJoyAxis axis = m_axes[i].gameAxis; + + if (JOYAXIS_None == axis) + { + continue; + } + + axes[axis] -= m_axes[i].value; + } +} + + +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) + { + return; + } + + IOHIDEventStruct event = { }; + AbsoluteTime zeroTime = { }; + + const IOReturn eventResult = (*m_queue)->getNextEvent(m_queue, &event, zeroTime, 0); + + if (kIOReturnSuccess == eventResult) + { + if (use_joystick) + { + ProcessAxis(event) || ProcessButton(event) || ProcessPOV(event); + } + } + else if (kIOReturnUnderrun != eventResult) + { + Printf(TEXTCOLOR_RED "IOHIDQueueInterface::getNextEvent() failed with code 0x%08X\n", eventResult); + } + + ProcessAxes(); +} + + +void IOKitJoystick::ProcessAxes() +{ + if (NULL == m_interface || !m_useAxesPolling) + { + return; + } + + for (size_t i = 0, count = m_axes.Size(); i < count; ++i) + { + AnalogAxis& axis = m_axes[i]; + + static const double scaledMin = -1; + static const double scaledMax = 1; + + IOHIDEventStruct event; + + if (kIOReturnSuccess == (*m_interface)->getElementValue(m_interface, axis.cookie, &event)) + { + const double scaledValue = scaledMin + + (event.value - axis.minValue) * (scaledMax - scaledMin) / (axis.maxValue - axis.minValue); + const double filteredValue = Joy_RemoveDeadZone(scaledValue, axis.deadZone, NULL); + + axis.value = static_cast(filteredValue * m_sensitivity * axis.sensitivity); + } + else + { + axis.value = 0.0f; + } + } +} + + +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) + { + continue; + } + + AnalogAxis& axis = m_axes[i]; + + static const double scaledMin = -1; + static const double scaledMax = 1; + + const double scaledValue = scaledMin + + (event.value - axis.minValue) * (scaledMax - scaledMin) / (axis.maxValue - axis.minValue); + const double filteredValue = Joy_RemoveDeadZone(scaledValue, axis.deadZone, NULL); + + axis.value = static_cast(filteredValue * m_sensitivity * axis.sensitivity); + + return true; + } + + return false; +} + +bool IOKitJoystick::ProcessButton(const IOHIDEventStruct& event) +{ + for (size_t i = 0, count = m_buttons.Size(); i < count; ++i) + { + if (event.elementCookie != m_buttons[i].cookie) + { + continue; + } + + int32_t& current = m_buttons[i].value; + const int32_t previous = current; + current = event.value; + + Joy_GenerateButtonEvents(previous, current, 1, static_cast(KEY_FIRSTJOYBUTTON + i)); + + return true; + } + + return false; +} + +bool IOKitJoystick::ProcessPOV(const IOHIDEventStruct& event) +{ + for (size_t i = 0, count = m_POVs.Size(); i ( + CFDictionaryGetValue(properties, CFSTR(kIOHIDManufacturerKey))); + CFStringRef productRef = static_cast( + CFDictionaryGetValue(properties, CFSTR(kIOHIDProductKey))); + CFNumberRef vendorIDRef = static_cast( + CFDictionaryGetValue(properties, CFSTR(kIOHIDVendorIDKey))); + CFNumberRef productIDRef = static_cast( + CFDictionaryGetValue(properties, CFSTR(kIOHIDProductIDKey))); + + CFMutableDictionaryRef usbProperties = NULL; + + if ( NULL == vendorRef || NULL == productRef + || NULL == vendorIDRef || NULL == productIDRef) + { + // OS X is not mirroring all USB properties to HID page, so need to look at USB device page also + // Step up two levels and get dictionary of USB properties + + io_registry_entry_t parent1; + kern_return_t ioResult = IORegistryEntryGetParentEntry(device, kIOServicePlane, &parent1); + + if (KERN_SUCCESS == ioResult) + { + io_registry_entry_t parent2; + ioResult = IORegistryEntryGetParentEntry(device, kIOServicePlane, &parent2); + + if (KERN_SUCCESS == ioResult) + { + ioResult = IORegistryEntryCreateCFProperties(parent2, &usbProperties, kCFAllocatorDefault, kNilOptions); + + if (KERN_SUCCESS != ioResult) + { + Printf(TEXTCOLOR_RED "IORegistryEntryCreateCFProperties() failed with code %i\n", ioResult); + } + + IOObjectRelease(parent2); + } + else + { + Printf(TEXTCOLOR_RED "IORegistryEntryGetParentEntry(2) failed with code %i\n", ioResult); + } + + IOObjectRelease(parent1); + } + else + { + Printf(TEXTCOLOR_RED "IORegistryEntryGetParentEntry(1) failed with code %i\n", ioResult); + } + } + + if (NULL != usbProperties) + { + if (NULL == vendorRef) + { + vendorRef = static_cast( + CFDictionaryGetValue(usbProperties, CFSTR("USB Vendor Name"))); + } + + if (NULL == productRef) + { + productRef = static_cast( + CFDictionaryGetValue(usbProperties, CFSTR("USB Product Name"))); + } + + if (NULL == vendorIDRef) + { + vendorIDRef = static_cast( + CFDictionaryGetValue(usbProperties, CFSTR("idVendor"))); + } + + if (NULL == productIDRef) + { + productIDRef = static_cast( + CFDictionaryGetValue(usbProperties, CFSTR("idProduct"))); + } + } + + m_name += ToFString(vendorRef); + m_name += " "; + m_name += ToFString(productRef); + + int vendorID = 0, productID = 0; + + if (NULL != vendorIDRef) + { + CFNumberGetValue(vendorIDRef, kCFNumberIntType, &vendorID); + } + + if (NULL != productIDRef) + { + CFNumberGetValue(productIDRef, kCFNumberIntType, &productID); + } + + m_identifier.AppendFormat("VID_%04x_PID_%04x", vendorID, productID); + + if (NULL != usbProperties) + { + CFRelease(usbProperties); + } +} + + +long GetElementValue(const CFDictionaryRef element, const CFStringRef key) +{ + const CFNumberRef number = + static_cast(CFDictionaryGetValue(element, key)); + long result = 0; + + if (NULL != number && CFGetTypeID(number) == CFNumberGetTypeID()) + { + CFNumberGetValue(number, kCFNumberLongType, &result); + } + + return result; +} + +void IOKitJoystick::GatherElementsHandler(const void* value, void* parameter) +{ + assert(NULL != value); + assert(NULL != parameter); + + const CFDictionaryRef element = static_cast(value); + IOKitJoystick* thisPtr = static_cast(parameter); + + if (CFGetTypeID(element) != CFDictionaryGetTypeID()) + { + Printf(TEXTCOLOR_RED "IOKitJoystick: Encountered wrong element type\n"); + return; + } + + const long type = GetElementValue(element, CFSTR(kIOHIDElementTypeKey)); + + if (kIOHIDElementTypeCollection == type) + { + thisPtr->GatherCollectionElements(element); + } + else if (0 != type) + { + const long usagePage = GetElementValue(element, CFSTR(kIOHIDElementUsagePageKey)); + + if (kHIDPage_GenericDesktop == usagePage) + { + const long usage = GetElementValue(element, CFSTR(kIOHIDElementUsageKey)); + + if ( kHIDUsage_GD_Slider == usage + || kHIDUsage_GD_X == usage || kHIDUsage_GD_Y == usage || kHIDUsage_GD_Z == usage + || kHIDUsage_GD_Rx == usage || kHIDUsage_GD_Ry == usage || kHIDUsage_GD_Rz == usage) + { + thisPtr->AddAxis(element); + } + else if (kHIDUsage_GD_Hatswitch == usage && thisPtr->m_POVs.Size() < 4) + { + thisPtr->AddPOV(element); + } + } + else if (kHIDPage_Button == usagePage) + { + thisPtr->AddButton(element); + } + } +} + +void IOKitJoystick::GatherCollectionElements(const CFDictionaryRef properties) +{ + const CFArrayRef topElement = static_cast( + CFDictionaryGetValue(properties, CFSTR(kIOHIDElementKey))); + + if (NULL == topElement || CFGetTypeID(topElement) != CFArrayGetTypeID()) + { + Printf(TEXTCOLOR_RED "GatherCollectionElements: invalid properties dictionary\n"); + return; + } + + const CFRange range = { 0, CFArrayGetCount(topElement) }; + + CFArrayApplyFunction(topElement, range, GatherElementsHandler, this); +} + + +IOHIDElementCookie GetElementCookie(const CFDictionaryRef element) +{ + // Use C-style cast to avoid 32/64-bit IOHIDElementCookie type issue + return (IOHIDElementCookie)GetElementValue(element, CFSTR(kIOHIDElementCookieKey)); +} + +void IOKitJoystick::AddAxis(const CFDictionaryRef element) +{ + AnalogAxis axis; + + axis.cookie = GetElementCookie(element); + axis.minValue = GetElementValue(element, CFSTR(kIOHIDElementMinKey)); + axis.maxValue = GetElementValue(element, CFSTR(kIOHIDElementMaxKey)); + + const CFStringRef nameRef = static_cast( + CFDictionaryGetValue(element, CFSTR(kIOHIDElementNameKey))); + + if (NULL != nameRef && CFStringGetTypeID() == CFGetTypeID(nameRef)) + { + CFStringGetCString(nameRef, axis.name, sizeof(axis.name) - 1, kCFStringEncodingUTF8); + } + else + { + snprintf(axis.name, sizeof(axis.name), "Axis %i", m_axes.Size() + 1); + } + + m_axes.Push(axis); +} + +void IOKitJoystick::AddButton(CFDictionaryRef element) +{ + const DigitalButton button(GetElementCookie(element)); + + m_buttons.Push(button); + + AddToQueue(button.cookie); +} + +void IOKitJoystick::AddPOV(CFDictionaryRef element) +{ + const DigitalButton pov(GetElementCookie(element)); + + m_POVs.Push(pov); + + AddToQueue(pov.cookie); +} + + +void IOKitJoystick::AddToQueue(const IOHIDElementCookie cookie) +{ + if (NULL == m_queue) + { + return; + } + + if (!(*m_queue)->hasElement(m_queue, cookie)) + { + (*m_queue)->addElement(m_queue, cookie, 0); + } +} + +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; +} + + +// --------------------------------------------------------------------------- + + +class IOKitJoystickManager +{ +public: + IOKitJoystickManager(); + ~IOKitJoystickManager(); + + void GetJoysticks(TArray& joysticks) const; + + void AddAxes(float axes[NUM_JOYAXIS]) const; + + // Updates axes/buttons states + void Update(); + + void UseAxesPolling(bool axesPolling); + +private: + typedef TDeletingArray JoystickList; + JoystickList m_joysticks; + + static const size_t NOTIFICATION_PORT_COUNT = 2; + + 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() +{ + 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() +{ + 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; + } + } +} + + +void IOKitJoystickManager::GetJoysticks(TArray& joysticks) const +{ + const size_t joystickCount = m_joysticks.Size(); + + joysticks.Resize(joystickCount); + + for (size_t i = 0; i < joystickCount; ++i) + { + M_LoadJoystickConfig(m_joysticks[i]); + + joysticks[i] = m_joysticks[i]; + } +} + +void IOKitJoystickManager::AddAxes(float axes[NUM_JOYAXIS]) const +{ + for (size_t i = 0, count = m_joysticks.Size(); i < count; ++i) + { + m_joysticks[i]->AddAxes(axes); + } +} + + +void IOKitJoystickManager::Update() +{ + for (size_t i = 0, count = m_joysticks.Size(); i < count; ++i) + { + m_joysticks[i]->Update(); + } +} + + +void IOKitJoystickManager::UseAxesPolling(const bool axesPolling) +{ + for (size_t i = 0, count = m_joysticks.Size(); i < count; ++i) + { + m_joysticks[i]->UseAxesPolling(axesPolling); + } +} + + +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); + + if (NULL == deviceMatching) + { + Printf(TEXTCOLOR_RED "IOServiceMatching() returned NULL\n"); + return; + } + + const CFNumberRef usagePageRef = + CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usagePage); + CFDictionarySetValue(deviceMatching, CFSTR(kIOHIDPrimaryUsagePageKey), usagePageRef); + + const CFNumberRef usageRef = + CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage); + CFDictionarySetValue(deviceMatching, CFSTR(kIOHIDPrimaryUsageKey), usageRef); + + 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 != notificationResult) + { + 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(); + } +} + + +void IOKitJoystickManager::OnDeviceAttached(void* const refcon, const io_iterator_t iterator) +{ + assert(NULL != refcon); + const IONotificationPortRef notificationPort = static_cast(refcon); + + 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; + } + + assert(NULL != refcon); + IOKitJoystick* const joystick = static_cast(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 + + +// --------------------------------------------------------------------------- + + +void I_ShutdownJoysticks() +{ + // Needed in order to support existing interface + // Left empty intentionally +} + +static void ShutdownJoysticks() +{ + delete s_joystickManager; + s_joystickManager = NULL; +} + +void I_GetJoysticks(TArray& sticks) +{ + // Instances of IOKitJoystick depend on GameConfig object. + // M_SaveDefaultsFinal() must be called after destruction of IOKitJoystickManager. + // To ensure this, its initialization is moved here. + // As M_LoadDefaults() was already called at this moment, + // the order of atterm's functions will be correct + + if (NULL == s_joystickManager && !Args->CheckParm("-nojoy")) + { + s_joystickManager = new IOKitJoystickManager; + atterm(ShutdownJoysticks); + } + + if (NULL != s_joystickManager) + { + s_joystickManager->GetJoysticks(sticks); + } +} + +void I_GetAxes(float axes[NUM_JOYAXIS]) +{ + for (size_t i = 0; i < NUM_JOYAXIS; ++i) + { + axes[i] = 0.0f; + } + + if (use_joystick && NULL != s_joystickManager) + { + s_joystickManager->AddAxes(axes); + } +} + +IJoystickConfig* I_UpdateDeviceList() +{ + // Does nothing, device list is always kept up-to-date + + return NULL; +} + + +// --------------------------------------------------------------------------- + + +void I_ProcessJoysticks() +{ + if (NULL != s_joystickManager) + { + s_joystickManager->Update(); + } +} + + +// --------------------------------------------------------------------------- + + +CUSTOM_CVAR(Bool, joy_axespolling, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) +{ + if (NULL != s_joystickManager) + { + s_joystickManager->UseAxesPolling(self); + } +} diff --git a/src/posix/cocoa/i_main.mm b/src/posix/cocoa/i_main.mm new file mode 100644 index 000000000..05a8081f6 --- /dev/null +++ b/src/posix/cocoa/i_main.mm @@ -0,0 +1,551 @@ +/* + ** i_main.mm + ** + **--------------------------------------------------------------------------- + ** 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 "i_common.h" + +#include +#include + +// 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" + +#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 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(screenSize.width); + vid_defheight = static_cast(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 += "/"; + + 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 + +#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]; +} + +void ReleaseApplicationController() +{ + if (NULL != appCtrl) + { + [NSApp setDelegate:nil]; + [NSApp deactivate]; + + [appCtrl release]; + appCtrl = NULL; + } +} + +} // unnamed namespace + + +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; +} diff --git a/src/cocoa/i_timer.cpp b/src/posix/cocoa/i_timer.cpp similarity index 55% rename from src/cocoa/i_timer.cpp rename to src/posix/cocoa/i_timer.cpp index 0699a9967..b08a43139 100644 --- a/src/cocoa/i_timer.cpp +++ b/src/posix/cocoa/i_timer.cpp @@ -1,11 +1,42 @@ +/* + ** 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 +#include #include #include #include -#include - #include "basictypes.h" #include "basicinlines.h" #include "doomdef.h" @@ -13,23 +44,25 @@ #include "templates.h" -unsigned int I_MSTime() -{ - return SDL_GetTicks(); -} - -unsigned int I_FPSTime() -{ - return SDL_GetTicks(); -} - - -bool g_isTicFrozen; - - namespace { +timeval s_gameStartTicks; +timeval s_systemBootTicks; + +unsigned int GetMillisecondsSince(const timeval& time) +{ + timeval now; + gettimeofday(&now, NULL); + + return static_cast( + (now.tv_sec - time.tv_sec ) * 1000 + + (now.tv_usec - time.tv_usec) / 1000); +} + + +bool s_isTicFrozen; + timespec GetNextTickTime() { static const long MILLISECONDS_IN_SECOND = 1000; @@ -91,7 +124,7 @@ void* TimerThreadFunc(void*) pthread_mutex_lock(&s_timerMutex); pthread_cond_timedwait(&s_timerEvent, &s_timerMutex, &timeToNextTick); - if (!g_isTicFrozen) + if (!s_isTicFrozen) { // The following GCC/Clang intrinsic can be used instead of OS X specific function: // __sync_add_and_fetch(&s_tics, 1); @@ -101,7 +134,7 @@ void* TimerThreadFunc(void*) OSAtomicIncrement32(&s_tics); } - s_timerStart = SDL_GetTicks(); + s_timerStart = I_MSTime(); pthread_cond_broadcast(&s_timerEvent); pthread_mutex_unlock(&s_timerMutex); @@ -122,7 +155,7 @@ int GetTimeThreaded(bool saveMS) int WaitForTicThreaded(int prevTic) { - assert(!g_isTicFrozen); + assert(!s_isTicFrozen); while (s_tics <= prevTic) { @@ -136,15 +169,26 @@ int WaitForTicThreaded(int prevTic) void FreezeTimeThreaded(bool frozen) { - g_isTicFrozen = frozen; + s_isTicFrozen = frozen; } } // unnamed namespace +unsigned int I_MSTime() +{ + return GetMillisecondsSince(s_gameStartTicks); +} + +unsigned int I_FPSTime() +{ + return GetMillisecondsSince(s_systemBootTicks); +} + + fixed_t I_GetTimeFrac(uint32* ms) { - const uint32_t now = SDL_GetTicks(); + const uint32_t now = I_MSTime(); if (NULL != ms) { @@ -157,11 +201,18 @@ fixed_t I_GetTimeFrac(uint32* ms) } -void I_InitTimer () +void I_InitTimer() { assert(!s_timerInitialized); s_timerInitialized = true; + gettimeofday(&s_gameStartTicks, NULL); + + int mib[2] = { CTL_KERN, KERN_BOOTTIME }; + size_t len = sizeof s_systemBootTicks; + + sysctl(mib, 2, &s_systemBootTicks, &len, NULL, 0); + pthread_cond_init (&s_timerEvent, NULL); pthread_mutex_init(&s_timerMutex, NULL); @@ -172,7 +223,7 @@ void I_InitTimer () I_FreezeTime = FreezeTimeThreaded; } -void I_ShutdownTimer () +void I_ShutdownTimer() { if (!s_timerInitialized) { diff --git a/src/posix/cocoa/i_video.mm b/src/posix/cocoa/i_video.mm new file mode 100644 index 000000000..57f7c16fd --- /dev/null +++ b/src/posix/cocoa/i_video.mm @@ -0,0 +1,1232 @@ +/* + ** i_video.mm + ** + **--------------------------------------------------------------------------- + ** 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 "i_common.h" + +#import +#import + +// Avoid collision between DObject class and Objective-C +#define Class ObjectClass + +#include "bitmap.h" +#include "c_dispatch.h" +#include "doomstat.h" +#include "hardware.h" +#include "i_system.h" +#include "m_argv.h" +#include "r_renderer.h" +#include "r_swrenderer.h" +#include "stats.h" +#include "textures.h" +#include "v_palette.h" +#include "v_pfx.h" +#include "v_text.h" +#include "v_video.h" +#include "version.h" + +#undef Class + + +EXTERN_CVAR(Bool, ticker ) +EXTERN_CVAR(Bool, vid_vsync) +EXTERN_CVAR(Bool, vid_hidpi) + +CUSTOM_CVAR(Bool, fullscreen, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + extern int NewWidth, NewHeight, NewBits, DisplayBits; + + NewWidth = screen->GetWidth(); + NewHeight = screen->GetHeight(); + NewBits = DisplayBits; + setmodeneeded = true; +} + + +RenderBufferOptions rbOpts; + + +// --------------------------------------------------------------------------- + + +namespace +{ + const NSInteger LEVEL_FULLSCREEN = NSMainMenuWindowLevel + 1; + const NSInteger LEVEL_WINDOWED = NSNormalWindowLevel; + + const NSUInteger STYLE_MASK_FULLSCREEN = NSBorderlessWindowMask; + const NSUInteger STYLE_MASK_WINDOWED = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask; +} + + +// --------------------------------------------------------------------------- + + +@interface CocoaWindow : NSWindow +{ +} + +- (BOOL)canBecomeKeyWindow; + +@end + + +@implementation CocoaWindow + +- (BOOL)canBecomeKeyWindow +{ + return true; +} + +@end + + +// --------------------------------------------------------------------------- + + +@interface CocoaView : NSOpenGLView +{ + NSCursor* m_cursor; +} + +- (void)resetCursorRects; + +- (void)setCursor:(NSCursor*)cursor; + +@end + + +@implementation CocoaView + +- (void)resetCursorRects +{ + [super resetCursorRects]; + + NSCursor* const cursor = nil == m_cursor + ? [NSCursor arrowCursor] + : m_cursor; + + [self addCursorRect:[self bounds] + cursor:cursor]; +} + +- (void)setCursor:(NSCursor*)cursor +{ + m_cursor = cursor; +} + +@end + + + +// --------------------------------------------------------------------------- + + +class CocoaVideo : public IVideo +{ +public: + explicit CocoaVideo(int multisample); + + virtual EDisplayType GetDisplayType() { return DISPLAY_Both; } + virtual void SetWindowedScale(float scale); + + virtual DFrameBuffer* CreateFrameBuffer(int width, int height, bool fs, DFrameBuffer* old); + + virtual void StartModeIterator(int bits, bool fullscreen); + virtual bool NextMode(int* width, int* height, bool* letterbox); + + static bool IsFullscreen(); + static void UseHiDPI(bool hiDPI); + static void SetCursor(NSCursor* cursor); + static void SetWindowVisible(bool visible); + +private: + struct ModeIterator + { + size_t index; + int bits; + bool fullscreen; + }; + + ModeIterator m_modeIterator; + + CocoaWindow* m_window; + + int m_width; + int m_height; + bool m_fullscreen; + bool m_hiDPI; + + void SetStyleMask(NSUInteger styleMask); + void SetFullscreenMode(int width, int height); + void SetWindowedMode(int width, int height); + void SetMode(int width, int height, bool fullscreen, bool hiDPI); + + static CocoaVideo* GetInstance(); +}; + + +class CocoaFrameBuffer : public DFrameBuffer +{ +public: + CocoaFrameBuffer(int width, int height, bool fullscreen); + ~CocoaFrameBuffer(); + + virtual bool Lock(bool buffer); + virtual void Unlock(); + virtual void Update(); + + virtual PalEntry* GetPalette(); + virtual void GetFlashedPalette(PalEntry pal[256]); + virtual void UpdatePalette(); + + virtual bool SetGamma(float gamma); + virtual bool SetFlash(PalEntry rgb, int amount); + virtual void GetFlash(PalEntry &rgb, int &amount); + + virtual int GetPageCount(); + + virtual bool IsFullscreen(); + + virtual void SetVSync(bool vsync); + +private: + static const size_t BYTES_PER_PIXEL = 4; + + PalEntry m_palette[256]; + bool m_needPaletteUpdate; + + BYTE m_gammaTable[3][256]; + float m_gamma; + bool m_needGammaUpdate; + + PalEntry m_flashColor; + int m_flashAmount; + + bool m_isUpdatePending; + + uint8_t* m_pixelBuffer; + GLuint m_texture; + + void Flip(); + + void UpdateColors(); +}; + + +// --------------------------------------------------------------------------- + + +EXTERN_CVAR(Float, Gamma) + +CUSTOM_CVAR(Float, rgamma, 1.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (NULL != screen) + { + screen->SetGamma(Gamma); + } +} + +CUSTOM_CVAR(Float, ggamma, 1.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (NULL != screen) + { + screen->SetGamma(Gamma); + } +} + +CUSTOM_CVAR(Float, bgamma, 1.0f, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (NULL != screen) + { + screen->SetGamma(Gamma); + } +} + + +// --------------------------------------------------------------------------- + + +extern id appCtrl; + + +namespace +{ + +const struct +{ + uint16_t width; + uint16_t height; +} +VideoModes[] = +{ + { 320, 200 }, + { 320, 240 }, + { 400, 225 }, // 16:9 + { 400, 300 }, + { 480, 270 }, // 16:9 + { 480, 360 }, + { 512, 288 }, // 16:9 + { 512, 384 }, + { 640, 360 }, // 16:9 + { 640, 400 }, + { 640, 480 }, + { 720, 480 }, // 16:10 + { 720, 540 }, + { 800, 450 }, // 16:9 + { 800, 480 }, + { 800, 500 }, // 16:10 + { 800, 600 }, + { 848, 480 }, // 16:9 + { 960, 600 }, // 16:10 + { 960, 720 }, + { 1024, 576 }, // 16:9 + { 1024, 600 }, // 17:10 + { 1024, 640 }, // 16:10 + { 1024, 768 }, + { 1088, 612 }, // 16:9 + { 1152, 648 }, // 16:9 + { 1152, 720 }, // 16:10 + { 1152, 864 }, + { 1280, 720 }, // 16:9 + { 1280, 854 }, + { 1280, 800 }, // 16:10 + { 1280, 960 }, + { 1280, 1024 }, // 5:4 + { 1360, 768 }, // 16:9 + { 1366, 768 }, + { 1400, 787 }, // 16:9 + { 1400, 875 }, // 16:10 + { 1400, 1050 }, + { 1440, 900 }, + { 1440, 960 }, + { 1440, 1080 }, + { 1600, 900 }, // 16:9 + { 1600, 1000 }, // 16:10 + { 1600, 1200 }, + { 1920, 1080 }, + { 1920, 1200 }, + { 2048, 1536 }, + { 2560, 1440 }, + { 2560, 1600 }, + { 2560, 2048 }, + { 2880, 1800 }, + { 3200, 1800 }, + { 3840, 2160 }, + { 3840, 2400 }, + { 4096, 2160 }, + { 5120, 2880 } +}; + + +cycle_t BlitCycles; +cycle_t FlipCycles; + + +CocoaWindow* CreateCocoaWindow(const NSUInteger styleMask) +{ + static const CGFloat TEMP_WIDTH = VideoModes[0].width - 1; + static const CGFloat TEMP_HEIGHT = VideoModes[0].height - 1; + + CocoaWindow* const window = [CocoaWindow alloc]; + [window initWithContentRect:NSMakeRect(0, 0, TEMP_WIDTH, TEMP_HEIGHT) + styleMask:styleMask + backing:NSBackingStoreBuffered + defer:NO]; + [window setOpaque:YES]; + [window makeFirstResponder:appCtrl]; + [window setAcceptsMouseMovedEvents:YES]; + + return window; +} + +} // unnamed namespace + + +// --------------------------------------------------------------------------- + + +CocoaVideo::CocoaVideo(const int multisample) +: m_window(CreateCocoaWindow(STYLE_MASK_WINDOWED)) +, m_width(-1) +, m_height(-1) +, m_fullscreen(false) +, m_hiDPI(false) +{ + memset(&m_modeIterator, 0, sizeof m_modeIterator); + + // Set attributes for OpenGL context + + NSOpenGLPixelFormatAttribute attributes[16]; + size_t i = 0; + + attributes[i++] = NSOpenGLPFADoubleBuffer; + attributes[i++] = NSOpenGLPFAColorSize; + attributes[i++] = NSOpenGLPixelFormatAttribute(32); + attributes[i++] = NSOpenGLPFADepthSize; + attributes[i++] = NSOpenGLPixelFormatAttribute(24); + attributes[i++] = NSOpenGLPFAStencilSize; + attributes[i++] = NSOpenGLPixelFormatAttribute(8); + + if (multisample) + { + attributes[i++] = NSOpenGLPFAMultisample; + attributes[i++] = NSOpenGLPFASampleBuffers; + attributes[i++] = NSOpenGLPixelFormatAttribute(1); + attributes[i++] = NSOpenGLPFASamples; + attributes[i++] = NSOpenGLPixelFormatAttribute(multisample); + } + + attributes[i] = NSOpenGLPixelFormatAttribute(0); + + // Create OpenGL context and view + + NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; + + const NSRect contentRect = [m_window contentRectForFrameRect:[m_window frame]]; + NSOpenGLView* glView = [[CocoaView alloc] initWithFrame:contentRect + pixelFormat:pixelFormat]; + [[glView openGLContext] makeCurrentContext]; + + [m_window setContentView:glView]; +} + +void CocoaVideo::StartModeIterator(const int bits, const bool fullscreen) +{ + m_modeIterator.index = 0; + m_modeIterator.bits = bits; + m_modeIterator.fullscreen = fullscreen; +} + +bool CocoaVideo::NextMode(int* const width, int* const height, bool* const letterbox) +{ + assert(NULL != width); + assert(NULL != height); + + const int bits = m_modeIterator.bits; + + if (8 != bits && 16 != bits && 24 != bits && 32 != bits) + { + return false; + } + + size_t& index = m_modeIterator.index; + + if (index < sizeof(VideoModes) / sizeof(VideoModes[0])) + { + *width = VideoModes[index].width; + *height = VideoModes[index].height; + + if (m_modeIterator.fullscreen && NULL != letterbox) + { + const NSSize screenSize = [[m_window screen] frame].size; + const float screenRatio = screenSize.width / screenSize.height; + const float modeRatio = float(*width) / *height; + + *letterbox = fabs(screenRatio - modeRatio) > 0.001f; + } + + ++index; + + return true; + } + + return false; +} + +DFrameBuffer* CocoaVideo::CreateFrameBuffer(const int width, const int height, const bool fullscreen, DFrameBuffer* const old) +{ + PalEntry flashColor = 0; + int flashAmount = 0; + + if (NULL != old) + { + if (width == m_width && height == m_height) + { + SetMode(width, height, fullscreen, vid_hidpi); + return old; + } + + old->GetFlash(flashColor, flashAmount); + old->ObjectFlags |= OF_YesReallyDelete; + + if (old == screen) + { + screen = NULL; + } + + delete old; + } + + CocoaFrameBuffer* fb = new CocoaFrameBuffer(width, height, fullscreen); + fb->SetFlash(flashColor, flashAmount); + + SetMode(width, height, fullscreen, vid_hidpi); + + return fb; +} + +void CocoaVideo::SetWindowedScale(float scale) +{ +} + + +bool CocoaVideo::IsFullscreen() +{ + CocoaVideo* const video = GetInstance(); + return NULL == video + ? false + : video->m_fullscreen; +} + +void CocoaVideo::UseHiDPI(const bool hiDPI) +{ + if (CocoaVideo* const video = GetInstance()) + { + video->SetMode(video->m_width, video->m_height, video->m_fullscreen, hiDPI); + } +} + +void CocoaVideo::SetCursor(NSCursor* cursor) +{ + if (CocoaVideo* const video = GetInstance()) + { + NSWindow* const window = video->m_window; + CocoaView* const view = [window contentView]; + + [view setCursor:cursor]; + [window invalidateCursorRectsForView:view]; + } +} + +void CocoaVideo::SetWindowVisible(bool visible) +{ + if (CocoaVideo* const video = GetInstance()) + { + if (visible) + { + [video->m_window orderFront:nil]; + } + else + { + [video->m_window orderOut:nil]; + } + } +} + + +static bool HasModernFullscreenAPI() +{ + // The following value shoud be equal to NSAppKitVersionNumber10_6 + // and it's hard-coded in order to build on earlier SDKs + + return NSAppKitVersionNumber >= 1038; +} + +void CocoaVideo::SetStyleMask(const NSUInteger styleMask) +{ + // Before 10.6 it's impossible to change window's style mask + // To workaround this new window should be created with required style mask + // This method should not be called when running on Snow Leopard or newer + + assert(!HasModernFullscreenAPI()); + + CocoaWindow* tempWindow = CreateCocoaWindow(styleMask); + [tempWindow setContentView:[m_window contentView]]; + + [m_window close]; + m_window = tempWindow; +} + +void CocoaVideo::SetFullscreenMode(const int width, const int height) +{ + NSScreen* screen = [m_window screen]; + + const NSRect screenFrame = [screen frame]; + const NSRect displayRect = vid_hidpi + ? [screen convertRectToBacking:screenFrame] + : screenFrame; + + const float displayWidth = displayRect.size.width; + const float displayHeight = displayRect.size.height; + + const float pixelScaleFactorX = displayWidth / static_cast(width ); + const float pixelScaleFactorY = displayHeight / static_cast(height); + + rbOpts.pixelScale = MIN(pixelScaleFactorX, pixelScaleFactorY); + + rbOpts.width = width * rbOpts.pixelScale; + rbOpts.height = height * rbOpts.pixelScale; + + rbOpts.shiftX = (displayWidth - rbOpts.width ) / 2.0f; + rbOpts.shiftY = (displayHeight - rbOpts.height) / 2.0f; + + if (!m_fullscreen) + { + if (HasModernFullscreenAPI()) + { + [m_window setLevel:LEVEL_FULLSCREEN]; + [m_window setStyleMask:STYLE_MASK_FULLSCREEN]; + } + else + { + // Old Carbon-based way to make fullscreen window above dock and menu + // It's supported on 64-bit, but on 10.6 and later the following is preferred: + // [NSWindow setLevel:NSMainMenuWindowLevel + 1] + + SetSystemUIMode(kUIModeAllHidden, 0); + SetStyleMask(STYLE_MASK_FULLSCREEN); + } + + [m_window setHidesOnDeactivate:YES]; + } + + [m_window setFrame:displayRect display:YES]; + [m_window setFrameOrigin:NSMakePoint(0.0f, 0.0f)]; +} + +void CocoaVideo::SetWindowedMode(const int width, const int height) +{ + rbOpts.pixelScale = 1.0f; + + rbOpts.width = static_cast(width ); + rbOpts.height = static_cast(height); + + rbOpts.shiftX = 0.0f; + rbOpts.shiftY = 0.0f; + + const NSSize windowPixelSize = NSMakeSize(width, height); + const NSSize windowSize = vid_hidpi + ? [[m_window contentView] convertSizeFromBacking:windowPixelSize] + : windowPixelSize; + + if (m_fullscreen) + { + if (HasModernFullscreenAPI()) + { + [m_window setLevel:LEVEL_WINDOWED]; + [m_window setStyleMask:STYLE_MASK_WINDOWED]; + } + else + { + SetSystemUIMode(kUIModeNormal, 0); + SetStyleMask(STYLE_MASK_WINDOWED); + } + + [m_window setHidesOnDeactivate:NO]; + } + + [m_window setContentSize:windowSize]; + [m_window center]; + + NSButton* closeButton = [m_window standardWindowButton:NSWindowCloseButton]; + [closeButton setAction:@selector(terminate:)]; + [closeButton setTarget:NSApp]; +} + +void CocoaVideo::SetMode(const int width, const int height, const bool fullscreen, const bool hiDPI) +{ + if (fullscreen == m_fullscreen + && width == m_width + && height == m_height + && hiDPI == m_hiDPI) + { + return; + } + + if (I_IsHiDPISupported()) + { + NSOpenGLView* const glView = [m_window contentView]; + [glView setWantsBestResolutionOpenGLSurface:hiDPI]; + } + + if (fullscreen) + { + SetFullscreenMode(width, height); + } + else + { + SetWindowedMode(width, height); + } + + rbOpts.dirty = true; + + const NSSize viewSize = I_GetContentViewSize(m_window); + + glViewport(0, 0, static_cast(viewSize.width), static_cast(viewSize.height)); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + [[NSOpenGLContext currentContext] flushBuffer]; + + static NSString* const TITLE_STRING = + [NSString stringWithFormat:@"%s %s", GAMESIG, GetVersionString()]; + [m_window setTitle:TITLE_STRING]; + + if (![m_window isKeyWindow]) + { + [m_window makeKeyAndOrderFront:nil]; + } + + m_fullscreen = fullscreen; + m_width = width; + m_height = height; + m_hiDPI = hiDPI; +} + + +CocoaVideo* CocoaVideo::GetInstance() +{ + return static_cast(Video); +} + + +CocoaFrameBuffer::CocoaFrameBuffer(int width, int height, bool fullscreen) +: DFrameBuffer(width, height) +, m_needPaletteUpdate(false) +, m_gamma(0.0f) +, m_needGammaUpdate(false) +, m_flashAmount(0) +, m_isUpdatePending(false) +, m_pixelBuffer(new uint8_t[width * height * BYTES_PER_PIXEL]) +, m_texture(0) +{ + glEnable(GL_TEXTURE_RECTANGLE_ARB); + + glGenTextures(1, &m_texture); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, m_texture); + glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE); + + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0.0, width, height, 0.0, -1.0, 1.0); + + GPfx.SetFormat(32, 0x000000FF, 0x0000FF00, 0x00FF0000); + + for (size_t i = 0; i < 256; ++i) + { + m_gammaTable[0][i] = m_gammaTable[1][i] = m_gammaTable[2][i] = i; + } + + memcpy(m_palette, GPalette.BaseColors, sizeof(PalEntry) * 256); + UpdateColors(); + + SetVSync(vid_vsync); +} + + +CocoaFrameBuffer::~CocoaFrameBuffer() +{ + glBindTexture(GL_TEXTURE_2D, 0); + glDeleteTextures(1, &m_texture); + + delete[] m_pixelBuffer; +} + +int CocoaFrameBuffer::GetPageCount() +{ + return 1; +} + +bool CocoaFrameBuffer::Lock(bool buffered) +{ + return DSimpleCanvas::Lock(buffered); +} + +void CocoaFrameBuffer::Unlock() +{ + if (m_isUpdatePending && LockCount == 1) + { + Update(); + } + else if (--LockCount <= 0) + { + Buffer = NULL; + LockCount = 0; + } +} + +void CocoaFrameBuffer::Update() +{ + if (LockCount != 1) + { + if (LockCount > 0) + { + m_isUpdatePending = true; + --LockCount; + } + return; + } + + DrawRateStuff(); + + Buffer = NULL; + LockCount = 0; + m_isUpdatePending = false; + + BlitCycles.Reset(); + FlipCycles.Reset(); + BlitCycles.Clock(); + + GPfx.Convert(MemBuffer, Pitch, m_pixelBuffer, Width * BYTES_PER_PIXEL, + Width, Height, FRACUNIT, FRACUNIT, 0, 0); + + FlipCycles.Clock(); + Flip(); + FlipCycles.Unclock(); + + BlitCycles.Unclock(); + + if (m_needGammaUpdate) + { + CalcGamma(rgamma == 0.0f ? m_gamma : m_gamma * rgamma, m_gammaTable[0]); + CalcGamma(ggamma == 0.0f ? m_gamma : m_gamma * ggamma, m_gammaTable[1]); + CalcGamma(bgamma == 0.0f ? m_gamma : m_gamma * bgamma, m_gammaTable[2]); + + m_needGammaUpdate = false; + m_needPaletteUpdate = true; + } + + if (m_needPaletteUpdate) + { + m_needPaletteUpdate = false; + UpdateColors(); + } +} + +void CocoaFrameBuffer::UpdateColors() +{ + PalEntry palette[256]; + + for (size_t i = 0; i < 256; ++i) + { + palette[i].r = m_gammaTable[0][m_palette[i].r]; + palette[i].g = m_gammaTable[1][m_palette[i].g]; + palette[i].b = m_gammaTable[2][m_palette[i].b]; + } + + if (0 != m_flashAmount) + { + DoBlending(palette, palette, 256, + m_gammaTable[0][m_flashColor.r], + m_gammaTable[1][m_flashColor.g], + m_gammaTable[2][m_flashColor.b], + m_flashAmount); + } + + GPfx.SetPalette(palette); +} + +PalEntry* CocoaFrameBuffer::GetPalette() +{ + return m_palette; +} + +void CocoaFrameBuffer::UpdatePalette() +{ + m_needPaletteUpdate = true; +} + +bool CocoaFrameBuffer::SetGamma(float gamma) +{ + m_gamma = gamma; + m_needGammaUpdate = true; + + return true; +} + +bool CocoaFrameBuffer::SetFlash(PalEntry rgb, int amount) +{ + m_flashColor = rgb; + m_flashAmount = amount; + m_needPaletteUpdate = true; + + return true; +} + +void CocoaFrameBuffer::GetFlash(PalEntry &rgb, int &amount) +{ + rgb = m_flashColor; + amount = m_flashAmount; +} + +void CocoaFrameBuffer::GetFlashedPalette(PalEntry pal[256]) +{ + memcpy(pal, m_palette, sizeof m_palette); + + if (0 != m_flashAmount) + { + DoBlending(pal, pal, 256, + m_flashColor.r, m_flashColor.g, m_flashColor.b, + m_flashAmount); + } +} + +bool CocoaFrameBuffer::IsFullscreen() +{ + return CocoaVideo::IsFullscreen(); +} + +void CocoaFrameBuffer::SetVSync(bool vsync) +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050 + const long value = vsync ? 1 : 0; +#else // 10.5 or newer + const GLint value = vsync ? 1 : 0; +#endif // prior to 10.5 + + [[NSOpenGLContext currentContext] setValues:&value + forParameter:NSOpenGLCPSwapInterval]; +} + +void CocoaFrameBuffer::Flip() +{ + assert(NULL != screen); + + if (rbOpts.dirty) + { + glViewport(rbOpts.shiftX, rbOpts.shiftY, rbOpts.width, rbOpts.height); + + // TODO: Figure out why the following glClear() call is needed + // to avoid drawing of garbage in fullscreen mode when + // in-game's aspect ratio is different from display one + glClear(GL_COLOR_BUFFER_BIT); + + rbOpts.dirty = false; + } + +#ifdef __LITTLE_ENDIAN__ + static const GLenum format = GL_RGBA; +#else // __BIG_ENDIAN__ + static const GLenum format = GL_ABGR_EXT; +#endif // __LITTLE_ENDIAN__ + + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, + Width, Height, 0, format, GL_UNSIGNED_BYTE, m_pixelBuffer); + + glBegin(GL_QUADS); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glTexCoord2f(0.0f, 0.0f); + glVertex2f(0.0f, 0.0f); + glTexCoord2f(Width, 0.0f); + glVertex2f(Width, 0.0f); + glTexCoord2f(Width, Height); + glVertex2f(Width, Height); + glTexCoord2f(0.0f, Height); + glVertex2f(0.0f, Height); + glEnd(); + + glFlush(); + + [[NSOpenGLContext currentContext] flushBuffer]; +} + + +ADD_STAT(blit) +{ + FString result; + result.Format("blit=%04.1f ms flip=%04.1f ms", BlitCycles.TimeMS(), FlipCycles.TimeMS()); + return result; +} + + +IVideo* Video; + + +void I_ShutdownGraphics() +{ + if (NULL != screen) + { + screen->ObjectFlags |= OF_YesReallyDelete; + delete screen; + screen = NULL; + } + + delete Video; + Video = NULL; +} + +void I_InitGraphics() +{ + UCVarValue val; + + val.Bool = !!Args->CheckParm("-devparm"); + ticker.SetGenericRepDefault(val, CVAR_Bool); + + Video = new CocoaVideo(0); + atterm(I_ShutdownGraphics); +} + + +static void I_DeleteRenderer() +{ + delete Renderer; + Renderer = NULL; +} + +void I_CreateRenderer() +{ + if (NULL == Renderer) + { + Renderer = new FSoftwareRenderer; + atterm(I_DeleteRenderer); + } +} + + +DFrameBuffer* I_SetMode(int &width, int &height, DFrameBuffer* old) +{ + return Video->CreateFrameBuffer(width, height, fullscreen, old); +} + +bool I_CheckResolution(const int width, const int height, const int bits) +{ + int twidth, theight; + + Video->StartModeIterator(bits, fullscreen); + + while (Video->NextMode(&twidth, &theight, NULL)) + { + if (width == twidth && height == theight) + { + return true; + } + } + + return false; +} + +void I_ClosestResolution(int *width, int *height, int bits) +{ + int twidth, theight; + int cwidth = 0, cheight = 0; + int iteration; + DWORD closest = DWORD(-1); + + for (iteration = 0; iteration < 2; ++iteration) + { + Video->StartModeIterator(bits, fullscreen); + + while (Video->NextMode(&twidth, &theight, NULL)) + { + if (twidth == *width && theight == *height) + { + return; + } + + if (iteration == 0 && (twidth < *width || theight < *height)) + { + continue; + } + + const DWORD dist = (twidth - *width) * (twidth - *width) + + (theight - *height) * (theight - *height); + + if (dist < closest) + { + closest = dist; + cwidth = twidth; + cheight = theight; + } + } + + if (closest != DWORD(-1)) + { + *width = cwidth; + *height = cheight; + return; + } + } +} + + +EXTERN_CVAR(Int, vid_maxfps); +EXTERN_CVAR(Bool, cl_capfps); + +// So Apple doesn't support POSIX timers and I can't find a good substitute short of +// having Objective-C Cocoa events or something like that. +void I_SetFPSLimit(int limit) +{ +} + +CUSTOM_CVAR(Int, vid_maxfps, 200, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (vid_maxfps < TICRATE && vid_maxfps != 0) + { + vid_maxfps = TICRATE; + } + else if (vid_maxfps > 1000) + { + vid_maxfps = 1000; + } + else if (cl_capfps == 0) + { + I_SetFPSLimit(vid_maxfps); + } +} + +CUSTOM_CVAR(Bool, vid_hidpi, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (I_IsHiDPISupported()) + { + CocoaVideo::UseHiDPI(self); + } + else if (0 != self) + { + self = 0; + } +} + + +CCMD(vid_listmodes) +{ + if (Video == NULL) + { + return; + } + + static const char* const ratios[5] = { "", " - 16:9", " - 16:10", " - 17:10", " - 5:4" }; + int width, height; + bool letterbox; + + Video->StartModeIterator(32, screen->IsFullscreen()); + + while (Video->NextMode(&width, &height, &letterbox)) + { + const bool current = width == DisplayWidth && height == DisplayHeight; + const int ratio = CheckRatio(width, height); + + Printf(current ? PRINT_BOLD : PRINT_HIGH, "%s%4d x%5d x%3d%s%s\n", + current || !(ratio & 3) ? "" : TEXTCOLOR_GOLD, + width, height, 32, ratios[ratio], + current || !letterbox ? "" : TEXTCOLOR_BROWN " LB"); + } +} + +CCMD(vid_currentmode) +{ + Printf("%dx%dx%d\n", DisplayWidth, DisplayHeight, DisplayBits); +} + + +// --------------------------------------------------------------------------- + + +bool I_SetCursor(FTexture* cursorpic) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSCursor* cursor = nil; + + if (NULL != cursorpic && FTexture::TEX_Null != cursorpic->UseType) + { + // Create bitmap image representation + + const NSInteger imageWidth = cursorpic->GetWidth(); + const NSInteger imageHeight = cursorpic->GetHeight(); + const NSInteger imagePitch = imageWidth * 4; + + NSBitmapImageRep* bitmapImageRep = [NSBitmapImageRep alloc]; + [bitmapImageRep initWithBitmapDataPlanes:NULL + pixelsWide:imageWidth + pixelsHigh:imageHeight + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:imagePitch + bitsPerPixel:0]; + + // Load bitmap data to representation + + BYTE* buffer = [bitmapImageRep bitmapData]; + memset(buffer, 0, imagePitch * imageHeight); + + FBitmap bitmap(buffer, imagePitch, imageWidth, imageHeight); + cursorpic->CopyTrueColorPixels(&bitmap, 0, 0); + + // Swap red and blue components in each pixel + + for (size_t i = 0; i < size_t(imageWidth * imageHeight); ++i) + { + const size_t offset = i * 4; + + const BYTE temp = buffer[offset ]; + buffer[offset ] = buffer[offset + 2]; + buffer[offset + 2] = temp; + } + + // Create image from representation and set it as cursor + + NSData* imageData = [bitmapImageRep representationUsingType:NSPNGFileType + properties:nil]; + NSImage* cursorImage = [[NSImage alloc] initWithData:imageData]; + + cursor = [[NSCursor alloc] initWithImage:cursorImage + hotSpot:NSMakePoint(0.0f, 0.0f)]; + } + + CocoaVideo::SetCursor(cursor); + + [pool release]; + + return true; +} + + +NSSize I_GetContentViewSize(const NSWindow* const window) +{ + const NSView* const view = [window contentView]; + const NSSize frameSize = [view frame].size; + + // TODO: figure out why [NSView frame] returns different values in "fullscreen" and in window + // In "fullscreen" the result is multiplied by [NSScreen backingScaleFactor], but not in window + + return (vid_hidpi && !fullscreen) + ? [view convertSizeToBacking:frameSize] + : frameSize; +} + +void I_SetMainWindowVisible(bool visible) +{ + CocoaVideo::SetWindowVisible(visible); + I_SetNativeMouse(!visible); +} diff --git a/src/sdl/dikeys.h b/src/posix/dikeys.h similarity index 96% rename from src/sdl/dikeys.h rename to src/posix/dikeys.h index 8ce9e95bb..4541b0ffd 100644 --- a/src/sdl/dikeys.h +++ b/src/posix/dikeys.h @@ -1,155 +1,155 @@ -// ZDoom bases its keycodes on DirectInput's scan codes -// Why? Because it was Win32-only before porting to anything else, -// so this made sense. AFAIK, it's primarily used under Win32 now, -// so it still makes sense. -// -// Actually, these key codes may only be used for key bindings now, -// in which case they're not really necessary--if we tweaked c_bind.cpp. - -enum -{ - DIK_ESCAPE = 1, - DIK_1, - DIK_2, - DIK_3, - DIK_4, - DIK_5, - DIK_6, - DIK_7, - DIK_8, - DIK_9, - DIK_0, - DIK_MINUS, /* - on main keyboard */ - DIK_EQUALS, - DIK_BACK, /* backspace */ - DIK_TAB, - DIK_Q, - DIK_W, - DIK_E, - DIK_R, - DIK_T, - DIK_Y, - DIK_U, - DIK_I, - DIK_O, - DIK_P, - DIK_LBRACKET, - DIK_RBRACKET, - DIK_RETURN, /* Enter on main keyboard */ - DIK_LCONTROL, - DIK_A, - DIK_S, - DIK_D, - DIK_F, - DIK_G, - DIK_H, - DIK_J, - DIK_K, - DIK_L, - DIK_SEMICOLON, - DIK_APOSTROPHE, - DIK_GRAVE, /* accent grave */ - DIK_LSHIFT, - DIK_BACKSLASH, - DIK_Z, - DIK_X, - DIK_C, - DIK_V, - DIK_B, - DIK_N, - DIK_M, - DIK_COMMA, - DIK_PERIOD, /* . on main keyboard */ - DIK_SLASH, /* / on main keyboard */ - DIK_RSHIFT, - DIK_MULTIPLY, /* * on numeric keypad */ - DIK_LMENU, /* left Alt */ - DIK_SPACE, - DIK_CAPITAL, - DIK_F1, - DIK_F2, - DIK_F3, - DIK_F4, - DIK_F5, - DIK_F6, - DIK_F7, - DIK_F8, - DIK_F9, - DIK_F10, - DIK_NUMLOCK, - DIK_SCROLL, /* Scroll Lock */ - DIK_NUMPAD7, - DIK_NUMPAD8, - DIK_NUMPAD9, - DIK_SUBTRACT, /* - on numeric keypad */ - DIK_NUMPAD4, - DIK_NUMPAD5, - DIK_NUMPAD6, - DIK_ADD, /* + on numeric keypad */ - DIK_NUMPAD1, - DIK_NUMPAD2, - DIK_NUMPAD3, - DIK_NUMPAD0, - DIK_DECIMAL, /* . on numeric keypad */ - DIK_OEM_102 = 0x56, /* < > | on UK/Germany keyboards */ - DIK_F11, - DIK_F12, - DIK_F13 = 0x64, /* (NEC PC98) */ - DIK_F14, /* (NEC PC98) */ - DIK_F15, /* (NEC PC98) */ - DIK_KANA = 0x70, /* (Japanese keyboard) */ - DIK_ABNT_C1 = 0x73, /* / ? on Portugese (Brazilian) keyboards */ - DIK_CONVERT = 0x79, /* (Japanese keyboard) */ - DIK_NOCONVERT = 0x7B, /* (Japanese keyboard) */ - DIK_YEN = 0x7D, /* (Japanese keyboard) */ - DIK_ABNT_C2 = 0x7E, /* Numpad . on Portugese (Brazilian) keyboards */ - DIK_NUMPAD_EQUALS = 0x8D, /* = on numeric keypad (NEC PC98) */ - DIK_PREVTRACK = 0x90, /* Previous Track (DIK_CIRCUMFLEX on Japanese keyboard) */ - DIK_AT, /* (NEC PC98) */ - DIK_COLON, /* (NEC PC98) */ - DIK_UNDERLINE, /* (NEC PC98) */ - DIK_KANJI, /* (Japanese keyboard) */ - DIK_STOP, /* (NEC PC98) */ - DIK_AX, /* (Japan AX) */ - DIK_UNLABELED, /* (J3100) */ - DIK_NEXTTRACK = 0x99, /* Next Track */ - DIK_NUMPADENTER = 0x9C, /* Enter on numeric keypad */ - DIK_RCONTROL = 0x9D, - DIK_MUTE = 0xA0, /* Mute */ - DIK_CALCULATOR = 0xA1, /* Calculator */ - DIK_PLAYPAUSE = 0xA2, /* Play / Pause */ - DIK_MEDIASTOP = 0xA4, /* Media Stop */ - DIK_VOLUMEDOWN = 0xAE, /* Volume - */ - DIK_VOLUMEUP = 0xB0, /* Volume + */ - DIK_WEBHOME = 0xB2, /* Web home */ - DIK_NUMPADCOMMA = 0xB3, /* , on numeric keypad (NEC PC98) */ - DIK_DIVIDE = 0xB5, /* / on numeric keypad */ - DIK_SYSRQ = 0xB7, - DIK_RMENU = 0xB8, /* right Alt */ - DIK_PAUSE = 0xC5, /* Pause */ - DIK_HOME = 0xC7, /* Home on arrow keypad */ - DIK_UP = 0xC8, /* UpArrow on arrow keypad */ - DIK_PRIOR = 0xC9, /* PgUp on arrow keypad */ - DIK_LEFT = 0xCB, /* LeftArrow on arrow keypad */ - DIK_RIGHT = 0xCD, /* RightArrow on arrow keypad */ - DIK_END = 0xCF, /* End on arrow keypad */ - DIK_DOWN = 0xD0, /* DownArrow on arrow keypad */ - DIK_NEXT = 0xD1, /* PgDn on arrow keypad */ - DIK_INSERT = 0xD2, /* Insert on arrow keypad */ - DIK_DELETE = 0xD3, /* Delete on arrow keypad */ - DIK_LWIN = 0xDB, /* Left Windows key */ - DIK_RWIN = 0xDC, /* Right Windows key */ - DIK_APPS = 0xDD, /* AppMenu key */ - DIK_POWER = 0xDE, /* System Power */ - DIK_SLEEP = 0xDF, /* System Sleep */ - DIK_WAKE = 0xE3, /* System Wake */ - DIK_WEBSEARCH = 0xE5, /* Web Search */ - DIK_WEBFAVORITES = 0xE6, /* Web Favorites */ - DIK_WEBREFRESH = 0xE7, /* Web Refresh */ - DIK_WEBSTOP = 0xE8, /* Web Stop */ - DIK_WEBFORWARD = 0xE9, /* Web Forward */ - DIK_WEBBACK = 0xEA, /* Web Back */ - DIK_MYCOMPUTER = 0xEB, /* My Computer */ - DIK_MAIL = 0xEC, /* Mail */ - DIK_MEDIASELECT = 0xED /* Media Select */ -}; +// ZDoom bases its keycodes on DirectInput's scan codes +// Why? Because it was Win32-only before porting to anything else, +// so this made sense. AFAIK, it's primarily used under Win32 now, +// so it still makes sense. +// +// Actually, these key codes may only be used for key bindings now, +// in which case they're not really necessary--if we tweaked c_bind.cpp. + +enum +{ + DIK_ESCAPE = 1, + DIK_1, + DIK_2, + DIK_3, + DIK_4, + DIK_5, + DIK_6, + DIK_7, + DIK_8, + DIK_9, + DIK_0, + DIK_MINUS, /* - on main keyboard */ + DIK_EQUALS, + DIK_BACK, /* backspace */ + DIK_TAB, + DIK_Q, + DIK_W, + DIK_E, + DIK_R, + DIK_T, + DIK_Y, + DIK_U, + DIK_I, + DIK_O, + DIK_P, + DIK_LBRACKET, + DIK_RBRACKET, + DIK_RETURN, /* Enter on main keyboard */ + DIK_LCONTROL, + DIK_A, + DIK_S, + DIK_D, + DIK_F, + DIK_G, + DIK_H, + DIK_J, + DIK_K, + DIK_L, + DIK_SEMICOLON, + DIK_APOSTROPHE, + DIK_GRAVE, /* accent grave */ + DIK_LSHIFT, + DIK_BACKSLASH, + DIK_Z, + DIK_X, + DIK_C, + DIK_V, + DIK_B, + DIK_N, + DIK_M, + DIK_COMMA, + DIK_PERIOD, /* . on main keyboard */ + DIK_SLASH, /* / on main keyboard */ + DIK_RSHIFT, + DIK_MULTIPLY, /* * on numeric keypad */ + DIK_LMENU, /* left Alt */ + DIK_SPACE, + DIK_CAPITAL, + DIK_F1, + DIK_F2, + DIK_F3, + DIK_F4, + DIK_F5, + DIK_F6, + DIK_F7, + DIK_F8, + DIK_F9, + DIK_F10, + DIK_NUMLOCK, + DIK_SCROLL, /* Scroll Lock */ + DIK_NUMPAD7, + DIK_NUMPAD8, + DIK_NUMPAD9, + DIK_SUBTRACT, /* - on numeric keypad */ + DIK_NUMPAD4, + DIK_NUMPAD5, + DIK_NUMPAD6, + DIK_ADD, /* + on numeric keypad */ + DIK_NUMPAD1, + DIK_NUMPAD2, + DIK_NUMPAD3, + DIK_NUMPAD0, + DIK_DECIMAL, /* . on numeric keypad */ + DIK_OEM_102 = 0x56, /* < > | on UK/Germany keyboards */ + DIK_F11, + DIK_F12, + DIK_F13 = 0x64, /* (NEC PC98) */ + DIK_F14, /* (NEC PC98) */ + DIK_F15, /* (NEC PC98) */ + DIK_KANA = 0x70, /* (Japanese keyboard) */ + DIK_ABNT_C1 = 0x73, /* / ? on Portugese (Brazilian) keyboards */ + DIK_CONVERT = 0x79, /* (Japanese keyboard) */ + DIK_NOCONVERT = 0x7B, /* (Japanese keyboard) */ + DIK_YEN = 0x7D, /* (Japanese keyboard) */ + DIK_ABNT_C2 = 0x7E, /* Numpad . on Portugese (Brazilian) keyboards */ + DIK_NUMPAD_EQUALS = 0x8D, /* = on numeric keypad (NEC PC98) */ + DIK_PREVTRACK = 0x90, /* Previous Track (DIK_CIRCUMFLEX on Japanese keyboard) */ + DIK_AT, /* (NEC PC98) */ + DIK_COLON, /* (NEC PC98) */ + DIK_UNDERLINE, /* (NEC PC98) */ + DIK_KANJI, /* (Japanese keyboard) */ + DIK_STOP, /* (NEC PC98) */ + DIK_AX, /* (Japan AX) */ + DIK_UNLABELED, /* (J3100) */ + DIK_NEXTTRACK = 0x99, /* Next Track */ + DIK_NUMPADENTER = 0x9C, /* Enter on numeric keypad */ + DIK_RCONTROL = 0x9D, + DIK_MUTE = 0xA0, /* Mute */ + DIK_CALCULATOR = 0xA1, /* Calculator */ + DIK_PLAYPAUSE = 0xA2, /* Play / Pause */ + DIK_MEDIASTOP = 0xA4, /* Media Stop */ + DIK_VOLUMEDOWN = 0xAE, /* Volume - */ + DIK_VOLUMEUP = 0xB0, /* Volume + */ + DIK_WEBHOME = 0xB2, /* Web home */ + DIK_NUMPADCOMMA = 0xB3, /* , on numeric keypad (NEC PC98) */ + DIK_DIVIDE = 0xB5, /* / on numeric keypad */ + DIK_SYSRQ = 0xB7, + DIK_RMENU = 0xB8, /* right Alt */ + DIK_PAUSE = 0xC5, /* Pause */ + DIK_HOME = 0xC7, /* Home on arrow keypad */ + DIK_UP = 0xC8, /* UpArrow on arrow keypad */ + DIK_PRIOR = 0xC9, /* PgUp on arrow keypad */ + DIK_LEFT = 0xCB, /* LeftArrow on arrow keypad */ + DIK_RIGHT = 0xCD, /* RightArrow on arrow keypad */ + DIK_END = 0xCF, /* End on arrow keypad */ + DIK_DOWN = 0xD0, /* DownArrow on arrow keypad */ + DIK_NEXT = 0xD1, /* PgDn on arrow keypad */ + DIK_INSERT = 0xD2, /* Insert on arrow keypad */ + DIK_DELETE = 0xD3, /* Delete on arrow keypad */ + DIK_LWIN = 0xDB, /* Left Windows key */ + DIK_RWIN = 0xDC, /* Right Windows key */ + DIK_APPS = 0xDD, /* AppMenu key */ + DIK_POWER = 0xDE, /* System Power */ + DIK_SLEEP = 0xDF, /* System Sleep */ + DIK_WAKE = 0xE3, /* System Wake */ + DIK_WEBSEARCH = 0xE5, /* Web Search */ + DIK_WEBFAVORITES = 0xE6, /* Web Favorites */ + DIK_WEBREFRESH = 0xE7, /* Web Refresh */ + DIK_WEBSTOP = 0xE8, /* Web Stop */ + DIK_WEBFORWARD = 0xE9, /* Web Forward */ + DIK_WEBBACK = 0xEA, /* Web Back */ + DIK_MYCOMPUTER = 0xEB, /* My Computer */ + DIK_MAIL = 0xEC, /* Mail */ + DIK_MEDIASELECT = 0xED /* Media Select */ +}; diff --git a/src/sdl/hardware.h b/src/posix/hardware.h similarity index 97% rename from src/sdl/hardware.h rename to src/posix/hardware.h index 6544f1498..618941fe5 100644 --- a/src/sdl/hardware.h +++ b/src/posix/hardware.h @@ -1,96 +1,96 @@ -/* -** hardware.h -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** 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 __HARDWARE_H__ -#define __HARDWARE_H__ - -#include "i_video.h" -#include "v_video.h" - -// Semaphores -#ifdef __APPLE__ -#include -#include -#include -typedef semaphore_t Semaphore; -#define SEMAPHORE_WAIT(sem) \ - while(semaphore_wait(sem) != KERN_SUCCESS){} -#define SEMAPHORE_SIGNAL(sem) \ - semaphore_signal(sem); -#define SEMAPHORE_INIT(sem, shared, value) \ - semaphore_create(mach_task_self(), &sem, shared, value); -#else -#include -typedef sem_t Semaphore; -#define SEMAPHORE_WAIT(sem) \ - do { \ - while(sem_wait(&sem) != 0); \ - int semValue; \ - sem_getvalue(&sem, &semValue); \ - if(semValue < 1) \ - break; \ - } while(true); -#define SEMAPHORE_SIGNAL(sem) \ - sem_post(&sem); -#define SEMAPHORE_INIT(sem, shared, value) \ - sem_init(&sem, shared, value); -#endif - -class IVideo -{ - public: - virtual ~IVideo () {} - - virtual EDisplayType GetDisplayType () = 0; - virtual void SetWindowedScale (float scale) = 0; - - virtual DFrameBuffer *CreateFrameBuffer (int width, int height, bool fs, DFrameBuffer *old) = 0; - - virtual void StartModeIterator (int bits, bool fs) = 0; - virtual bool NextMode (int *width, int *height, bool *letterbox) = 0; - - virtual bool SetResolution (int width, int height, int bits); - - virtual void DumpAdapters(); -}; - -void I_InitGraphics (); -void I_ShutdownGraphics (); -void I_CreateRenderer(); - -extern Semaphore FPSLimitSemaphore; -void I_SetFPSLimit(int limit); - -extern IVideo *Video; - -#endif // __HARDWARE_H__ +/* +** hardware.h +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** 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 __HARDWARE_H__ +#define __HARDWARE_H__ + +#include "i_video.h" +#include "v_video.h" + +// Semaphores +#ifdef __APPLE__ +#include +#include +#include +typedef semaphore_t Semaphore; +#define SEMAPHORE_WAIT(sem) \ + while(semaphore_wait(sem) != KERN_SUCCESS){} +#define SEMAPHORE_SIGNAL(sem) \ + semaphore_signal(sem); +#define SEMAPHORE_INIT(sem, shared, value) \ + semaphore_create(mach_task_self(), &sem, shared, value); +#else +#include +typedef sem_t Semaphore; +#define SEMAPHORE_WAIT(sem) \ + do { \ + while(sem_wait(&sem) != 0); \ + int semValue; \ + sem_getvalue(&sem, &semValue); \ + if(semValue < 1) \ + break; \ + } while(true); +#define SEMAPHORE_SIGNAL(sem) \ + sem_post(&sem); +#define SEMAPHORE_INIT(sem, shared, value) \ + sem_init(&sem, shared, value); +#endif + +class IVideo +{ + public: + virtual ~IVideo () {} + + virtual EDisplayType GetDisplayType () = 0; + virtual void SetWindowedScale (float scale) = 0; + + virtual DFrameBuffer *CreateFrameBuffer (int width, int height, bool fs, DFrameBuffer *old) = 0; + + virtual void StartModeIterator (int bits, bool fs) = 0; + virtual bool NextMode (int *width, int *height, bool *letterbox) = 0; + + virtual bool SetResolution (int width, int height, int bits); + + virtual void DumpAdapters(); +}; + +void I_InitGraphics (); +void I_ShutdownGraphics (); +void I_CreateRenderer(); + +extern Semaphore FPSLimitSemaphore; +void I_SetFPSLimit(int limit); + +extern IVideo *Video; + +#endif // __HARDWARE_H__ diff --git a/src/sdl/i_cd.cpp b/src/posix/i_cd.cpp similarity index 95% rename from src/sdl/i_cd.cpp rename to src/posix/i_cd.cpp index 83f1e8c89..96b59934c 100644 --- a/src/sdl/i_cd.cpp +++ b/src/posix/i_cd.cpp @@ -1,154 +1,154 @@ -#include "i_cd.h" - -//========================================================================== -// -// CD_Init -// -//========================================================================== - -bool CD_Init () -{ - return false; -} - -bool CD_Init (int device) -{ - return false; -} - -//========================================================================== -// -// CD_InitID -// -//========================================================================== - -bool CD_InitID (unsigned int id, int guess) -{ - return false; -} - -//========================================================================== -// -// CD_Close -// -//========================================================================== - -void CD_Close () -{ -} - -//========================================================================== -// -// CD_Eject -// -//========================================================================== - -void CD_Eject () -{ -} - -//========================================================================== -// -// CD_UnEject -// -//========================================================================== - -bool CD_UnEject () -{ - return false; -} - -//========================================================================== -// -// CD_Stop -// -//========================================================================== - -void CD_Stop () -{ -} - -//========================================================================== -// -// CD_Play -// -//========================================================================== - -bool CD_Play (int track, bool looping) -{ - return false; -} - -//========================================================================== -// -// CD_PlayNoWait -// -//========================================================================== - -void CD_PlayNoWait (int track, bool looping) -{ -} - -//========================================================================== -// -// CD_PlayCD -// -//========================================================================== - -bool CD_PlayCD (bool looping) -{ - return false; -} - -//========================================================================== -// -// CD_PlayCDNoWait -// -//========================================================================== - -void CD_PlayCDNoWait (bool looping) -{ -} - -//========================================================================== -// -// CD_Pause -// -//========================================================================== - -void CD_Pause () -{ -} - -//========================================================================== -// -// CD_Resume -// -//========================================================================== - -bool CD_Resume () -{ - return false; -} - -//========================================================================== -// -// CD_GetMode -// -//========================================================================== - -ECDModes CD_GetMode () -{ - return CDMode_Unknown; -} - -//========================================================================== -// -// CD_CheckTrack -// -//========================================================================== - -bool CD_CheckTrack (int track) -{ - return false; -} +#include "i_cd.h" + +//========================================================================== +// +// CD_Init +// +//========================================================================== + +bool CD_Init () +{ + return false; +} + +bool CD_Init (int device) +{ + return false; +} + +//========================================================================== +// +// CD_InitID +// +//========================================================================== + +bool CD_InitID (unsigned int id, int guess) +{ + return false; +} + +//========================================================================== +// +// CD_Close +// +//========================================================================== + +void CD_Close () +{ +} + +//========================================================================== +// +// CD_Eject +// +//========================================================================== + +void CD_Eject () +{ +} + +//========================================================================== +// +// CD_UnEject +// +//========================================================================== + +bool CD_UnEject () +{ + return false; +} + +//========================================================================== +// +// CD_Stop +// +//========================================================================== + +void CD_Stop () +{ +} + +//========================================================================== +// +// CD_Play +// +//========================================================================== + +bool CD_Play (int track, bool looping) +{ + return false; +} + +//========================================================================== +// +// CD_PlayNoWait +// +//========================================================================== + +void CD_PlayNoWait (int track, bool looping) +{ +} + +//========================================================================== +// +// CD_PlayCD +// +//========================================================================== + +bool CD_PlayCD (bool looping) +{ + return false; +} + +//========================================================================== +// +// CD_PlayCDNoWait +// +//========================================================================== + +void CD_PlayCDNoWait (bool looping) +{ +} + +//========================================================================== +// +// CD_Pause +// +//========================================================================== + +void CD_Pause () +{ +} + +//========================================================================== +// +// CD_Resume +// +//========================================================================== + +bool CD_Resume () +{ + return false; +} + +//========================================================================== +// +// CD_GetMode +// +//========================================================================== + +ECDModes CD_GetMode () +{ + return CDMode_Unknown; +} + +//========================================================================== +// +// CD_CheckTrack +// +//========================================================================== + +bool CD_CheckTrack (int track) +{ + return false; +} diff --git a/src/sdl/i_input.h b/src/posix/i_input.h similarity index 95% rename from src/sdl/i_input.h rename to src/posix/i_input.h index 124c2ca85..07ee1115d 100644 --- a/src/sdl/i_input.h +++ b/src/posix/i_input.h @@ -1,10 +1,10 @@ -#ifndef __I_INPUT_H__ -#define __I_INPUT_H__ - -void I_PutInClipboard (const char *str); -FString I_GetFromClipboard (bool use_primary_selection); -void I_SetMouseCapture(); -void I_ReleaseMouseCapture(); - -#endif - +#ifndef __I_INPUT_H__ +#define __I_INPUT_H__ + +void I_PutInClipboard (const char *str); +FString I_GetFromClipboard (bool use_primary_selection); +void I_SetMouseCapture(); +void I_ReleaseMouseCapture(); + +#endif + diff --git a/src/sdl/i_movie.cpp b/src/posix/i_movie.cpp similarity index 92% rename from src/sdl/i_movie.cpp rename to src/posix/i_movie.cpp index 020541516..8aea4b500 100644 --- a/src/sdl/i_movie.cpp +++ b/src/posix/i_movie.cpp @@ -1,7 +1,7 @@ -#include "i_movie.h" - -int I_PlayMovie (const char *movie) -{ - return MOVIE_Failed; -} - +#include "i_movie.h" + +int I_PlayMovie (const char *movie) +{ + return MOVIE_Failed; +} + diff --git a/src/sdl/i_steam.cpp b/src/posix/i_steam.cpp similarity index 91% rename from src/sdl/i_steam.cpp rename to src/posix/i_steam.cpp index 23e74af5a..9819bc09e 100644 --- a/src/sdl/i_steam.cpp +++ b/src/posix/i_steam.cpp @@ -34,6 +34,10 @@ #include +#ifdef __APPLE__ +#include +#endif // __APPLE__ + #include "doomerrors.h" #include "d_main.h" #include "zstring.h" @@ -167,9 +171,20 @@ TArray I_GetSteamPath() // we need to figure out on an app-by-app basis where the game is installed. // To do so, we read the virtual registry. #ifdef __APPLE__ - FString OSX_FindApplicationSupport(); + FString appSupportPath; - FString regPath = OSX_FindApplicationSupport() + "/Steam/config/config.vdf"; + { + char cpath[PATH_MAX]; + FSRef folder; + + if (noErr == FSFindFolder(kUserDomain, kApplicationSupportFolderType, kCreateFolder, &folder) && + noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX)) + { + appSupportPath = cpath; + } + } + + FString regPath = appSupportPath + "/Steam/config/config.vdf"; try { SteamInstallFolders = ParseSteamRegistry(regPath); @@ -180,7 +195,7 @@ TArray I_GetSteamPath() return result; } - SteamInstallFolders.Push(OSX_FindApplicationSupport() + "/Steam/SteamApps/common"); + SteamInstallFolders.Push(appSupportPath + "/Steam/SteamApps/common"); #else char* home = getenv("HOME"); if(home != NULL && *home != '\0') diff --git a/src/sdl/i_system.cpp b/src/posix/i_system.cpp similarity index 99% rename from src/sdl/i_system.cpp rename to src/posix/i_system.cpp index 41fdef323..c2ce4aa9f 100644 --- a/src/sdl/i_system.cpp +++ b/src/posix/i_system.cpp @@ -41,7 +41,6 @@ #include "doomerrors.h" #include -#include "SDL.h" #include "doomtype.h" #include "doomstat.h" #include "version.h" diff --git a/src/sdl/i_system.h b/src/posix/i_system.h similarity index 96% rename from src/sdl/i_system.h rename to src/posix/i_system.h index fa03d3c37..abda490c4 100644 --- a/src/sdl/i_system.h +++ b/src/posix/i_system.h @@ -1,170 +1,170 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// $Id:$ -// -// Copyright (C) 1993-1996 by id Software, Inc. -// -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// DESCRIPTION: -// System specific interface stuff. -// -//----------------------------------------------------------------------------- - - -#ifndef __I_SYSTEM__ -#define __I_SYSTEM__ - -#include -#include - -#include "doomtype.h" - -struct ticcmd_t; -struct WadStuff; - -#ifndef SHARE_DIR -#define SHARE_DIR "/usr/local/share/" -#endif - -// Index values into the LanguageIDs array -enum -{ - LANGIDX_UserPreferred, - LANGIDX_UserDefault, - LANGIDX_SysPreferred, - LANGIDX_SysDefault -}; -extern DWORD LanguageIDs[4]; -extern void SetLanguageIDs (); - -// Called by DoomMain. -void I_Init (void); - -// Called by D_DoomLoop, -// returns current time in tics. -extern int (*I_GetTime) (bool saveMS); - -// like I_GetTime, except it waits for a new tic before returning -extern int (*I_WaitForTic) (int); - -// Freezes tic counting temporarily. While frozen, calls to I_GetTime() -// will always return the same value. This does not affect I_MSTime(). -// You must also not call I_WaitForTic() while freezing time, since the -// tic will never arrive (unless it's the current one). -extern void (*I_FreezeTime) (bool frozen); - -fixed_t I_GetTimeFrac (uint32 *ms); - -// Return a seed value for the RNG. -unsigned int I_MakeRNGSeed(); - - -// -// Called by D_DoomLoop, -// called before processing any tics in a frame -// (just after displaying a frame). -// Time consuming syncronous operations -// are performed here (joystick reading). -// Can call D_PostEvent. -// -void I_StartFrame (void); - - -// -// Called by D_DoomLoop, -// called before processing each tic in a frame. -// Quick syncronous operations are performed here. -// Can call D_PostEvent. -void I_StartTic (void); - -// Asynchronous interrupt functions should maintain private queues -// that are read by the synchronous functions -// to be converted into events. - -// Either returns a null ticcmd, -// or calls a loadable driver to build it. -// This ticcmd will then be modified by the gameloop -// for normal input. -ticcmd_t *I_BaseTiccmd (void); - - -// Called by M_Responder when quit is selected. -// Clean exit, displays sell blurb. -void I_Quit (void); - - -void I_Tactile (int on, int off, int total); - -void STACK_ARGS I_Error (const char *error, ...) GCCPRINTF(1,2); -void STACK_ARGS I_FatalError (const char *error, ...) GCCPRINTF(1,2); - -void addterm (void (*func)(void), const char *name); -#define atterm(t) addterm (t, #t) -void popterm (); - -// Print a console string -void I_PrintStr (const char *str); - -// Set the title string of the startup window -void I_SetIWADInfo (); - -// Pick from multiple IWADs to use -int I_PickIWad (WadStuff *wads, int numwads, bool queryiwad, int defaultiwad); - -// [RH] Checks the registry for Steam's install path, so we can scan its -// directories for IWADs if the user purchased any through Steam. -TArray I_GetSteamPath(); - -// The ini could not be saved at exit -bool I_WriteIniFailed (); - -// [RH] Returns millisecond-accurate time -unsigned int I_MSTime (void); -unsigned int I_FPSTime(); - -class FTexture; -bool I_SetCursor(FTexture *); - -// Directory searching routines - -struct findstate_t -{ - int count; - struct dirent **namelist; - int current; -}; - -void *I_FindFirst (const char *filespec, findstate_t *fileinfo); -int I_FindNext (void *handle, findstate_t *fileinfo); -int I_FindClose (void *handle); -int I_FindAttr (findstate_t *fileinfo); - -#define I_FindName(a) ((a)->namelist[(a)->current]->d_name) - -#define FA_RDONLY 1 -#define FA_HIDDEN 2 -#define FA_SYSTEM 4 -#define FA_DIREC 8 -#define FA_ARCH 16 - -static inline char *strlwr(char *str) -{ - char *ptr = str; - while(*ptr) - { - *ptr = tolower(*ptr); - ++ptr; - } - return str; -} - -#endif +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// $Id:$ +// +// Copyright (C) 1993-1996 by id Software, Inc. +// +// This source is available for distribution and/or modification +// only under the terms of the DOOM Source Code License as +// published by id Software. All rights reserved. +// +// The source is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License +// for more details. +// +// DESCRIPTION: +// System specific interface stuff. +// +//----------------------------------------------------------------------------- + + +#ifndef __I_SYSTEM__ +#define __I_SYSTEM__ + +#include +#include + +#include "doomtype.h" + +struct ticcmd_t; +struct WadStuff; + +#ifndef SHARE_DIR +#define SHARE_DIR "/usr/local/share/" +#endif + +// Index values into the LanguageIDs array +enum +{ + LANGIDX_UserPreferred, + LANGIDX_UserDefault, + LANGIDX_SysPreferred, + LANGIDX_SysDefault +}; +extern DWORD LanguageIDs[4]; +extern void SetLanguageIDs (); + +// Called by DoomMain. +void I_Init (void); + +// Called by D_DoomLoop, +// returns current time in tics. +extern int (*I_GetTime) (bool saveMS); + +// like I_GetTime, except it waits for a new tic before returning +extern int (*I_WaitForTic) (int); + +// Freezes tic counting temporarily. While frozen, calls to I_GetTime() +// will always return the same value. This does not affect I_MSTime(). +// You must also not call I_WaitForTic() while freezing time, since the +// tic will never arrive (unless it's the current one). +extern void (*I_FreezeTime) (bool frozen); + +fixed_t I_GetTimeFrac (uint32 *ms); + +// Return a seed value for the RNG. +unsigned int I_MakeRNGSeed(); + + +// +// Called by D_DoomLoop, +// called before processing any tics in a frame +// (just after displaying a frame). +// Time consuming syncronous operations +// are performed here (joystick reading). +// Can call D_PostEvent. +// +void I_StartFrame (void); + + +// +// Called by D_DoomLoop, +// called before processing each tic in a frame. +// Quick syncronous operations are performed here. +// Can call D_PostEvent. +void I_StartTic (void); + +// Asynchronous interrupt functions should maintain private queues +// that are read by the synchronous functions +// to be converted into events. + +// Either returns a null ticcmd, +// or calls a loadable driver to build it. +// This ticcmd will then be modified by the gameloop +// for normal input. +ticcmd_t *I_BaseTiccmd (void); + + +// Called by M_Responder when quit is selected. +// Clean exit, displays sell blurb. +void I_Quit (void); + + +void I_Tactile (int on, int off, int total); + +void STACK_ARGS I_Error (const char *error, ...) GCCPRINTF(1,2); +void STACK_ARGS I_FatalError (const char *error, ...) GCCPRINTF(1,2); + +void addterm (void (*func)(void), const char *name); +#define atterm(t) addterm (t, #t) +void popterm (); + +// Print a console string +void I_PrintStr (const char *str); + +// Set the title string of the startup window +void I_SetIWADInfo (); + +// Pick from multiple IWADs to use +int I_PickIWad (WadStuff *wads, int numwads, bool queryiwad, int defaultiwad); + +// [RH] Checks the registry for Steam's install path, so we can scan its +// directories for IWADs if the user purchased any through Steam. +TArray I_GetSteamPath(); + +// The ini could not be saved at exit +bool I_WriteIniFailed (); + +// [RH] Returns millisecond-accurate time +unsigned int I_MSTime (void); +unsigned int I_FPSTime(); + +class FTexture; +bool I_SetCursor(FTexture *); + +// Directory searching routines + +struct findstate_t +{ + int count; + struct dirent **namelist; + int current; +}; + +void *I_FindFirst (const char *filespec, findstate_t *fileinfo); +int I_FindNext (void *handle, findstate_t *fileinfo); +int I_FindClose (void *handle); +int I_FindAttr (findstate_t *fileinfo); + +#define I_FindName(a) ((a)->namelist[(a)->current]->d_name) + +#define FA_RDONLY 1 +#define FA_HIDDEN 2 +#define FA_SYSTEM 4 +#define FA_DIREC 8 +#define FA_ARCH 16 + +static inline char *strlwr(char *str) +{ + char *ptr = str; + while(*ptr) + { + *ptr = tolower(*ptr); + ++ptr; + } + return str; +} + +#endif diff --git a/src/sdl/iwadpicker_cocoa.mm b/src/posix/osx/iwadpicker_cocoa.mm similarity index 95% rename from src/sdl/iwadpicker_cocoa.mm rename to src/posix/osx/iwadpicker_cocoa.mm index d1364fa81..d2bc1ff0c 100644 --- a/src/sdl/iwadpicker_cocoa.mm +++ b/src/posix/osx/iwadpicker_cocoa.mm @@ -139,7 +139,7 @@ static NSDictionary* GetKnownFileTypes() @"-bex" , @"bex", @"-exec" , @"cfg", @"-playdemo", @"lmp", - nil]; + nil]; } static NSArray* GetKnownExtensions() @@ -156,7 +156,7 @@ static NSArray* GetKnownExtensions() { NSString* extension = [[filePath pathExtension] lowercaseString]; NSString* parameter = [GetKnownFileTypes() objectForKey:extension]; - + if (nil == parameter) { return; @@ -211,7 +211,7 @@ static NSArray* GetKnownExtensions() { NSArray* files = [openPanel URLs]; NSMutableString* parameters = [NSMutableString string]; - + for (NSUInteger i = 0, ei = [files count]; i < ei; ++i) { NSString* filePath = [[files objectAtIndex:i] path]; @@ -236,9 +236,9 @@ static NSArray* GetKnownExtensions() { newParameters = [newParameters stringByAppendingString:@" "]; } - + newParameters = [newParameters stringByAppendingString:parameters]; - + [parametersTextField setStringValue: newParameters]; } } @@ -337,7 +337,7 @@ static NSArray* GetKnownExtensions() [cancelButton setTarget:self]; [cancelButton setKeyEquivalent:@"\033"]; [[window contentView] addSubview:cancelButton]; - + browseButton = [[NSButton alloc] initWithFrame:NSMakeRect(14, 8, 96, 32)]; [browseButton setTitle:@"Browse..."]; [browseButton setBezelStyle:NSRoundedBezelStyle]; @@ -398,31 +398,38 @@ static NSString* GetArchitectureString() static void RestartWithParameters(const char* iwadPath, NSString* parameters) { assert(nil != parameters); - + defaultiwad = ExtractFileBase(iwadPath); - + GameConfig->DoGameSetup("Doom"); M_SaveDefaults(NULL); - + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; @try { - const int commandLineParametersCount = Args->NumArgs(); - assert(commandLineParametersCount > 0); - NSString* executablePath = [NSString stringWithUTF8String:Args->GetArg(0)]; - NSString* architecture = GetArchitectureString(); - - NSMutableArray* arguments = [NSMutableArray arrayWithCapacity:commandLineParametersCount + 6]; - [arguments addObject:@"-arch"]; - [arguments addObject:architecture]; - [arguments addObject:executablePath]; + + NSMutableArray* const arguments = [[NSMutableArray alloc] init]; + + // The following value shoud be equal to NSAppKitVersionNumber10_5 + // It's hard-coded in order to build with earlier SDKs + const bool canSelectArchitecture = NSAppKitVersionNumber >= 949; + + if (canSelectArchitecture) + { + [arguments addObject:@"-arch"]; + [arguments addObject:GetArchitectureString()]; + [arguments addObject:executablePath]; + + executablePath = @"/usr/bin/arch"; + } + [arguments addObject:@"-wad_picker_restart"]; [arguments addObject:@"-iwad"]; [arguments addObject:[NSString stringWithUTF8String:iwadPath]]; - for (int i = 1; i < commandLineParametersCount; ++i) + for (int i = 1, count = Args->NumArgs(); i < count; ++i) { NSString* currentParameter = [NSString stringWithUTF8String:Args->GetArg(i)]; [arguments addObject:currentParameter]; @@ -442,7 +449,8 @@ static void RestartWithParameters(const char* iwadPath, NSString* parameters) wordfree(&expansion); } - [NSTask launchedTaskWithLaunchPath:@"/usr/bin/arch" arguments:arguments]; + [NSTask launchedTaskWithLaunchPath:executablePath + arguments:arguments]; _exit(0); // to avoid atexit()'s functions } @@ -450,7 +458,7 @@ static void RestartWithParameters(const char* iwadPath, NSString* parameters) { NSLog(@"Cannot restart: %@", [e reason]); } - + [pool release]; } diff --git a/src/cocoa/zdoom-info.plist b/src/posix/osx/zdoom-info.plist similarity index 100% rename from src/cocoa/zdoom-info.plist rename to src/posix/osx/zdoom-info.plist diff --git a/src/cocoa/zdoom.icns b/src/posix/osx/zdoom.icns similarity index 100% rename from src/cocoa/zdoom.icns rename to src/posix/osx/zdoom.icns diff --git a/src/posix/readme.md b/src/posix/readme.md new file mode 100644 index 000000000..ce66dab2c --- /dev/null +++ b/src/posix/readme.md @@ -0,0 +1,6 @@ +This directory contains files required to support POSIX-compatible OSes, like GNU/Linux, OS X or BSD. + +Common files are placed in this directory directly. +SDL backend files are in `sdl` subdirectory. +Native OS X backend files are in `cocoa` subdirectory. +Shared files for both OS X backends are in `osx` subdirectory. diff --git a/src/sdl/crashcatcher.c b/src/posix/sdl/crashcatcher.c similarity index 95% rename from src/sdl/crashcatcher.c rename to src/posix/sdl/crashcatcher.c index a4f68d9a3..4754a369a 100644 --- a/src/sdl/crashcatcher.c +++ b/src/posix/sdl/crashcatcher.c @@ -1,429 +1,429 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __linux__ -#include -#ifndef PR_SET_PTRACER -#define PR_SET_PTRACER 0x59616d61 -#endif -#elif defined (__APPLE__) -#include -#endif - - -static const char crash_switch[] = "--cc-handle-crash"; - -static const char fatal_err[] = "\n\n*** Fatal Error ***\n"; -static const char pipe_err[] = "!!! Failed to create pipe\n"; -static const char fork_err[] = "!!! Failed to fork debug process\n"; -static const char exec_err[] = "!!! Failed to exec debug process\n"; - -static char argv0[PATH_MAX]; - -static char altstack[SIGSTKSZ]; - - -static struct { - int signum; - pid_t pid; - int has_siginfo; - siginfo_t siginfo; - char buf[1024]; -} crash_info; - - -static const struct { - const char *name; - int signum; -} signals[] = { - { "Segmentation fault", SIGSEGV }, - { "Illegal instruction", SIGILL }, - { "FPU exception", SIGFPE }, - { "System BUS error", SIGBUS }, - { NULL, 0 } -}; - -static const struct { - int code; - const char *name; -} sigill_codes[] = { -#ifndef __FreeBSD__ - { ILL_ILLOPC, "Illegal opcode" }, - { ILL_ILLOPN, "Illegal operand" }, - { ILL_ILLADR, "Illegal addressing mode" }, - { ILL_ILLTRP, "Illegal trap" }, - { ILL_PRVOPC, "Privileged opcode" }, - { ILL_PRVREG, "Privileged register" }, - { ILL_COPROC, "Coprocessor error" }, - { ILL_BADSTK, "Internal stack error" }, -#endif - { 0, NULL } -}; - -static const struct { - int code; - const char *name; -} sigfpe_codes[] = { - { FPE_INTDIV, "Integer divide by zero" }, - { FPE_INTOVF, "Integer overflow" }, - { FPE_FLTDIV, "Floating point divide by zero" }, - { FPE_FLTOVF, "Floating point overflow" }, - { FPE_FLTUND, "Floating point underflow" }, - { FPE_FLTRES, "Floating point inexact result" }, - { FPE_FLTINV, "Floating point invalid operation" }, - { FPE_FLTSUB, "Subscript out of range" }, - { 0, NULL } -}; - -static const struct { - int code; - const char *name; -} sigsegv_codes[] = { -#ifndef __FreeBSD__ - { SEGV_MAPERR, "Address not mapped to object" }, - { SEGV_ACCERR, "Invalid permissions for mapped object" }, -#endif - { 0, NULL } -}; - -static const struct { - int code; - const char *name; -} sigbus_codes[] = { -#ifndef __FreeBSD__ - { BUS_ADRALN, "Invalid address alignment" }, - { BUS_ADRERR, "Non-existent physical address" }, - { BUS_OBJERR, "Object specific hardware error" }, -#endif - { 0, NULL } -}; - -static int (*cc_user_info)(char*, char*); - - -static void gdb_info(pid_t pid) -{ - char respfile[64]; - char cmd_buf[128]; - FILE *f; - int fd; - - /* Create a temp file to put gdb commands into */ - strcpy(respfile, "gdb-respfile-XXXXXX"); - if((fd=mkstemp(respfile)) >= 0 && (f=fdopen(fd, "w")) != NULL) - { - fprintf(f, "attach %d\n" - "shell echo \"\"\n" - "shell echo \"* Loaded Libraries\"\n" - "info sharedlibrary\n" - "shell echo \"\"\n" - "shell echo \"* Threads\"\n" - "info threads\n" - "shell echo \"\"\n" - "shell echo \"* FPU Status\"\n" - "info float\n" - "shell echo \"\"\n" - "shell echo \"* Registers\"\n" - "info registers\n" - "shell echo \"\"\n" - "shell echo \"* Backtrace\"\n" - "thread apply all backtrace full\n" - "detach\n" - "quit\n", pid); - fclose(f); - - /* Run gdb and print process info. */ - snprintf(cmd_buf, sizeof(cmd_buf), "gdb --quiet --batch --command=%s", respfile); - printf("Executing: %s\n", cmd_buf); - fflush(stdout); - - system(cmd_buf); - /* Clean up */ - remove(respfile); - } - else - { - /* Error creating temp file */ - if(fd >= 0) - { - close(fd); - remove(respfile); - } - printf("!!! Could not create gdb command file\n"); - } - fflush(stdout); -} - -static void sys_info(void) -{ -#ifdef __unix__ - system("echo \"System: `uname -a`\""); - putchar('\n'); - fflush(stdout); -#endif -} - - -static size_t safe_write(int fd, const void *buf, size_t len) -{ - size_t ret = 0; - while(ret < len) - { - ssize_t rem; - if((rem=write(fd, (const char*)buf+ret, len-ret)) == -1) - { - if(errno == EINTR) - continue; - break; - } - ret += rem; - } - return ret; -} - -static void crash_catcher(int signum, siginfo_t *siginfo, void *context) -{ - //ucontext_t *ucontext = (ucontext_t*)context; - pid_t dbg_pid; - int fd[2]; - - /* Make sure the effective uid is the real uid */ - if(getuid() != geteuid()) - { - raise(signum); - return; - } - - safe_write(STDERR_FILENO, fatal_err, sizeof(fatal_err)-1); - if(pipe(fd) == -1) - { - safe_write(STDERR_FILENO, pipe_err, sizeof(pipe_err)-1); - raise(signum); - return; - } - - crash_info.signum = signum; - crash_info.pid = getpid(); - crash_info.has_siginfo = !!siginfo; - if(siginfo) - crash_info.siginfo = *siginfo; - if(cc_user_info) - cc_user_info(crash_info.buf, crash_info.buf+sizeof(crash_info.buf)); - - /* Fork off to start a crash handler */ - switch((dbg_pid=fork())) - { - /* Error */ - case -1: - safe_write(STDERR_FILENO, fork_err, sizeof(fork_err)-1); - raise(signum); - return; - - case 0: - dup2(fd[0], STDIN_FILENO); - close(fd[0]); - close(fd[1]); - - execl(argv0, argv0, crash_switch, NULL); - - safe_write(STDERR_FILENO, exec_err, sizeof(exec_err)-1); - _exit(1); - - default: -#ifdef __linux__ - prctl(PR_SET_PTRACER, dbg_pid, 0, 0, 0); -#endif - safe_write(fd[1], &crash_info, sizeof(crash_info)); - close(fd[0]); - close(fd[1]); - - /* Wait; we'll be killed when gdb is done */ - do { - int status; - if(waitpid(dbg_pid, &status, 0) == dbg_pid && - (WIFEXITED(status) || WIFSIGNALED(status))) - { - /* The debug process died before it could kill us */ - raise(signum); - break; - } - } while(1); - } -} - -static void crash_handler(const char *logfile) -{ - const char *sigdesc = ""; - int i; - - if(fread(&crash_info, sizeof(crash_info), 1, stdin) != 1) - { - fprintf(stderr, "!!! Failed to retrieve info from crashed process\n"); - exit(1); - } - - /* Get the signal description */ - for(i = 0;signals[i].name;++i) - { - if(signals[i].signum == crash_info.signum) - { - sigdesc = signals[i].name; - break; - } - } - - if(crash_info.has_siginfo) - { - switch(crash_info.signum) - { - case SIGSEGV: - for(i = 0;sigsegv_codes[i].name;++i) - { - if(sigsegv_codes[i].code == crash_info.siginfo.si_code) - { - sigdesc = sigsegv_codes[i].name; - break; - } - } - break; - - case SIGFPE: - for(i = 0;sigfpe_codes[i].name;++i) - { - if(sigfpe_codes[i].code == crash_info.siginfo.si_code) - { - sigdesc = sigfpe_codes[i].name; - break; - } - } - break; - - case SIGILL: - for(i = 0;sigill_codes[i].name;++i) - { - if(sigill_codes[i].code == crash_info.siginfo.si_code) - { - sigdesc = sigill_codes[i].name; - break; - } - } - break; - - case SIGBUS: - for(i = 0;sigbus_codes[i].name;++i) - { - if(sigbus_codes[i].code == crash_info.siginfo.si_code) - { - sigdesc = sigbus_codes[i].name; - break; - } - } - break; - } - } - fprintf(stderr, "%s (signal %i)\n", sigdesc, crash_info.signum); - if(crash_info.has_siginfo) - fprintf(stderr, "Address: %p\n", crash_info.siginfo.si_addr); - fputc('\n', stderr); - - if(logfile) - { - /* Create crash log file and redirect shell output to it */ - if(freopen(logfile, "wa", stdout) != stdout) - { - fprintf(stderr, "!!! Could not create %s following signal\n", logfile); - exit(1); - } - fprintf(stderr, "Generating %s and killing process %d, please wait... ", logfile, crash_info.pid); - - printf("*** Fatal Error ***\n" - "%s (signal %i)\n", sigdesc, crash_info.signum); - if(crash_info.has_siginfo) - printf("Address: %p\n", crash_info.siginfo.si_addr); - fputc('\n', stdout); - fflush(stdout); - } - - sys_info(); - - crash_info.buf[sizeof(crash_info.buf)-1] = '\0'; - printf("%s\n", crash_info.buf); - fflush(stdout); - - if(crash_info.pid > 0) - { - gdb_info(crash_info.pid); - kill(crash_info.pid, SIGKILL); - } - - if(logfile) - { - const char *str; - char buf[512]; - - if((str=getenv("KDE_FULL_SESSION")) && strcmp(str, "true") == 0) - snprintf(buf, sizeof(buf), "kdialog --title \"Very Fatal Error\" --textbox \"%s\" 800 600", logfile); - else if((str=getenv("GNOME_DESKTOP_SESSION_ID")) && str[0] != '\0') - snprintf(buf, sizeof(buf), "gxmessage -buttons \"Okay:0\" -geometry 800x600 -title \"Very Fatal Error\" -center -file \"%s\"", logfile); - else - snprintf(buf, sizeof(buf), "xmessage -buttons \"Okay:0\" -center -file \"%s\"", logfile); - - system(buf); - } - exit(0); -} - -int cc_install_handlers(int argc, char **argv, int num_signals, int *signals, const char *logfile, int (*user_info)(char*, char*)) -{ - struct sigaction sa; - stack_t altss; - int retval; - - if(argc == 2 && strcmp(argv[1], crash_switch) == 0) - crash_handler(logfile); - - cc_user_info = user_info; - - if(argv[0][0] == '/') - snprintf(argv0, sizeof(argv0), "%s", argv[0]); - else - { - getcwd(argv0, sizeof(argv0)); - retval = strlen(argv0); - snprintf(argv0+retval, sizeof(argv0)-retval, "/%s", argv[0]); - } - - /* Set an alternate signal stack so SIGSEGVs caused by stack overflows - * still run */ - altss.ss_sp = altstack; - altss.ss_flags = 0; - altss.ss_size = sizeof(altstack); - sigaltstack(&altss, NULL); - - memset(&sa, 0, sizeof(sa)); - sa.sa_sigaction = crash_catcher; - sa.sa_flags = SA_RESETHAND | SA_NODEFER | SA_SIGINFO | SA_ONSTACK; - sigemptyset(&sa.sa_mask); - - retval = 0; - while(num_signals--) - { - if((*signals != SIGSEGV && *signals != SIGILL && *signals != SIGFPE && - *signals != SIGBUS) || sigaction(*signals, &sa, NULL) == -1) - { - *signals = 0; - retval = -1; - } - ++signals; - } - return retval; -} +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#ifndef PR_SET_PTRACER +#define PR_SET_PTRACER 0x59616d61 +#endif +#elif defined (__APPLE__) +#include +#endif + + +static const char crash_switch[] = "--cc-handle-crash"; + +static const char fatal_err[] = "\n\n*** Fatal Error ***\n"; +static const char pipe_err[] = "!!! Failed to create pipe\n"; +static const char fork_err[] = "!!! Failed to fork debug process\n"; +static const char exec_err[] = "!!! Failed to exec debug process\n"; + +static char argv0[PATH_MAX]; + +static char altstack[SIGSTKSZ]; + + +static struct { + int signum; + pid_t pid; + int has_siginfo; + siginfo_t siginfo; + char buf[1024]; +} crash_info; + + +static const struct { + const char *name; + int signum; +} signals[] = { + { "Segmentation fault", SIGSEGV }, + { "Illegal instruction", SIGILL }, + { "FPU exception", SIGFPE }, + { "System BUS error", SIGBUS }, + { NULL, 0 } +}; + +static const struct { + int code; + const char *name; +} sigill_codes[] = { +#ifndef __FreeBSD__ + { ILL_ILLOPC, "Illegal opcode" }, + { ILL_ILLOPN, "Illegal operand" }, + { ILL_ILLADR, "Illegal addressing mode" }, + { ILL_ILLTRP, "Illegal trap" }, + { ILL_PRVOPC, "Privileged opcode" }, + { ILL_PRVREG, "Privileged register" }, + { ILL_COPROC, "Coprocessor error" }, + { ILL_BADSTK, "Internal stack error" }, +#endif + { 0, NULL } +}; + +static const struct { + int code; + const char *name; +} sigfpe_codes[] = { + { FPE_INTDIV, "Integer divide by zero" }, + { FPE_INTOVF, "Integer overflow" }, + { FPE_FLTDIV, "Floating point divide by zero" }, + { FPE_FLTOVF, "Floating point overflow" }, + { FPE_FLTUND, "Floating point underflow" }, + { FPE_FLTRES, "Floating point inexact result" }, + { FPE_FLTINV, "Floating point invalid operation" }, + { FPE_FLTSUB, "Subscript out of range" }, + { 0, NULL } +}; + +static const struct { + int code; + const char *name; +} sigsegv_codes[] = { +#ifndef __FreeBSD__ + { SEGV_MAPERR, "Address not mapped to object" }, + { SEGV_ACCERR, "Invalid permissions for mapped object" }, +#endif + { 0, NULL } +}; + +static const struct { + int code; + const char *name; +} sigbus_codes[] = { +#ifndef __FreeBSD__ + { BUS_ADRALN, "Invalid address alignment" }, + { BUS_ADRERR, "Non-existent physical address" }, + { BUS_OBJERR, "Object specific hardware error" }, +#endif + { 0, NULL } +}; + +static int (*cc_user_info)(char*, char*); + + +static void gdb_info(pid_t pid) +{ + char respfile[64]; + char cmd_buf[128]; + FILE *f; + int fd; + + /* Create a temp file to put gdb commands into */ + strcpy(respfile, "gdb-respfile-XXXXXX"); + if((fd=mkstemp(respfile)) >= 0 && (f=fdopen(fd, "w")) != NULL) + { + fprintf(f, "attach %d\n" + "shell echo \"\"\n" + "shell echo \"* Loaded Libraries\"\n" + "info sharedlibrary\n" + "shell echo \"\"\n" + "shell echo \"* Threads\"\n" + "info threads\n" + "shell echo \"\"\n" + "shell echo \"* FPU Status\"\n" + "info float\n" + "shell echo \"\"\n" + "shell echo \"* Registers\"\n" + "info registers\n" + "shell echo \"\"\n" + "shell echo \"* Backtrace\"\n" + "thread apply all backtrace full\n" + "detach\n" + "quit\n", pid); + fclose(f); + + /* Run gdb and print process info. */ + snprintf(cmd_buf, sizeof(cmd_buf), "gdb --quiet --batch --command=%s", respfile); + printf("Executing: %s\n", cmd_buf); + fflush(stdout); + + system(cmd_buf); + /* Clean up */ + remove(respfile); + } + else + { + /* Error creating temp file */ + if(fd >= 0) + { + close(fd); + remove(respfile); + } + printf("!!! Could not create gdb command file\n"); + } + fflush(stdout); +} + +static void sys_info(void) +{ +#ifdef __unix__ + system("echo \"System: `uname -a`\""); + putchar('\n'); + fflush(stdout); +#endif +} + + +static size_t safe_write(int fd, const void *buf, size_t len) +{ + size_t ret = 0; + while(ret < len) + { + ssize_t rem; + if((rem=write(fd, (const char*)buf+ret, len-ret)) == -1) + { + if(errno == EINTR) + continue; + break; + } + ret += rem; + } + return ret; +} + +static void crash_catcher(int signum, siginfo_t *siginfo, void *context) +{ + //ucontext_t *ucontext = (ucontext_t*)context; + pid_t dbg_pid; + int fd[2]; + + /* Make sure the effective uid is the real uid */ + if(getuid() != geteuid()) + { + raise(signum); + return; + } + + safe_write(STDERR_FILENO, fatal_err, sizeof(fatal_err)-1); + if(pipe(fd) == -1) + { + safe_write(STDERR_FILENO, pipe_err, sizeof(pipe_err)-1); + raise(signum); + return; + } + + crash_info.signum = signum; + crash_info.pid = getpid(); + crash_info.has_siginfo = !!siginfo; + if(siginfo) + crash_info.siginfo = *siginfo; + if(cc_user_info) + cc_user_info(crash_info.buf, crash_info.buf+sizeof(crash_info.buf)); + + /* Fork off to start a crash handler */ + switch((dbg_pid=fork())) + { + /* Error */ + case -1: + safe_write(STDERR_FILENO, fork_err, sizeof(fork_err)-1); + raise(signum); + return; + + case 0: + dup2(fd[0], STDIN_FILENO); + close(fd[0]); + close(fd[1]); + + execl(argv0, argv0, crash_switch, NULL); + + safe_write(STDERR_FILENO, exec_err, sizeof(exec_err)-1); + _exit(1); + + default: +#ifdef __linux__ + prctl(PR_SET_PTRACER, dbg_pid, 0, 0, 0); +#endif + safe_write(fd[1], &crash_info, sizeof(crash_info)); + close(fd[0]); + close(fd[1]); + + /* Wait; we'll be killed when gdb is done */ + do { + int status; + if(waitpid(dbg_pid, &status, 0) == dbg_pid && + (WIFEXITED(status) || WIFSIGNALED(status))) + { + /* The debug process died before it could kill us */ + raise(signum); + break; + } + } while(1); + } +} + +static void crash_handler(const char *logfile) +{ + const char *sigdesc = ""; + int i; + + if(fread(&crash_info, sizeof(crash_info), 1, stdin) != 1) + { + fprintf(stderr, "!!! Failed to retrieve info from crashed process\n"); + exit(1); + } + + /* Get the signal description */ + for(i = 0;signals[i].name;++i) + { + if(signals[i].signum == crash_info.signum) + { + sigdesc = signals[i].name; + break; + } + } + + if(crash_info.has_siginfo) + { + switch(crash_info.signum) + { + case SIGSEGV: + for(i = 0;sigsegv_codes[i].name;++i) + { + if(sigsegv_codes[i].code == crash_info.siginfo.si_code) + { + sigdesc = sigsegv_codes[i].name; + break; + } + } + break; + + case SIGFPE: + for(i = 0;sigfpe_codes[i].name;++i) + { + if(sigfpe_codes[i].code == crash_info.siginfo.si_code) + { + sigdesc = sigfpe_codes[i].name; + break; + } + } + break; + + case SIGILL: + for(i = 0;sigill_codes[i].name;++i) + { + if(sigill_codes[i].code == crash_info.siginfo.si_code) + { + sigdesc = sigill_codes[i].name; + break; + } + } + break; + + case SIGBUS: + for(i = 0;sigbus_codes[i].name;++i) + { + if(sigbus_codes[i].code == crash_info.siginfo.si_code) + { + sigdesc = sigbus_codes[i].name; + break; + } + } + break; + } + } + fprintf(stderr, "%s (signal %i)\n", sigdesc, crash_info.signum); + if(crash_info.has_siginfo) + fprintf(stderr, "Address: %p\n", crash_info.siginfo.si_addr); + fputc('\n', stderr); + + if(logfile) + { + /* Create crash log file and redirect shell output to it */ + if(freopen(logfile, "wa", stdout) != stdout) + { + fprintf(stderr, "!!! Could not create %s following signal\n", logfile); + exit(1); + } + fprintf(stderr, "Generating %s and killing process %d, please wait... ", logfile, crash_info.pid); + + printf("*** Fatal Error ***\n" + "%s (signal %i)\n", sigdesc, crash_info.signum); + if(crash_info.has_siginfo) + printf("Address: %p\n", crash_info.siginfo.si_addr); + fputc('\n', stdout); + fflush(stdout); + } + + sys_info(); + + crash_info.buf[sizeof(crash_info.buf)-1] = '\0'; + printf("%s\n", crash_info.buf); + fflush(stdout); + + if(crash_info.pid > 0) + { + gdb_info(crash_info.pid); + kill(crash_info.pid, SIGKILL); + } + + if(logfile) + { + const char *str; + char buf[512]; + + if((str=getenv("KDE_FULL_SESSION")) && strcmp(str, "true") == 0) + snprintf(buf, sizeof(buf), "kdialog --title \"Very Fatal Error\" --textbox \"%s\" 800 600", logfile); + else if((str=getenv("GNOME_DESKTOP_SESSION_ID")) && str[0] != '\0') + snprintf(buf, sizeof(buf), "gxmessage -buttons \"Okay:0\" -geometry 800x600 -title \"Very Fatal Error\" -center -file \"%s\"", logfile); + else + snprintf(buf, sizeof(buf), "xmessage -buttons \"Okay:0\" -center -file \"%s\"", logfile); + + system(buf); + } + exit(0); +} + +int cc_install_handlers(int argc, char **argv, int num_signals, int *signals, const char *logfile, int (*user_info)(char*, char*)) +{ + struct sigaction sa; + stack_t altss; + int retval; + + if(argc == 2 && strcmp(argv[1], crash_switch) == 0) + crash_handler(logfile); + + cc_user_info = user_info; + + if(argv[0][0] == '/') + snprintf(argv0, sizeof(argv0), "%s", argv[0]); + else + { + getcwd(argv0, sizeof(argv0)); + retval = strlen(argv0); + snprintf(argv0+retval, sizeof(argv0)-retval, "/%s", argv[0]); + } + + /* Set an alternate signal stack so SIGSEGVs caused by stack overflows + * still run */ + altss.ss_sp = altstack; + altss.ss_flags = 0; + altss.ss_size = sizeof(altstack); + sigaltstack(&altss, NULL); + + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = crash_catcher; + sa.sa_flags = SA_RESETHAND | SA_NODEFER | SA_SIGINFO | SA_ONSTACK; + sigemptyset(&sa.sa_mask); + + retval = 0; + while(num_signals--) + { + if((*signals != SIGSEGV && *signals != SIGILL && *signals != SIGFPE && + *signals != SIGBUS) || sigaction(*signals, &sa, NULL) == -1) + { + *signals = 0; + retval = -1; + } + ++signals; + } + return retval; +} diff --git a/src/sdl/critsec.h b/src/posix/sdl/critsec.h similarity index 94% rename from src/sdl/critsec.h rename to src/posix/sdl/critsec.h index daaf30f7d..a3d6210af 100644 --- a/src/sdl/critsec.h +++ b/src/posix/sdl/critsec.h @@ -1,48 +1,48 @@ -// Wraps an SDL mutex object. (A critical section is a Windows synchronization -// object similar to a mutex but optimized for access by threads belonging to -// only one process, hence the class name.) - -#ifndef CRITSEC_H -#define CRITSEC_H - -#include "SDL.h" -#include "SDL_thread.h" -#include "i_system.h" - -class FCriticalSection -{ -public: - FCriticalSection() - { - CritSec = SDL_CreateMutex(); - if (CritSec == NULL) - { - I_FatalError("Failed to create a critical section mutex."); - } - } - ~FCriticalSection() - { - if (CritSec != NULL) - { - SDL_DestroyMutex(CritSec); - } - } - void Enter() - { - if (SDL_mutexP(CritSec) != 0) - { - I_FatalError("Failed entering a critical section."); - } - } - void Leave() - { - if (SDL_mutexV(CritSec) != 0) - { - I_FatalError("Failed to leave a critical section."); - } - } -private: - SDL_mutex *CritSec; -}; - -#endif +// Wraps an SDL mutex object. (A critical section is a Windows synchronization +// object similar to a mutex but optimized for access by threads belonging to +// only one process, hence the class name.) + +#ifndef CRITSEC_H +#define CRITSEC_H + +#include "SDL.h" +#include "SDL_thread.h" +#include "i_system.h" + +class FCriticalSection +{ +public: + FCriticalSection() + { + CritSec = SDL_CreateMutex(); + if (CritSec == NULL) + { + I_FatalError("Failed to create a critical section mutex."); + } + } + ~FCriticalSection() + { + if (CritSec != NULL) + { + SDL_DestroyMutex(CritSec); + } + } + void Enter() + { + if (SDL_mutexP(CritSec) != 0) + { + I_FatalError("Failed entering a critical section."); + } + } + void Leave() + { + if (SDL_mutexV(CritSec) != 0) + { + I_FatalError("Failed to leave a critical section."); + } + } +private: + SDL_mutex *CritSec; +}; + +#endif diff --git a/src/sdl/hardware.cpp b/src/posix/sdl/hardware.cpp similarity index 96% rename from src/sdl/hardware.cpp rename to src/posix/sdl/hardware.cpp index 352fe8558..25e19ff21 100644 --- a/src/sdl/hardware.cpp +++ b/src/posix/sdl/hardware.cpp @@ -1,330 +1,330 @@ -/* -** hardware.cpp -** Somewhat OS-independant interface to the screen, mouse, keyboard, and stick -** -**--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit -** 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 -#include -#include - -#include "hardware.h" -#include "i_video.h" -#include "i_system.h" -#include "c_console.h" -#include "c_cvars.h" -#include "c_dispatch.h" -#include "sdlvideo.h" -#include "v_text.h" -#include "doomstat.h" -#include "m_argv.h" -#include "r_renderer.h" -#include "r_swrenderer.h" - -EXTERN_CVAR (Bool, ticker) -EXTERN_CVAR (Bool, fullscreen) -EXTERN_CVAR (Float, vid_winscale) - -IVideo *Video; - -void I_ShutdownGraphics () -{ - if (screen) - { - DFrameBuffer *s = screen; - screen = NULL; - s->ObjectFlags |= OF_YesReallyDelete; - delete s; - } - if (Video) - delete Video, Video = NULL; -} - -void I_InitGraphics () -{ - UCVarValue val; - - val.Bool = !!Args->CheckParm ("-devparm"); - ticker.SetGenericRepDefault (val, CVAR_Bool); - - Video = new SDLVideo (0); - if (Video == NULL) - I_FatalError ("Failed to initialize display"); - - atterm (I_ShutdownGraphics); - - Video->SetWindowedScale (vid_winscale); -} - -static void I_DeleteRenderer() -{ - if (Renderer != NULL) delete Renderer; -} - -void I_CreateRenderer() -{ - if (Renderer == NULL) - { - Renderer = new FSoftwareRenderer; - atterm(I_DeleteRenderer); - } -} - - -/** Remaining code is common to Win32 and Linux **/ - -// VIDEO WRAPPERS --------------------------------------------------------- - -DFrameBuffer *I_SetMode (int &width, int &height, DFrameBuffer *old) -{ - bool fs = false; - switch (Video->GetDisplayType ()) - { - case DISPLAY_WindowOnly: - fs = false; - break; - case DISPLAY_FullscreenOnly: - fs = true; - break; - case DISPLAY_Both: - fs = fullscreen; - break; - } - DFrameBuffer *res = Video->CreateFrameBuffer (width, height, fs, old); - - /* Right now, CreateFrameBuffer cannot return NULL - if (res == NULL) - { - I_FatalError ("Mode %dx%d is unavailable\n", width, height); - } - */ - return res; -} - -bool I_CheckResolution (int width, int height, int bits) -{ - int twidth, theight; - - Video->StartModeIterator (bits, screen ? screen->IsFullscreen() : fullscreen); - while (Video->NextMode (&twidth, &theight, NULL)) - { - if (width == twidth && height == theight) - return true; - } - return false; -} - -void I_ClosestResolution (int *width, int *height, int bits) -{ - int twidth, theight; - int cwidth = 0, cheight = 0; - int iteration; - DWORD closest = 4294967295u; - - for (iteration = 0; iteration < 2; iteration++) - { - Video->StartModeIterator (bits, screen ? screen->IsFullscreen() : fullscreen); - while (Video->NextMode (&twidth, &theight, NULL)) - { - if (twidth == *width && theight == *height) - return; - - if (iteration == 0 && (twidth < *width || theight < *height)) - continue; - - DWORD dist = (twidth - *width) * (twidth - *width) - + (theight - *height) * (theight - *height); - - if (dist < closest) - { - closest = dist; - cwidth = twidth; - cheight = theight; - } - } - if (closest != 4294967295u) - { - *width = cwidth; - *height = cheight; - return; - } - } -} - -//========================================================================== -// -// SetFPSLimit -// -// Initializes an event timer to fire at a rate of /sec. The video -// update will wait for this timer to trigger before updating. -// -// Pass 0 as the limit for unlimited. -// Pass a negative value for the limit to use the value of vid_maxfps. -// -//========================================================================== - -EXTERN_CVAR(Int, vid_maxfps); -EXTERN_CVAR(Bool, cl_capfps); - -#ifndef __APPLE__ -Semaphore FPSLimitSemaphore; - -static void FPSLimitNotify(sigval val) -{ - SEMAPHORE_SIGNAL(FPSLimitSemaphore) -} - -void I_SetFPSLimit(int limit) -{ - static sigevent FPSLimitEvent; - static timer_t FPSLimitTimer; - static bool FPSLimitTimerEnabled = false; - static bool EventSetup = false; - if(!EventSetup) - { - EventSetup = true; - FPSLimitEvent.sigev_notify = SIGEV_THREAD; - FPSLimitEvent.sigev_signo = 0; - FPSLimitEvent.sigev_value.sival_int = 0; - FPSLimitEvent.sigev_notify_function = FPSLimitNotify; - FPSLimitEvent.sigev_notify_attributes = NULL; - - SEMAPHORE_INIT(FPSLimitSemaphore, 0, 0) - } - - if (limit < 0) - { - limit = vid_maxfps; - } - // Kill any leftover timer. - if (FPSLimitTimerEnabled) - { - timer_delete(FPSLimitTimer); - FPSLimitTimerEnabled = false; - } - if (limit == 0) - { // no limit - DPrintf("FPS timer disabled\n"); - } - else - { - FPSLimitTimerEnabled = true; - if(timer_create(CLOCK_REALTIME, &FPSLimitEvent, &FPSLimitTimer) == -1) - Printf("Failed to create FPS limitter event\n"); - itimerspec period = { {0, 0}, {0, 0} }; - period.it_value.tv_nsec = period.it_interval.tv_nsec = 1000000000 / limit; - if(timer_settime(FPSLimitTimer, 0, &period, NULL) == -1) - Printf("Failed to set FPS limitter timer\n"); - DPrintf("FPS timer set to %u ms\n", (unsigned int) period.it_interval.tv_nsec / 1000000); - } -} -#else -// So Apple doesn't support POSIX timers and I can't find a good substitute short of -// having Objective-C Cocoa events or something like that. -void I_SetFPSLimit(int limit) -{ -} -#endif - -CUSTOM_CVAR (Int, vid_maxfps, 200, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -{ - if (vid_maxfps < TICRATE && vid_maxfps != 0) - { - vid_maxfps = TICRATE; - } - else if (vid_maxfps > 1000) - { - vid_maxfps = 1000; - } - else if (cl_capfps == 0) - { - I_SetFPSLimit(vid_maxfps); - } -} - -extern int NewWidth, NewHeight, NewBits, DisplayBits; - -CUSTOM_CVAR (Bool, fullscreen, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - NewWidth = screen->GetWidth(); - NewHeight = screen->GetHeight(); - NewBits = DisplayBits; - setmodeneeded = true; -} - -CUSTOM_CVAR (Float, vid_winscale, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - if (self < 1.f) - { - self = 1.f; - } - else if (Video) - { - Video->SetWindowedScale (self); - NewWidth = screen->GetWidth(); - NewHeight = screen->GetHeight(); - NewBits = DisplayBits; - setmodeneeded = true; - } -} - -CCMD (vid_listmodes) -{ - static const char *ratios[5] = { "", " - 16:9", " - 16:10", "", " - 5:4" }; - int width, height, bits; - bool letterbox; - - if (Video == NULL) - { - return; - } - for (bits = 1; bits <= 32; bits++) - { - Video->StartModeIterator (bits, screen->IsFullscreen()); - while (Video->NextMode (&width, &height, &letterbox)) - { - bool thisMode = (width == DisplayWidth && height == DisplayHeight && bits == DisplayBits); - int ratio = CheckRatio (width, height); - Printf (thisMode ? PRINT_BOLD : PRINT_HIGH, - "%s%4d x%5d x%3d%s%s\n", - thisMode || !(ratio & 3) ? "" : TEXTCOLOR_GOLD, - width, height, bits, - ratios[ratio], - thisMode || !letterbox ? "" : TEXTCOLOR_BROWN " LB" - ); - } - } -} - -CCMD (vid_currentmode) -{ - Printf ("%dx%dx%d\n", DisplayWidth, DisplayHeight, DisplayBits); -} +/* +** hardware.cpp +** Somewhat OS-independant interface to the screen, mouse, keyboard, and stick +** +**--------------------------------------------------------------------------- +** Copyright 1998-2006 Randy Heit +** 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 +#include +#include + +#include "hardware.h" +#include "i_video.h" +#include "i_system.h" +#include "c_console.h" +#include "c_cvars.h" +#include "c_dispatch.h" +#include "sdlvideo.h" +#include "v_text.h" +#include "doomstat.h" +#include "m_argv.h" +#include "r_renderer.h" +#include "r_swrenderer.h" + +EXTERN_CVAR (Bool, ticker) +EXTERN_CVAR (Bool, fullscreen) +EXTERN_CVAR (Float, vid_winscale) + +IVideo *Video; + +void I_ShutdownGraphics () +{ + if (screen) + { + DFrameBuffer *s = screen; + screen = NULL; + s->ObjectFlags |= OF_YesReallyDelete; + delete s; + } + if (Video) + delete Video, Video = NULL; +} + +void I_InitGraphics () +{ + UCVarValue val; + + val.Bool = !!Args->CheckParm ("-devparm"); + ticker.SetGenericRepDefault (val, CVAR_Bool); + + Video = new SDLVideo (0); + if (Video == NULL) + I_FatalError ("Failed to initialize display"); + + atterm (I_ShutdownGraphics); + + Video->SetWindowedScale (vid_winscale); +} + +static void I_DeleteRenderer() +{ + if (Renderer != NULL) delete Renderer; +} + +void I_CreateRenderer() +{ + if (Renderer == NULL) + { + Renderer = new FSoftwareRenderer; + atterm(I_DeleteRenderer); + } +} + + +/** Remaining code is common to Win32 and Linux **/ + +// VIDEO WRAPPERS --------------------------------------------------------- + +DFrameBuffer *I_SetMode (int &width, int &height, DFrameBuffer *old) +{ + bool fs = false; + switch (Video->GetDisplayType ()) + { + case DISPLAY_WindowOnly: + fs = false; + break; + case DISPLAY_FullscreenOnly: + fs = true; + break; + case DISPLAY_Both: + fs = fullscreen; + break; + } + DFrameBuffer *res = Video->CreateFrameBuffer (width, height, fs, old); + + /* Right now, CreateFrameBuffer cannot return NULL + if (res == NULL) + { + I_FatalError ("Mode %dx%d is unavailable\n", width, height); + } + */ + return res; +} + +bool I_CheckResolution (int width, int height, int bits) +{ + int twidth, theight; + + Video->StartModeIterator (bits, screen ? screen->IsFullscreen() : fullscreen); + while (Video->NextMode (&twidth, &theight, NULL)) + { + if (width == twidth && height == theight) + return true; + } + return false; +} + +void I_ClosestResolution (int *width, int *height, int bits) +{ + int twidth, theight; + int cwidth = 0, cheight = 0; + int iteration; + DWORD closest = 4294967295u; + + for (iteration = 0; iteration < 2; iteration++) + { + Video->StartModeIterator (bits, screen ? screen->IsFullscreen() : fullscreen); + while (Video->NextMode (&twidth, &theight, NULL)) + { + if (twidth == *width && theight == *height) + return; + + if (iteration == 0 && (twidth < *width || theight < *height)) + continue; + + DWORD dist = (twidth - *width) * (twidth - *width) + + (theight - *height) * (theight - *height); + + if (dist < closest) + { + closest = dist; + cwidth = twidth; + cheight = theight; + } + } + if (closest != 4294967295u) + { + *width = cwidth; + *height = cheight; + return; + } + } +} + +//========================================================================== +// +// SetFPSLimit +// +// Initializes an event timer to fire at a rate of /sec. The video +// update will wait for this timer to trigger before updating. +// +// Pass 0 as the limit for unlimited. +// Pass a negative value for the limit to use the value of vid_maxfps. +// +//========================================================================== + +EXTERN_CVAR(Int, vid_maxfps); +EXTERN_CVAR(Bool, cl_capfps); + +#ifndef __APPLE__ +Semaphore FPSLimitSemaphore; + +static void FPSLimitNotify(sigval val) +{ + SEMAPHORE_SIGNAL(FPSLimitSemaphore) +} + +void I_SetFPSLimit(int limit) +{ + static sigevent FPSLimitEvent; + static timer_t FPSLimitTimer; + static bool FPSLimitTimerEnabled = false; + static bool EventSetup = false; + if(!EventSetup) + { + EventSetup = true; + FPSLimitEvent.sigev_notify = SIGEV_THREAD; + FPSLimitEvent.sigev_signo = 0; + FPSLimitEvent.sigev_value.sival_int = 0; + FPSLimitEvent.sigev_notify_function = FPSLimitNotify; + FPSLimitEvent.sigev_notify_attributes = NULL; + + SEMAPHORE_INIT(FPSLimitSemaphore, 0, 0) + } + + if (limit < 0) + { + limit = vid_maxfps; + } + // Kill any leftover timer. + if (FPSLimitTimerEnabled) + { + timer_delete(FPSLimitTimer); + FPSLimitTimerEnabled = false; + } + if (limit == 0) + { // no limit + DPrintf("FPS timer disabled\n"); + } + else + { + FPSLimitTimerEnabled = true; + if(timer_create(CLOCK_REALTIME, &FPSLimitEvent, &FPSLimitTimer) == -1) + Printf("Failed to create FPS limitter event\n"); + itimerspec period = { {0, 0}, {0, 0} }; + period.it_value.tv_nsec = period.it_interval.tv_nsec = 1000000000 / limit; + if(timer_settime(FPSLimitTimer, 0, &period, NULL) == -1) + Printf("Failed to set FPS limitter timer\n"); + DPrintf("FPS timer set to %u ms\n", (unsigned int) period.it_interval.tv_nsec / 1000000); + } +} +#else +// So Apple doesn't support POSIX timers and I can't find a good substitute short of +// having Objective-C Cocoa events or something like that. +void I_SetFPSLimit(int limit) +{ +} +#endif + +CUSTOM_CVAR (Int, vid_maxfps, 200, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (vid_maxfps < TICRATE && vid_maxfps != 0) + { + vid_maxfps = TICRATE; + } + else if (vid_maxfps > 1000) + { + vid_maxfps = 1000; + } + else if (cl_capfps == 0) + { + I_SetFPSLimit(vid_maxfps); + } +} + +extern int NewWidth, NewHeight, NewBits, DisplayBits; + +CUSTOM_CVAR (Bool, fullscreen, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + NewWidth = screen->GetWidth(); + NewHeight = screen->GetHeight(); + NewBits = DisplayBits; + setmodeneeded = true; +} + +CUSTOM_CVAR (Float, vid_winscale, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (self < 1.f) + { + self = 1.f; + } + else if (Video) + { + Video->SetWindowedScale (self); + NewWidth = screen->GetWidth(); + NewHeight = screen->GetHeight(); + NewBits = DisplayBits; + setmodeneeded = true; + } +} + +CCMD (vid_listmodes) +{ + static const char *ratios[5] = { "", " - 16:9", " - 16:10", "", " - 5:4" }; + int width, height, bits; + bool letterbox; + + if (Video == NULL) + { + return; + } + for (bits = 1; bits <= 32; bits++) + { + Video->StartModeIterator (bits, screen->IsFullscreen()); + while (Video->NextMode (&width, &height, &letterbox)) + { + bool thisMode = (width == DisplayWidth && height == DisplayHeight && bits == DisplayBits); + int ratio = CheckRatio (width, height); + Printf (thisMode ? PRINT_BOLD : PRINT_HIGH, + "%s%4d x%5d x%3d%s%s\n", + thisMode || !(ratio & 3) ? "" : TEXTCOLOR_GOLD, + width, height, bits, + ratios[ratio], + thisMode || !letterbox ? "" : TEXTCOLOR_BROWN " LB" + ); + } + } +} + +CCMD (vid_currentmode) +{ + Printf ("%dx%dx%d\n", DisplayWidth, DisplayHeight, DisplayBits); +} diff --git a/src/posix/sdl/i_gui.cpp b/src/posix/sdl/i_gui.cpp new file mode 100644 index 000000000..f9e6714b4 --- /dev/null +++ b/src/posix/sdl/i_gui.cpp @@ -0,0 +1,61 @@ + +// Moved from sdl/i_system.cpp + +#include + +#include + +#include "bitmap.h" +#include "v_palette.h" +#include "textures.h" + +bool I_SetCursor(FTexture *cursorpic) +{ + static SDL_Cursor *cursor; + static SDL_Surface *cursorSurface; + + if (cursorpic != NULL && cursorpic->UseType != FTexture::TEX_Null) + { + // Must be no larger than 32x32. + if (cursorpic->GetWidth() > 32 || cursorpic->GetHeight() > 32) + { + return false; + } + + if (cursorSurface == NULL) + cursorSurface = SDL_CreateRGBSurface (0, 32, 32, 32, MAKEARGB(0,255,0,0), MAKEARGB(0,0,255,0), MAKEARGB(0,0,0,255), MAKEARGB(255,0,0,0)); + + SDL_LockSurface(cursorSurface); + BYTE buffer[32*32*4]; + memset(buffer, 0, 32*32*4); + FBitmap bmp(buffer, 32*4, 32, 32); + cursorpic->CopyTrueColorPixels(&bmp, 0, 0); + memcpy(cursorSurface->pixels, bmp.GetPixels(), 32*32*4); + SDL_UnlockSurface(cursorSurface); + + if (cursor) + SDL_FreeCursor (cursor); + cursor = SDL_CreateColorCursor (cursorSurface, 0, 0); + SDL_SetCursor (cursor); + } + else + { + if (cursor) + { + SDL_SetCursor (NULL); + SDL_FreeCursor (cursor); + cursor = NULL; + } + if (cursorSurface != NULL) + { + SDL_FreeSurface(cursorSurface); + cursorSurface = NULL; + } + } + return true; +} + +void I_SetMainWindowVisible(bool visible) +{ + +} diff --git a/src/posix/sdl/i_input.cpp b/src/posix/sdl/i_input.cpp new file mode 100644 index 000000000..6fff2d2a9 --- /dev/null +++ b/src/posix/sdl/i_input.cpp @@ -0,0 +1,514 @@ +#include +#include +#include "doomtype.h" +#include "c_dispatch.h" +#include "doomdef.h" +#include "doomstat.h" +#include "m_argv.h" +#include "i_input.h" +#include "v_video.h" + +#include "d_main.h" +#include "d_event.h" +#include "d_gui.h" +#include "c_console.h" +#include "c_cvars.h" +#include "i_system.h" +#include "dikeys.h" +#include "templates.h" +#include "s_sound.h" + +void ScaleWithAspect (int &w, int &h, int Width, int Height); + +static void I_CheckGUICapture (); +static void I_CheckNativeMouse (); + +bool GUICapture; +static bool NativeMouse = true; + +extern int paused; + +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) + +EXTERN_CVAR (Bool, fullscreen) + +extern int WaitingForKey, chatmodeon; +extern constate_e ConsoleState; + +static bool DownState[SDL_NUM_SCANCODES]; + +static const SDL_Keycode DIKToKeySym[256] = +{ + 0, SDLK_ESCAPE, SDLK_1, SDLK_2, SDLK_3, SDLK_4, SDLK_5, SDLK_6, + SDLK_7, SDLK_8, SDLK_9, SDLK_0,SDLK_MINUS, SDLK_EQUALS, SDLK_BACKSPACE, SDLK_TAB, + SDLK_q, SDLK_w, SDLK_e, SDLK_r, SDLK_t, SDLK_y, SDLK_u, SDLK_i, + SDLK_o, SDLK_p, SDLK_LEFTBRACKET, SDLK_RIGHTBRACKET, SDLK_RETURN, SDLK_LCTRL, SDLK_a, SDLK_s, + SDLK_d, SDLK_f, SDLK_g, SDLK_h, SDLK_j, SDLK_k, SDLK_l, SDLK_SEMICOLON, + SDLK_QUOTE, SDLK_BACKQUOTE, SDLK_LSHIFT, SDLK_BACKSLASH, SDLK_z, SDLK_x, SDLK_c, SDLK_v, + SDLK_b, SDLK_n, SDLK_m, SDLK_COMMA, SDLK_PERIOD, SDLK_SLASH, SDLK_RSHIFT, SDLK_KP_MULTIPLY, + SDLK_LALT, SDLK_SPACE, SDLK_CAPSLOCK, SDLK_F1, SDLK_F2, SDLK_F3, SDLK_F4, SDLK_F5, + SDLK_F6, SDLK_F7, SDLK_F8, SDLK_F9, SDLK_F10, SDLK_NUMLOCKCLEAR, SDLK_SCROLLLOCK, SDLK_KP_7, + SDLK_KP_8, SDLK_KP_9, SDLK_KP_MINUS, SDLK_KP_4, SDLK_KP_5, SDLK_KP_6, SDLK_KP_PLUS, SDLK_KP_1, + SDLK_KP_2, SDLK_KP_3, SDLK_KP_0, SDLK_KP_PERIOD, 0, 0, 0, SDLK_F11, + SDLK_F12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, SDLK_F13, SDLK_F14, SDLK_F15, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, SDLK_KP_EQUALS, 0, 0, + 0, SDLK_AT, SDLK_COLON, 0, 0, 0, 0, 0, + 0, 0, 0, 0, SDLK_KP_ENTER, SDLK_RCTRL, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, SDLK_KP_COMMA, 0, SDLK_KP_DIVIDE, 0, SDLK_SYSREQ, + SDLK_RALT, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, SDLK_PAUSE, 0, SDLK_HOME, + SDLK_UP, SDLK_PAGEUP, 0, SDLK_LEFT, 0, SDLK_RIGHT, 0, SDLK_END, + SDLK_DOWN, SDLK_PAGEDOWN, SDLK_INSERT, SDLK_DELETE, 0, 0, 0, 0, + 0, 0, 0, SDLK_LGUI, SDLK_RGUI, SDLK_MENU, SDLK_POWER, SDLK_SLEEP, + 0, 0, 0, 0, 0, SDLK_AC_SEARCH, SDLK_AC_BOOKMARKS, SDLK_AC_REFRESH, + SDLK_AC_STOP, SDLK_AC_FORWARD, SDLK_AC_BACK, SDLK_COMPUTER, SDLK_MAIL, SDLK_MEDIASELECT, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static const SDL_Scancode DIKToKeyScan[256] = +{ + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_ESCAPE, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3, SDL_SCANCODE_4, SDL_SCANCODE_5, SDL_SCANCODE_6, + SDL_SCANCODE_7, SDL_SCANCODE_8, SDL_SCANCODE_9, SDL_SCANCODE_0 ,SDL_SCANCODE_MINUS, SDL_SCANCODE_EQUALS, SDL_SCANCODE_BACKSPACE, SDL_SCANCODE_TAB, + SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_E, SDL_SCANCODE_R, SDL_SCANCODE_T, SDL_SCANCODE_Y, SDL_SCANCODE_U, SDL_SCANCODE_I, + SDL_SCANCODE_O, SDL_SCANCODE_P, SDL_SCANCODE_LEFTBRACKET, SDL_SCANCODE_RIGHTBRACKET, SDL_SCANCODE_RETURN, SDL_SCANCODE_LCTRL, SDL_SCANCODE_A, SDL_SCANCODE_S, + SDL_SCANCODE_D, SDL_SCANCODE_F, SDL_SCANCODE_G, SDL_SCANCODE_H, SDL_SCANCODE_J, SDL_SCANCODE_K, SDL_SCANCODE_L, SDL_SCANCODE_SEMICOLON, + SDL_SCANCODE_APOSTROPHE, SDL_SCANCODE_GRAVE, SDL_SCANCODE_LSHIFT, SDL_SCANCODE_BACKSLASH, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_C, SDL_SCANCODE_V, + SDL_SCANCODE_B, SDL_SCANCODE_N, SDL_SCANCODE_M, SDL_SCANCODE_COMMA, SDL_SCANCODE_PERIOD, SDL_SCANCODE_SLASH, SDL_SCANCODE_RSHIFT, SDL_SCANCODE_KP_MULTIPLY, + SDL_SCANCODE_LALT, SDL_SCANCODE_SPACE, SDL_SCANCODE_CAPSLOCK, SDL_SCANCODE_F1, SDL_SCANCODE_F2, SDL_SCANCODE_F3, SDL_SCANCODE_F4, SDL_SCANCODE_F5, + SDL_SCANCODE_F6, SDL_SCANCODE_F7, SDL_SCANCODE_F8, SDL_SCANCODE_F9, SDL_SCANCODE_F10, SDL_SCANCODE_NUMLOCKCLEAR, SDL_SCANCODE_SCROLLLOCK, SDL_SCANCODE_KP_7, + SDL_SCANCODE_KP_8, SDL_SCANCODE_KP_9, SDL_SCANCODE_KP_MINUS, SDL_SCANCODE_KP_4, SDL_SCANCODE_KP_5, SDL_SCANCODE_KP_6, SDL_SCANCODE_KP_PLUS, SDL_SCANCODE_KP_1, + SDL_SCANCODE_KP_2, SDL_SCANCODE_KP_3, SDL_SCANCODE_KP_0, SDL_SCANCODE_KP_PERIOD, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_F11, + SDL_SCANCODE_F12, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_F13, SDL_SCANCODE_F14, SDL_SCANCODE_F15, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_EQUALS, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_ENTER, SDL_SCANCODE_RCTRL, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_COMMA, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_KP_DIVIDE, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_SYSREQ, + SDL_SCANCODE_RALT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_PAUSE, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_HOME, + SDL_SCANCODE_UP, SDL_SCANCODE_PAGEUP, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_LEFT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_RIGHT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_END, + SDL_SCANCODE_DOWN, SDL_SCANCODE_PAGEDOWN, SDL_SCANCODE_INSERT, SDL_SCANCODE_DELETE, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_LGUI, SDL_SCANCODE_RGUI, SDL_SCANCODE_MENU, SDL_SCANCODE_POWER, SDL_SCANCODE_SLEEP, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_AC_SEARCH, SDL_SCANCODE_AC_BOOKMARKS, SDL_SCANCODE_AC_REFRESH, + SDL_SCANCODE_AC_STOP, SDL_SCANCODE_AC_FORWARD, SDL_SCANCODE_AC_BACK, SDL_SCANCODE_COMPUTER, SDL_SCANCODE_MAIL, SDL_SCANCODE_MEDIASELECT, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN +}; + +static TMap InitKeySymMap () +{ + TMap KeySymToDIK; + + for (int i = 0; i < 256; ++i) + { + KeySymToDIK[DIKToKeySym[i]] = i; + } + KeySymToDIK[0] = 0; + KeySymToDIK[SDLK_RSHIFT] = DIK_LSHIFT; + KeySymToDIK[SDLK_RCTRL] = DIK_LCONTROL; + KeySymToDIK[SDLK_RALT] = DIK_LMENU; + // Depending on your Linux flavor, you may get SDLK_PRINT or SDLK_SYSREQ + KeySymToDIK[SDLK_PRINTSCREEN] = DIK_SYSRQ; + + return KeySymToDIK; +} +static const TMap KeySymToDIK(InitKeySymMap()); + +static TMap InitKeyScanMap () +{ + TMap KeyScanToDIK; + + for (int i = 0; i < 256; ++i) + { + KeyScanToDIK[DIKToKeyScan[i]] = i; + } + + return KeyScanToDIK; +} +static const TMap KeyScanToDIK(InitKeyScanMap()); + +static void I_CheckGUICapture () +{ + bool wantCapt; + + if (menuactive == MENU_Off) + { + wantCapt = ConsoleState == c_down || ConsoleState == c_falling || chatmodeon; + } + else + { + wantCapt = (menuactive == MENU_On || menuactive == MENU_OnNoPause); + } + + if (wantCapt != GUICapture) + { + GUICapture = wantCapt; + if (wantCapt) + { + memset (DownState, 0, sizeof(DownState)); + } + } +} + +void I_SetMouseCapture() +{ + // Clear out any mouse movement. + SDL_GetRelativeMouseState (NULL, NULL); + SDL_SetRelativeMouseMode (SDL_TRUE); +} + +void I_ReleaseMouseCapture() +{ + SDL_SetRelativeMouseMode (SDL_FALSE); +} + +static void PostMouseMove (int x, int y) +{ + static int lastx = 0, lasty = 0; + event_t ev = { 0,0,0,0,0,0,0 }; + + if (m_filter) + { + ev.x = (x + lastx) / 2; + ev.y = (y + lasty) / 2; + } + else + { + ev.x = x; + ev.y = y; + } + lastx = x; + lasty = y; + if (ev.x | ev.y) + { + ev.type = EV_Mouse; + D_PostEvent (&ev); + } +} + +static void MouseRead () +{ + int x, y; + + if (NativeMouse) + { + return; + } + + SDL_GetRelativeMouseState (&x, &y); + if (!m_noprescale) + { + x *= 3; + y *= 2; + } + if (x | y) + { + PostMouseMove (x, -y); + } +} + +CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) +{ + if (self < 0) self = 0; + else if (self > 2) self = 2; +} + +static bool inGame() +{ + 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; + } +} + +static void I_CheckNativeMouse () +{ + bool focus = SDL_GetKeyboardFocus() != NULL; + bool fs = screen->IsFullscreen(); + + bool wantNative = !focus || (!use_mouse || GUICapture || paused || demoplayback || !inGame()); + + if (wantNative != NativeMouse) + { + NativeMouse = wantNative; + SDL_ShowCursor (wantNative); + if (wantNative) + I_ReleaseMouseCapture (); + else + I_SetMouseCapture (); + } +} + +void MessagePump (const SDL_Event &sev) +{ + static int lastx = 0, lasty = 0; + int x, y; + event_t event = { 0,0,0,0,0,0,0 }; + + switch (sev.type) + { + case SDL_QUIT: + exit (0); + + case SDL_WINDOWEVENT: + switch (sev.window.event) + { + case SDL_WINDOWEVENT_FOCUS_GAINED: + case SDL_WINDOWEVENT_FOCUS_LOST: + S_SetSoundPaused(sev.window.event == SDL_WINDOWEVENT_FOCUS_GAINED); + break; + } + break; + + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + case SDL_MOUSEMOTION: + if (!GUICapture || sev.button.button == 4 || sev.button.button == 5) + { + if(sev.type != SDL_MOUSEMOTION) + { + event.type = sev.type == SDL_MOUSEBUTTONDOWN ? EV_KeyDown : EV_KeyUp; + /* These button mappings work with my Gentoo system using the + * evdev driver and a Logitech MX510 mouse. Whether or not they + * carry over to other Linux systems, I have no idea, but I sure + * hope so. (Though buttons 11 and 12 are kind of useless, since + * they also trigger buttons 4 and 5.) + */ + switch (sev.button.button) + { + case SDL_BUTTON_LEFT: event.data1 = KEY_MOUSE1; break; + case SDL_BUTTON_MIDDLE: event.data1 = KEY_MOUSE3; break; + case SDL_BUTTON_RIGHT: event.data1 = KEY_MOUSE2; break; + case 8: event.data1 = KEY_MOUSE4; break; // For whatever reason my side mouse buttons are here. + case 9: event.data1 = KEY_MOUSE5; break; + case SDL_BUTTON_X1: event.data1 = KEY_MOUSE6; break; // And these don't exist + case SDL_BUTTON_X2: event.data1 = KEY_MOUSE7; break; + case 6: event.data1 = KEY_MOUSE8; break; + default: printf("SDL mouse button %s %d\n", + sev.type == SDL_MOUSEBUTTONDOWN ? "down" : "up", sev.button.button); break; + } + if (event.data1 != 0) + { + D_PostEvent(&event); + } + } + } + else if (sev.type == SDL_MOUSEMOTION || (sev.button.button >= 1 && sev.button.button <= 3)) + { + int x, y; + SDL_GetMouseState (&x, &y); + + // Detect if we're doing scaling in the Window and adjust the mouse + // coordinates accordingly. This could be more efficent, but I + // don't think performance is an issue in the menus. + SDL_Window *focus; + if (screen->IsFullscreen() && (focus = SDL_GetMouseFocus ())) + { + int w, h; + SDL_GetWindowSize (focus, &w, &h); + int realw = w, realh = h; + ScaleWithAspect (realw, realh, SCREENWIDTH, SCREENHEIGHT); + if (realw != SCREENWIDTH || realh != SCREENHEIGHT) + { + double xratio = (double)SCREENWIDTH/realw; + double yratio = (double)SCREENHEIGHT/realh; + if (realw < w) + { + x = (x - (w - realw)/2)*xratio; + y *= yratio; + } + else + { + y = (y - (h - realh)/2)*yratio; + x *= xratio; + } + } + } + + event.data1 = x; + event.data2 = y; + event.type = EV_GUI_Event; + if(sev.type == SDL_MOUSEMOTION) + event.subtype = EV_GUI_MouseMove; + else + { + event.subtype = sev.type == SDL_MOUSEBUTTONDOWN ? EV_GUI_LButtonDown : EV_GUI_LButtonUp; + event.subtype += (sev.button.button - 1) * 3; + } + D_PostEvent(&event); + } + break; + + case SDL_MOUSEWHEEL: + if (GUICapture) + { + event.type = EV_GUI_Event; + event.subtype = sev.wheel.y > 0 ? EV_GUI_WheelUp : EV_GUI_WheelDown; + D_PostEvent (&event); + } + else + { + event.type = EV_KeyDown; + event.data1 = sev.wheel.y > 0 ? KEY_MWHEELUP : KEY_MWHEELDOWN; + D_PostEvent (&event); + event.type = EV_KeyUp; + D_PostEvent (&event); + } + break; + + case SDL_KEYDOWN: + case SDL_KEYUP: + if (!GUICapture) + { + event.type = sev.type == SDL_KEYDOWN ? EV_KeyDown : EV_KeyUp; + + // Try to look up our key mapped key for conversion to DirectInput. + // If that fails, then we'll do a lookup against the scan code, + // which may not return the right key, but at least the key should + // work in the game. + if (const BYTE *dik = KeySymToDIK.CheckKey (sev.key.keysym.sym)) + event.data1 = *dik; + else if (const BYTE *dik = KeyScanToDIK.CheckKey (sev.key.keysym.scancode)) + event.data1 = *dik; + + if (event.data1) + { + if (sev.key.keysym.sym < 256) + { + event.data2 = sev.key.keysym.sym; + } + D_PostEvent (&event); + } + } + else + { + event.type = EV_GUI_Event; + event.subtype = sev.type == SDL_KEYDOWN ? EV_GUI_KeyDown : EV_GUI_KeyUp; + event.data3 = ((sev.key.keysym.mod & KMOD_SHIFT) ? GKM_SHIFT : 0) | + ((sev.key.keysym.mod & KMOD_CTRL) ? GKM_CTRL : 0) | + ((sev.key.keysym.mod & KMOD_ALT) ? GKM_ALT : 0); + + if (event.subtype == EV_GUI_KeyDown) + { + if (DownState[sev.key.keysym.scancode]) + { + event.subtype = EV_GUI_KeyRepeat; + } + DownState[sev.key.keysym.scancode] = 1; + } + else + { + DownState[sev.key.keysym.scancode] = 0; + } + + switch (sev.key.keysym.sym) + { + case SDLK_KP_ENTER: event.data1 = GK_RETURN; break; + case SDLK_PAGEUP: event.data1 = GK_PGUP; break; + case SDLK_PAGEDOWN: event.data1 = GK_PGDN; break; + case SDLK_END: event.data1 = GK_END; break; + case SDLK_HOME: event.data1 = GK_HOME; break; + case SDLK_LEFT: event.data1 = GK_LEFT; break; + case SDLK_RIGHT: event.data1 = GK_RIGHT; break; + case SDLK_UP: event.data1 = GK_UP; break; + case SDLK_DOWN: event.data1 = GK_DOWN; break; + case SDLK_DELETE: event.data1 = GK_DEL; break; + case SDLK_ESCAPE: event.data1 = GK_ESCAPE; break; + case SDLK_F1: event.data1 = GK_F1; break; + case SDLK_F2: event.data1 = GK_F2; break; + case SDLK_F3: event.data1 = GK_F3; break; + case SDLK_F4: event.data1 = GK_F4; break; + case SDLK_F5: event.data1 = GK_F5; break; + case SDLK_F6: event.data1 = GK_F6; break; + case SDLK_F7: event.data1 = GK_F7; break; + case SDLK_F8: event.data1 = GK_F8; break; + case SDLK_F9: event.data1 = GK_F9; break; + case SDLK_F10: event.data1 = GK_F10; break; + case SDLK_F11: event.data1 = GK_F11; break; + case SDLK_F12: event.data1 = GK_F12; break; + default: + if (sev.key.keysym.sym < 256) + { + event.data1 = sev.key.keysym.sym; + } + break; + } + if (event.data1 < 128) + { + event.data1 = toupper(event.data1); + D_PostEvent (&event); + } + } + break; + + case SDL_TEXTINPUT: + if (GUICapture) + { + event.type = EV_GUI_Event; + event.subtype = EV_GUI_Char; + event.data1 = sev.text.text[0]; + D_PostEvent (&event); + } + break; + + case SDL_JOYBUTTONDOWN: + case SDL_JOYBUTTONUP: + if (!GUICapture) + { + event.type = sev.type == SDL_JOYBUTTONDOWN ? EV_KeyDown : EV_KeyUp; + event.data1 = KEY_FIRSTJOYBUTTON + sev.jbutton.button; + if(event.data1 != 0) + D_PostEvent(&event); + } + break; + } +} + +void I_GetEvent () +{ + SDL_Event sev; + + while (SDL_PollEvent (&sev)) + { + MessagePump (sev); + } + if (use_mouse) + { + MouseRead (); + } +} + +void I_StartTic () +{ + I_CheckGUICapture (); + I_CheckNativeMouse (); + I_GetEvent (); +} + +void I_ProcessJoysticks (); +void I_StartFrame () +{ + I_ProcessJoysticks(); +} diff --git a/src/sdl/i_joystick.cpp b/src/posix/sdl/i_joystick.cpp similarity index 99% rename from src/sdl/i_joystick.cpp rename to src/posix/sdl/i_joystick.cpp index 7a529861f..9b1d326ae 100644 --- a/src/sdl/i_joystick.cpp +++ b/src/posix/sdl/i_joystick.cpp @@ -35,7 +35,7 @@ public: FString GetName() { - return SDL_JoystickName(DeviceIndex); + return SDL_JoystickName(Device); } float GetSensitivity() { diff --git a/src/sdl/i_main.cpp b/src/posix/sdl/i_main.cpp similarity index 85% rename from src/sdl/i_main.cpp rename to src/posix/sdl/i_main.cpp index 7a18fb05f..ff700eff4 100644 --- a/src/sdl/i_main.cpp +++ b/src/posix/sdl/i_main.cpp @@ -1,378 +1,338 @@ -/* -** i_main.cpp -** System-specific startup code. Eventually calls D_DoomMain. -** -**--------------------------------------------------------------------------- -** Copyright 1998-2007 Randy Heit -** 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include -#include -#include -#include -#ifndef NO_GTK -#include -#endif -#include -#if defined(__MACH__) && !defined(NOASM) -#include -#include -#endif - -#include "doomerrors.h" -#include "m_argv.h" -#include "d_main.h" -#include "i_system.h" -#include "i_video.h" -#include "c_console.h" -#include "errors.h" -#include "version.h" -#include "w_wad.h" -#include "g_level.h" -#include "r_state.h" -#include "cmdlib.h" -#include "r_utility.h" -#include "doomstat.h" - -// MACROS ------------------------------------------------------------------ - -// The maximum number of functions that can be registered with atterm. -#define MAX_TERMS 64 - -// TYPES ------------------------------------------------------------------- - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -extern "C" int cc_install_handlers(int, char**, int, int*, const char*, int(*)(char*, char*)); - -#ifdef __APPLE__ -void Mac_I_FatalError(const char* errortext); -#endif - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -#ifdef USE_XCURSOR -extern bool UseXCursor; -#endif - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -#ifndef NO_GTK -bool GtkAvailable; -#endif - -// The command line arguments. -DArgs *Args; - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -static void (*TermFuncs[MAX_TERMS]) (); -static const char *TermNames[MAX_TERMS]; -static int NumTerms; - -// CODE -------------------------------------------------------------------- - -void addterm (void (*func) (), const char *name) -{ - // Make sure this function wasn't already registered. - for (int i = 0; i < NumTerms; ++i) - { - if (TermFuncs[i] == func) - { - return; - } - } - if (NumTerms == MAX_TERMS) - { - func (); - I_FatalError ( - "Too many exit functions registered.\n" - "Increase MAX_TERMS in i_main.cpp"); - } - TermNames[NumTerms] = name; - TermFuncs[NumTerms++] = func; -} - -void popterm () -{ - if (NumTerms) - NumTerms--; -} - -void STACK_ARGS call_terms () -{ - while (NumTerms > 0) - { -// printf ("term %d - %s\n", NumTerms, TermNames[NumTerms-1]); - TermFuncs[--NumTerms] (); - } -} - -static void STACK_ARGS NewFailure () -{ - I_FatalError ("Failed to allocate memory from system heap"); -} - -static int DoomSpecificInfo (char *buffer, char *end) -{ - const char *arg; - int size = end-buffer-2; - int i, p; - - p = 0; - p += snprintf (buffer+p, size-p, GAMENAME" version %s (%s)\n", GetVersionString(), GetGitHash()); -#ifdef __VERSION__ - p += snprintf (buffer+p, size-p, "Compiler version: %s\n", __VERSION__); -#endif - p += snprintf (buffer+p, size-p, "\nCommand line:"); - for (i = 0; i < Args->NumArgs(); ++i) - { - p += snprintf (buffer+p, size-p, " %s", Args->GetArg(i)); - } - p += snprintf (buffer+p, size-p, "\n"); - - for (i = 0; (arg = Wads.GetWadName (i)) != NULL; ++i) - { - p += snprintf (buffer+p, size-p, "\nWad %d: %s", i, arg); - } - - if (gamestate != GS_LEVEL && gamestate != GS_TITLELEVEL) - { - p += snprintf (buffer+p, size-p, "\n\nNot in a level."); - } - else - { - p += snprintf (buffer+p, size-p, "\n\nCurrent map: %s", level.MapName.GetChars()); - - if (!viewactive) - { - p += snprintf (buffer+p, size-p, "\n\nView not active."); - } - else - { - p += snprintf (buffer+p, size-p, "\n\nviewx = %d", (int)viewx); - p += snprintf (buffer+p, size-p, "\nviewy = %d", (int)viewy); - p += snprintf (buffer+p, size-p, "\nviewz = %d", (int)viewz); - p += snprintf (buffer+p, size-p, "\nviewangle = %x", (unsigned int)viewangle); - } - } - buffer[p++] = '\n'; - buffer[p++] = '\0'; - - return p; -} - -#if defined(__MACH__) && !defined(NOASM) -// NASM won't let us create custom sections for Mach-O. Whether that's a limitation of NASM -// or of Mach-O, I don't know, but since we're using NASM for the assembly, it doesn't much -// matter. -extern "C" -{ - extern void *rtext_a_start, *rtext_a_end; - extern void *rtext_tmap_start, *rtext_tmap_end; - extern void *rtext_tmap2_start, *rtext_tmap2_end; - extern void *rtext_tmap3_start, *rtext_tmap3_end; -}; - -static void unprotect_pages(long pagesize, void *start, void *end) -{ - char *page = (char *)((intptr_t)start & ~(pagesize - 1)); - size_t len = (char *)end - (char *)start; - if (mprotect(page, len, PROT_READ|PROT_WRITE|PROT_EXEC) != 0) - { - fprintf(stderr, "mprotect failed\n"); - exit(1); - } -} - -static void unprotect_rtext() -{ - static void *const pages[] = - { - rtext_a_start, rtext_a_end, - rtext_tmap_start, rtext_tmap_end, - rtext_tmap2_start, rtext_tmap2_end, - rtext_tmap3_start, rtext_tmap3_end - }; - long pagesize = sysconf(_SC_PAGESIZE); - for (void *const *p = pages; p < &pages[countof(pages)]; p += 2) - { - unprotect_pages(pagesize, p[0], p[1]); - } -} -#endif - -void I_StartupJoysticks(); -void I_ShutdownJoysticks(); - -const char* I_GetBackEndName(); - -int main (int argc, char **argv) -{ -#if !defined (__APPLE__) - { - int s[4] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS }; - cc_install_handlers(argc, argv, 4, s, "zdoom-crash.log", DoomSpecificInfo); - } -#endif // !__APPLE__ - - printf(GAMENAME" %s - %s - %s version\nCompiled on %s\n", - GetVersionString(), GetGitTime(), I_GetBackEndName(), __DATE__); - - seteuid (getuid ()); - std::set_new_handler (NewFailure); - -#if defined(__MACH__) && !defined(NOASM) - unprotect_rtext(); -#endif - - // 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); - -#ifndef NO_GTK - GtkAvailable = gtk_init_check (&argc, &argv); -#endif - - setlocale (LC_ALL, "C"); - - if (SDL_Init (SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_NOPARACHUTE|SDL_INIT_JOYSTICK) == -1) - { - fprintf (stderr, "Could not initialize SDL:\n%s\n", SDL_GetError()); - return -1; - } - atterm (SDL_Quit); - - { - char viddriver[80]; - - if (SDL_VideoDriverName(viddriver, sizeof(viddriver)) != NULL) - { - printf("Using video driver %s\n", viddriver); -#ifdef USE_XCURSOR - UseXCursor = (strcmp(viddriver, "x11") == 0); -#endif - } - printf("\n"); - } - - char caption[100]; - mysnprintf(caption, countof(caption), GAMESIG " %s (%s)", GetVersionString(), GetGitTime()); - SDL_WM_SetCaption(caption, caption); - -#ifdef __APPLE__ - - const SDL_VideoInfo* videoInfo = SDL_GetVideoInfo(); - if ( NULL != videoInfo ) - { - EXTERN_CVAR( Int, vid_defwidth ) - EXTERN_CVAR( Int, vid_defheight ) - EXTERN_CVAR( Int, vid_defbits ) - EXTERN_CVAR( Bool, vid_vsync ) - EXTERN_CVAR( Bool, fullscreen ) - - vid_defwidth = videoInfo->current_w; - vid_defheight = videoInfo->current_h; - vid_defbits = videoInfo->vfmt->BitsPerPixel; - vid_vsync = true; - fullscreen = true; - } - -#endif // __APPLE__ - - 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); - - // Should we even be doing anything with progdir on Unix systems? - char program[PATH_MAX]; - if (realpath (argv[0], program) == NULL) - strcpy (program, argv[0]); - char *slash = strrchr (program, '/'); - if (slash != NULL) - { - *(slash + 1) = '\0'; - progdir = program; - } - else - { - progdir = "./"; - } - - I_StartupJoysticks(); - C_InitConsole (80*8, 25*8, false); - D_DoomMain (); - } - catch (class CDoomError &error) - { - I_ShutdownJoysticks(); - if (error.GetMessage ()) - fprintf (stderr, "%s\n", error.GetMessage ()); - -#ifdef __APPLE__ - Mac_I_FatalError(error.GetMessage()); -#endif // __APPLE__ - - exit (-1); - } - catch (...) - { - call_terms (); - throw; - } - return 0; -} +/* +** i_main.cpp +** System-specific startup code. Eventually calls D_DoomMain. +** +**--------------------------------------------------------------------------- +** Copyright 1998-2007 Randy Heit +** 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. +**--------------------------------------------------------------------------- +** +*/ + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include +#include +#include +#include +#ifndef NO_GTK +#include +#endif +#include +#if defined(__MACH__) && !defined(NOASM) +#include +#include +#endif + +#include "doomerrors.h" +#include "m_argv.h" +#include "d_main.h" +#include "i_system.h" +#include "i_video.h" +#include "c_console.h" +#include "errors.h" +#include "version.h" +#include "w_wad.h" +#include "g_level.h" +#include "r_state.h" +#include "cmdlib.h" +#include "r_utility.h" +#include "doomstat.h" + +// MACROS ------------------------------------------------------------------ + +// The maximum number of functions that can be registered with atterm. +#define MAX_TERMS 64 + +// TYPES ------------------------------------------------------------------- + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +extern "C" int cc_install_handlers(int, char**, int, int*, const char*, int(*)(char*, char*)); + +#ifdef __APPLE__ +void Mac_I_FatalError(const char* errortext); +#endif + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +#ifndef NO_GTK +bool GtkAvailable; +#endif + +// The command line arguments. +DArgs *Args; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static void (*TermFuncs[MAX_TERMS]) (); +static const char *TermNames[MAX_TERMS]; +static int NumTerms; + +// CODE -------------------------------------------------------------------- + +void addterm (void (*func) (), const char *name) +{ + // Make sure this function wasn't already registered. + for (int i = 0; i < NumTerms; ++i) + { + if (TermFuncs[i] == func) + { + return; + } + } + if (NumTerms == MAX_TERMS) + { + func (); + I_FatalError ( + "Too many exit functions registered.\n" + "Increase MAX_TERMS in i_main.cpp"); + } + TermNames[NumTerms] = name; + TermFuncs[NumTerms++] = func; +} + +void popterm () +{ + if (NumTerms) + NumTerms--; +} + +void STACK_ARGS call_terms () +{ + while (NumTerms > 0) + { +// printf ("term %d - %s\n", NumTerms, TermNames[NumTerms-1]); + TermFuncs[--NumTerms] (); + } +} + +static void STACK_ARGS NewFailure () +{ + I_FatalError ("Failed to allocate memory from system heap"); +} + +static int DoomSpecificInfo (char *buffer, char *end) +{ + const char *arg; + int size = end-buffer-2; + int i, p; + + p = 0; + p += snprintf (buffer+p, size-p, GAMENAME" version %s (%s)\n", GetVersionString(), GetGitHash()); +#ifdef __VERSION__ + p += snprintf (buffer+p, size-p, "Compiler version: %s\n", __VERSION__); +#endif + p += snprintf (buffer+p, size-p, "\nCommand line:"); + for (i = 0; i < Args->NumArgs(); ++i) + { + p += snprintf (buffer+p, size-p, " %s", Args->GetArg(i)); + } + p += snprintf (buffer+p, size-p, "\n"); + + for (i = 0; (arg = Wads.GetWadName (i)) != NULL; ++i) + { + p += snprintf (buffer+p, size-p, "\nWad %d: %s", i, arg); + } + + if (gamestate != GS_LEVEL && gamestate != GS_TITLELEVEL) + { + p += snprintf (buffer+p, size-p, "\n\nNot in a level."); + } + else + { + p += snprintf (buffer+p, size-p, "\n\nCurrent map: %s", level.MapName.GetChars()); + + if (!viewactive) + { + p += snprintf (buffer+p, size-p, "\n\nView not active."); + } + else + { + p += snprintf (buffer+p, size-p, "\n\nviewx = %d", (int)viewx); + p += snprintf (buffer+p, size-p, "\nviewy = %d", (int)viewy); + p += snprintf (buffer+p, size-p, "\nviewz = %d", (int)viewz); + p += snprintf (buffer+p, size-p, "\nviewangle = %x", (unsigned int)viewangle); + } + } + buffer[p++] = '\n'; + buffer[p++] = '\0'; + + return p; +} + +#if defined(__MACH__) && !defined(NOASM) +// NASM won't let us create custom sections for Mach-O. Whether that's a limitation of NASM +// or of Mach-O, I don't know, but since we're using NASM for the assembly, it doesn't much +// matter. +extern "C" +{ + extern void *rtext_a_start, *rtext_a_end; + extern void *rtext_tmap_start, *rtext_tmap_end; + extern void *rtext_tmap2_start, *rtext_tmap2_end; + extern void *rtext_tmap3_start, *rtext_tmap3_end; +}; + +static void unprotect_pages(long pagesize, void *start, void *end) +{ + char *page = (char *)((intptr_t)start & ~(pagesize - 1)); + size_t len = (char *)end - (char *)start; + if (mprotect(page, len, PROT_READ|PROT_WRITE|PROT_EXEC) != 0) + { + fprintf(stderr, "mprotect failed\n"); + exit(1); + } +} + +static void unprotect_rtext() +{ + static void *const pages[] = + { + rtext_a_start, rtext_a_end, + rtext_tmap_start, rtext_tmap_end, + rtext_tmap2_start, rtext_tmap2_end, + rtext_tmap3_start, rtext_tmap3_end + }; + long pagesize = sysconf(_SC_PAGESIZE); + for (void *const *p = pages; p < &pages[countof(pages)]; p += 2) + { + unprotect_pages(pagesize, p[0], p[1]); + } +} +#endif + +void I_StartupJoysticks(); +void I_ShutdownJoysticks(); + +int main (int argc, char **argv) +{ +#if !defined (__APPLE__) + { + int s[4] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS }; + cc_install_handlers(argc, argv, 4, s, "zdoom-crash.log", DoomSpecificInfo); + } +#endif // !__APPLE__ + + printf(GAMENAME" %s - %s - SDL version\nCompiled on %s\n", + GetVersionString(), GetGitTime(), __DATE__); + + seteuid (getuid ()); + std::set_new_handler (NewFailure); + +#if defined(__MACH__) && !defined(NOASM) + unprotect_rtext(); +#endif + + // 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); + +#ifndef NO_GTK + GtkAvailable = gtk_init_check (&argc, &argv); +#endif + + setlocale (LC_ALL, "C"); + + if (SDL_Init (SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_NOPARACHUTE|SDL_INIT_JOYSTICK) == -1) + { + fprintf (stderr, "Could not initialize SDL:\n%s\n", SDL_GetError()); + return -1; + } + atterm (SDL_Quit); + + printf("Using video driver %s\n", SDL_GetCurrentVideoDriver()); + printf("\n"); + + 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); + + // Should we even be doing anything with progdir on Unix systems? + char program[PATH_MAX]; + if (realpath (argv[0], program) == NULL) + strcpy (program, argv[0]); + char *slash = strrchr (program, '/'); + if (slash != NULL) + { + *(slash + 1) = '\0'; + progdir = program; + } + else + { + progdir = "./"; + } + + I_StartupJoysticks(); + C_InitConsole (80*8, 25*8, false); + D_DoomMain (); + } + catch (class CDoomError &error) + { + I_ShutdownJoysticks(); + if (error.GetMessage ()) + fprintf (stderr, "%s\n", error.GetMessage ()); + +#ifdef __APPLE__ + Mac_I_FatalError(error.GetMessage()); +#endif // __APPLE__ + + exit (-1); + } + catch (...) + { + call_terms (); + throw; + } + return 0; +} diff --git a/src/sdl/i_system_cocoa.mm b/src/posix/sdl/i_system.mm similarity index 100% rename from src/sdl/i_system_cocoa.mm rename to src/posix/sdl/i_system.mm diff --git a/src/sdl/i_timer.cpp b/src/posix/sdl/i_timer.cpp similarity index 100% rename from src/sdl/i_timer.cpp rename to src/posix/sdl/i_timer.cpp diff --git a/src/sdl/sdlvideo.cpp b/src/posix/sdl/sdlvideo.cpp similarity index 65% rename from src/sdl/sdlvideo.cpp rename to src/posix/sdl/sdlvideo.cpp index e4222633d..309002456 100644 --- a/src/sdl/sdlvideo.cpp +++ b/src/posix/sdl/sdlvideo.cpp @@ -1,573 +1,732 @@ - -// HEADER FILES ------------------------------------------------------------ - -#include "doomtype.h" - -#include "templates.h" -#include "i_system.h" -#include "i_video.h" -#include "v_video.h" -#include "v_pfx.h" -#include "stats.h" -#include "v_palette.h" -#include "sdlvideo.h" -#include "r_swrenderer.h" - -#include - -#ifdef __APPLE__ -#include -#endif // __APPLE__ - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -class SDLFB : public DFrameBuffer -{ - DECLARE_CLASS(SDLFB, DFrameBuffer) -public: - SDLFB (int width, int height, bool fullscreen); - ~SDLFB (); - - bool Lock (bool buffer); - void Unlock (); - bool Relock (); - void ForceBuffering (bool force); - bool IsValid (); - void Update (); - PalEntry *GetPalette (); - void GetFlashedPalette (PalEntry pal[256]); - void UpdatePalette (); - bool SetGamma (float gamma); - bool SetFlash (PalEntry rgb, int amount); - void GetFlash (PalEntry &rgb, int &amount); - int GetPageCount (); - bool IsFullscreen (); - - friend class SDLVideo; - - virtual void SetVSync (bool vsync); - -private: - PalEntry SourcePalette[256]; - BYTE GammaTable[3][256]; - PalEntry Flash; - int FlashAmount; - float Gamma; - bool UpdatePending; - - SDL_Surface *Screen; - - bool NeedPalUpdate; - bool NeedGammaUpdate; - bool NotPaletted; - - void UpdateColors (); - - SDLFB () {} -}; -IMPLEMENT_CLASS(SDLFB) - -struct MiniModeInfo -{ - WORD Width, Height; -}; - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -extern IVideo *Video; -extern bool GUICapture; - -SDL_Surface *cursorSurface = NULL; -SDL_Rect cursorBlit = {0, 0, 32, 32}; - -EXTERN_CVAR (Float, Gamma) -EXTERN_CVAR (Int, vid_maxfps) -EXTERN_CVAR (Bool, cl_capfps) -EXTERN_CVAR (Bool, vid_vsync) - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -CVAR (Int, vid_displaybits, 8, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) - -// vid_asyncblit needs a restart to work. SDL doesn't seem to change if the -// frame buffer is changed at run time. -CVAR (Bool, vid_asyncblit, 1, CVAR_NOINITCALL|CVAR_ARCHIVE|CVAR_GLOBALCONFIG) - -CUSTOM_CVAR (Float, rgamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - if (screen != NULL) - { - screen->SetGamma (Gamma); - } -} -CUSTOM_CVAR (Float, ggamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - if (screen != NULL) - { - screen->SetGamma (Gamma); - } -} -CUSTOM_CVAR (Float, bgamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - if (screen != NULL) - { - screen->SetGamma (Gamma); - } -} - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -// Dummy screen sizes to pass when windowed -static MiniModeInfo WinModes[] = -{ - { 320, 200 }, - { 320, 240 }, - { 400, 225 }, // 16:9 - { 400, 300 }, - { 480, 270 }, // 16:9 - { 480, 360 }, - { 512, 288 }, // 16:9 - { 512, 384 }, - { 640, 360 }, // 16:9 - { 640, 400 }, - { 640, 480 }, - { 720, 480 }, // 16:10 - { 720, 540 }, - { 800, 450 }, // 16:9 - { 800, 500 }, // 16:10 - { 800, 600 }, - { 848, 480 }, // 16:9 - { 960, 600 }, // 16:10 - { 960, 720 }, - { 1024, 576 }, // 16:9 - { 1024, 640 }, // 16:10 - { 1024, 768 }, - { 1088, 612 }, // 16:9 - { 1152, 648 }, // 16:9 - { 1152, 720 }, // 16:10 - { 1152, 864 }, - { 1280, 720 }, // 16:9 - { 1280, 800 }, // 16:10 - { 1280, 960 }, - { 1360, 768 }, // 16:9 - { 1400, 787 }, // 16:9 - { 1400, 875 }, // 16:10 - { 1400, 1050 }, - { 1600, 900 }, // 16:9 - { 1600, 1000 }, // 16:10 - { 1600, 1200 }, - { 1920, 1080 }, -}; - -static cycle_t BlitCycles; -static cycle_t SDLFlipCycles; - -// CODE -------------------------------------------------------------------- - -SDLVideo::SDLVideo (int parm) -{ - IteratorBits = 0; - IteratorFS = false; -} - -SDLVideo::~SDLVideo () -{ -} - -void SDLVideo::StartModeIterator (int bits, bool fs) -{ - IteratorMode = 0; - IteratorBits = bits; - IteratorFS = fs; -} - -bool SDLVideo::NextMode (int *width, int *height, bool *letterbox) -{ - if (IteratorBits != 8) - return false; - - if (!IteratorFS) - { - if ((unsigned)IteratorMode < sizeof(WinModes)/sizeof(WinModes[0])) - { - *width = WinModes[IteratorMode].Width; - *height = WinModes[IteratorMode].Height; - ++IteratorMode; - return true; - } - } - else - { - SDL_Rect **modes = SDL_ListModes (NULL, SDL_FULLSCREEN|SDL_HWSURFACE); - if (modes != NULL && modes[IteratorMode] != NULL) - { - *width = modes[IteratorMode]->w; - *height = modes[IteratorMode]->h; - ++IteratorMode; - return true; - } - } - return false; -} - -DFrameBuffer *SDLVideo::CreateFrameBuffer (int width, int height, bool fullscreen, DFrameBuffer *old) -{ - static int retry = 0; - static int owidth, oheight; - - PalEntry flashColor; - int flashAmount; - - if (old != NULL) - { // Reuse the old framebuffer if its attributes are the same - SDLFB *fb = static_cast (old); - if (fb->Width == width && - fb->Height == height) - { - bool fsnow = (fb->Screen->flags & SDL_FULLSCREEN) != 0; - - if (fsnow != fullscreen) - { - SDL_WM_ToggleFullScreen (fb->Screen); - } - return old; - } - old->GetFlash (flashColor, flashAmount); - old->ObjectFlags |= OF_YesReallyDelete; - if (screen == old) screen = NULL; - delete old; - } - else - { - flashColor = 0; - flashAmount = 0; - } - - SDLFB *fb = new SDLFB (width, height, fullscreen); - retry = 0; - - // If we could not create the framebuffer, try again with slightly - // different parameters in this order: - // 1. Try with the closest size - // 2. Try in the opposite screen mode with the original size - // 3. Try in the opposite screen mode with the closest size - // This is a somewhat confusing mass of recursion here. - - while (fb == NULL || !fb->IsValid ()) - { - if (fb != NULL) - { - delete fb; - } - - switch (retry) - { - case 0: - owidth = width; - oheight = height; - case 2: - // Try a different resolution. Hopefully that will work. - I_ClosestResolution (&width, &height, 8); - break; - - case 1: - // Try changing fullscreen mode. Maybe that will work. - width = owidth; - height = oheight; - fullscreen = !fullscreen; - break; - - default: - // I give up! - I_FatalError ("Could not create new screen (%d x %d)", owidth, oheight); - } - - ++retry; - fb = static_cast(CreateFrameBuffer (width, height, fullscreen, NULL)); - } - - fb->SetFlash (flashColor, flashAmount); - - return fb; -} - -void SDLVideo::SetWindowedScale (float scale) -{ -} - -// FrameBuffer implementation ----------------------------------------------- - -SDLFB::SDLFB (int width, int height, bool fullscreen) - : DFrameBuffer (width, height) -{ - int i; - - NeedPalUpdate = false; - NeedGammaUpdate = false; - UpdatePending = false; - NotPaletted = false; - FlashAmount = 0; - Screen = SDL_SetVideoMode (width, height, vid_displaybits, - (vid_asyncblit ? SDL_ASYNCBLIT : 0)|SDL_HWSURFACE|SDL_HWPALETTE|SDL_DOUBLEBUF|SDL_ANYFORMAT| - (fullscreen ? SDL_FULLSCREEN : 0)); - - if (Screen == NULL) - return; - - for (i = 0; i < 256; i++) - { - GammaTable[0][i] = GammaTable[1][i] = GammaTable[2][i] = i; - } - if (Screen->format->palette == NULL) - { - NotPaletted = true; - GPfx.SetFormat (Screen->format->BitsPerPixel, - Screen->format->Rmask, - Screen->format->Gmask, - Screen->format->Bmask); - } - memcpy (SourcePalette, GPalette.BaseColors, sizeof(PalEntry)*256); - UpdateColors (); - SetVSync (vid_vsync); -} - -SDLFB::~SDLFB () -{ -} - -bool SDLFB::IsValid () -{ - return DFrameBuffer::IsValid() && Screen != NULL; -} - -int SDLFB::GetPageCount () -{ - return 1; -} - -bool SDLFB::Lock (bool buffered) -{ - return DSimpleCanvas::Lock (); -} - -bool SDLFB::Relock () -{ - return DSimpleCanvas::Lock (); -} - -void SDLFB::Unlock () -{ - if (UpdatePending && LockCount == 1) - { - Update (); - } - else if (--LockCount <= 0) - { - Buffer = NULL; - LockCount = 0; - } -} - -void SDLFB::Update () -{ - if (LockCount != 1) - { - if (LockCount > 0) - { - UpdatePending = true; - --LockCount; - } - return; - } - - DrawRateStuff (); - -#ifndef __APPLE__ - if(vid_maxfps && !cl_capfps) - { - SEMAPHORE_WAIT(FPSLimitSemaphore) - } -#endif - - Buffer = NULL; - LockCount = 0; - UpdatePending = false; - - BlitCycles.Reset(); - SDLFlipCycles.Reset(); - BlitCycles.Clock(); - - if (SDL_LockSurface (Screen) == -1) - return; - - if (NotPaletted) - { - GPfx.Convert (MemBuffer, Pitch, - Screen->pixels, Screen->pitch, Width, Height, - FRACUNIT, FRACUNIT, 0, 0); - } - else - { - if (Screen->pitch == Pitch) - { - memcpy (Screen->pixels, MemBuffer, Width*Height); - } - else - { - for (int y = 0; y < Height; ++y) - { - memcpy ((BYTE *)Screen->pixels+y*Screen->pitch, MemBuffer+y*Pitch, Width); - } - } - } - - SDL_UnlockSurface (Screen); - - if (cursorSurface != NULL && GUICapture) - { - // SDL requires us to draw a surface to get true color cursors. - SDL_BlitSurface(cursorSurface, NULL, Screen, &cursorBlit); - } - - SDLFlipCycles.Clock(); - SDL_Flip (Screen); - SDLFlipCycles.Unclock(); - - BlitCycles.Unclock(); - - if (NeedGammaUpdate) - { - bool Windowed = false; - NeedGammaUpdate = false; - CalcGamma ((Windowed || rgamma == 0.f) ? Gamma : (Gamma * rgamma), GammaTable[0]); - CalcGamma ((Windowed || ggamma == 0.f) ? Gamma : (Gamma * ggamma), GammaTable[1]); - CalcGamma ((Windowed || bgamma == 0.f) ? Gamma : (Gamma * bgamma), GammaTable[2]); - NeedPalUpdate = true; - } - - if (NeedPalUpdate) - { - NeedPalUpdate = false; - UpdateColors (); - } -} - -void SDLFB::UpdateColors () -{ - if (NotPaletted) - { - PalEntry palette[256]; - - for (int i = 0; i < 256; ++i) - { - palette[i].r = GammaTable[0][SourcePalette[i].r]; - palette[i].g = GammaTable[1][SourcePalette[i].g]; - palette[i].b = GammaTable[2][SourcePalette[i].b]; - } - if (FlashAmount) - { - DoBlending (palette, palette, - 256, GammaTable[0][Flash.r], GammaTable[1][Flash.g], GammaTable[2][Flash.b], - FlashAmount); - } - GPfx.SetPalette (palette); - } - else - { - SDL_Color colors[256]; - - for (int i = 0; i < 256; ++i) - { - colors[i].r = GammaTable[0][SourcePalette[i].r]; - colors[i].g = GammaTable[1][SourcePalette[i].g]; - colors[i].b = GammaTable[2][SourcePalette[i].b]; - } - if (FlashAmount) - { - DoBlending ((PalEntry *)colors, (PalEntry *)colors, - 256, GammaTable[2][Flash.b], GammaTable[1][Flash.g], GammaTable[0][Flash.r], - FlashAmount); - } - SDL_SetPalette (Screen, SDL_LOGPAL|SDL_PHYSPAL, colors, 0, 256); - } -} - -PalEntry *SDLFB::GetPalette () -{ - return SourcePalette; -} - -void SDLFB::UpdatePalette () -{ - NeedPalUpdate = true; -} - -bool SDLFB::SetGamma (float gamma) -{ - Gamma = gamma; - NeedGammaUpdate = true; - return true; -} - -bool SDLFB::SetFlash (PalEntry rgb, int amount) -{ - Flash = rgb; - FlashAmount = amount; - NeedPalUpdate = true; - return true; -} - -void SDLFB::GetFlash (PalEntry &rgb, int &amount) -{ - rgb = Flash; - amount = FlashAmount; -} - -// Q: Should I gamma adjust the returned palette? -void SDLFB::GetFlashedPalette (PalEntry pal[256]) -{ - memcpy (pal, SourcePalette, 256*sizeof(PalEntry)); - if (FlashAmount) - { - DoBlending (pal, pal, 256, Flash.r, Flash.g, Flash.b, FlashAmount); - } -} - -bool SDLFB::IsFullscreen () -{ - return (Screen->flags & SDL_FULLSCREEN) != 0; -} - -void SDLFB::SetVSync (bool vsync) -{ -#ifdef __APPLE__ - if (CGLContextObj context = CGLGetCurrentContext()) - { - // Apply vsync for native backend only (where OpenGL context is set) - -#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050 - // Inconsistency between 10.4 and 10.5 SDKs: - // third argument of CGLSetParameter() is const long* on 10.4 and const GLint* on 10.5 - // So, GLint typedef'ed to long instead of int to workaround this issue - typedef long GLint; -#endif // prior to 10.5 - - const GLint value = vsync ? 1 : 0; - CGLSetParameter(context, kCGLCPSwapInterval, &value); - } -#endif // __APPLE__ -} - -ADD_STAT (blit) -{ - FString out; - out.Format ("blit=%04.1f ms flip=%04.1f ms", - BlitCycles.Time() * 1e-3, SDLFlipCycles.TimeMS()); - return out; -} + +// HEADER FILES ------------------------------------------------------------ + +#include "doomtype.h" + +#include "templates.h" +#include "i_system.h" +#include "i_video.h" +#include "v_video.h" +#include "v_pfx.h" +#include "stats.h" +#include "v_palette.h" +#include "sdlvideo.h" +#include "r_swrenderer.h" +#include "version.h" + +#include + +#ifdef __APPLE__ +#include +#endif // __APPLE__ + +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +class SDLFB : public DFrameBuffer +{ + DECLARE_CLASS(SDLFB, DFrameBuffer) +public: + SDLFB (int width, int height, bool fullscreen); + ~SDLFB (); + + bool Lock (bool buffer); + void Unlock (); + bool Relock (); + void ForceBuffering (bool force); + bool IsValid (); + void Update (); + PalEntry *GetPalette (); + void GetFlashedPalette (PalEntry pal[256]); + void UpdatePalette (); + bool SetGamma (float gamma); + bool SetFlash (PalEntry rgb, int amount); + void GetFlash (PalEntry &rgb, int &amount); + void SetFullscreen (bool fullscreen); + int GetPageCount (); + bool IsFullscreen (); + + friend class SDLVideo; + + virtual void SetVSync (bool vsync); + +private: + PalEntry SourcePalette[256]; + BYTE GammaTable[3][256]; + PalEntry Flash; + int FlashAmount; + float Gamma; + bool UpdatePending; + + SDL_Window *Screen; + SDL_Renderer *Renderer; + union + { + SDL_Texture *Texture; + SDL_Surface *Surface; + }; + SDL_Rect UpdateRect; + + bool UsingRenderer; + bool NeedPalUpdate; + bool NeedGammaUpdate; + bool NotPaletted; + + void UpdateColors (); + void ResetSDLRenderer (); + + SDLFB () {} +}; +IMPLEMENT_CLASS(SDLFB) + +struct MiniModeInfo +{ + WORD Width, Height; +}; + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +extern IVideo *Video; +extern bool GUICapture; + +EXTERN_CVAR (Float, Gamma) +EXTERN_CVAR (Int, vid_maxfps) +EXTERN_CVAR (Bool, cl_capfps) +EXTERN_CVAR (Bool, vid_vsync) + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +CVAR (Int, vid_adapter, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) + +CVAR (Int, vid_displaybits, 32, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) + +CVAR (Bool, vid_forcesurface, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) + +CUSTOM_CVAR (Float, rgamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (screen != NULL) + { + screen->SetGamma (Gamma); + } +} +CUSTOM_CVAR (Float, ggamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (screen != NULL) + { + screen->SetGamma (Gamma); + } +} +CUSTOM_CVAR (Float, bgamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (screen != NULL) + { + screen->SetGamma (Gamma); + } +} + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +// Dummy screen sizes to pass when windowed +static MiniModeInfo WinModes[] = +{ + { 320, 200 }, + { 320, 240 }, + { 400, 225 }, // 16:9 + { 400, 300 }, + { 480, 270 }, // 16:9 + { 480, 360 }, + { 512, 288 }, // 16:9 + { 512, 384 }, + { 640, 360 }, // 16:9 + { 640, 400 }, + { 640, 480 }, + { 720, 480 }, // 16:10 + { 720, 540 }, + { 800, 450 }, // 16:9 + { 800, 480 }, + { 800, 500 }, // 16:10 + { 800, 600 }, + { 848, 480 }, // 16:9 + { 960, 600 }, // 16:10 + { 960, 720 }, + { 1024, 576 }, // 16:9 + { 1024, 600 }, // 17:10 + { 1024, 640 }, // 16:10 + { 1024, 768 }, + { 1088, 612 }, // 16:9 + { 1152, 648 }, // 16:9 + { 1152, 720 }, // 16:10 + { 1152, 864 }, + { 1280, 720 }, // 16:9 + { 1280, 854 }, + { 1280, 800 }, // 16:10 + { 1280, 960 }, + { 1280, 1024 }, // 5:4 + { 1360, 768 }, // 16:9 + { 1366, 768 }, + { 1400, 787 }, // 16:9 + { 1400, 875 }, // 16:10 + { 1400, 1050 }, + { 1440, 900 }, + { 1440, 960 }, + { 1440, 1080 }, + { 1600, 900 }, // 16:9 + { 1600, 1000 }, // 16:10 + { 1600, 1200 }, + { 1920, 1080 }, + { 1920, 1200 }, + { 2048, 1536 }, + { 2560, 1440 }, + { 2560, 1600 }, + { 2560, 2048 }, + { 2880, 1800 }, + { 3200, 1800 }, + { 3840, 2160 }, + { 3840, 2400 }, + { 4096, 2160 }, + { 5120, 2880 } +}; + +static cycle_t BlitCycles; +static cycle_t SDLFlipCycles; + +// CODE -------------------------------------------------------------------- + +void ScaleWithAspect (int &w, int &h, int Width, int Height) +{ + int resRatio = CheckRatio (Width, Height); + int screenRatio; + CheckRatio (w, h, &screenRatio); + if (resRatio == screenRatio) + return; + + double yratio; + switch(resRatio) + { + case 0: yratio = 4./3.; break; + case 1: yratio = 16./9.; break; + case 2: yratio = 16./10.; break; + case 3: yratio = 17./10.; break; + case 4: yratio = 5./4.; break; + default: return; + } + double y = w/yratio; + if (y > h) + w = h*yratio; + else + h = y; +} + +SDLVideo::SDLVideo (int parm) +{ + IteratorBits = 0; +} + +SDLVideo::~SDLVideo () +{ +} + +void SDLVideo::StartModeIterator (int bits, bool fs) +{ + IteratorMode = 0; + IteratorBits = bits; +} + +bool SDLVideo::NextMode (int *width, int *height, bool *letterbox) +{ + if (IteratorBits != 8) + return false; + + if ((unsigned)IteratorMode < sizeof(WinModes)/sizeof(WinModes[0])) + { + *width = WinModes[IteratorMode].Width; + *height = WinModes[IteratorMode].Height; + ++IteratorMode; + return true; + } + return false; +} + +DFrameBuffer *SDLVideo::CreateFrameBuffer (int width, int height, bool fullscreen, DFrameBuffer *old) +{ + static int retry = 0; + static int owidth, oheight; + + PalEntry flashColor; + int flashAmount; + + if (old != NULL) + { // Reuse the old framebuffer if its attributes are the same + SDLFB *fb = static_cast (old); + if (fb->Width == width && + fb->Height == height) + { + bool fsnow = (SDL_GetWindowFlags (fb->Screen) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0; + + if (fsnow != fullscreen) + { + fb->SetFullscreen (fullscreen); + } + return old; + } + old->GetFlash (flashColor, flashAmount); + old->ObjectFlags |= OF_YesReallyDelete; + if (screen == old) screen = NULL; + delete old; + } + else + { + flashColor = 0; + flashAmount = 0; + } + + SDLFB *fb = new SDLFB (width, height, fullscreen); + + // If we could not create the framebuffer, try again with slightly + // different parameters in this order: + // 1. Try with the closest size + // 2. Try in the opposite screen mode with the original size + // 3. Try in the opposite screen mode with the closest size + // This is a somewhat confusing mass of recursion here. + + while (fb == NULL || !fb->IsValid ()) + { + if (fb != NULL) + { + delete fb; + } + + switch (retry) + { + case 0: + owidth = width; + oheight = height; + case 2: + // Try a different resolution. Hopefully that will work. + I_ClosestResolution (&width, &height, 8); + break; + + case 1: + // Try changing fullscreen mode. Maybe that will work. + width = owidth; + height = oheight; + fullscreen = !fullscreen; + break; + + default: + // I give up! + I_FatalError ("Could not create new screen (%d x %d)", owidth, oheight); + } + + ++retry; + fb = static_cast(CreateFrameBuffer (width, height, fullscreen, NULL)); + } + retry = 0; + + fb->SetFlash (flashColor, flashAmount); + + return fb; +} + +void SDLVideo::SetWindowedScale (float scale) +{ +} + +// FrameBuffer implementation ----------------------------------------------- + +SDLFB::SDLFB (int width, int height, bool fullscreen) + : DFrameBuffer (width, height) +{ + int i; + + NeedPalUpdate = false; + NeedGammaUpdate = false; + UpdatePending = false; + NotPaletted = false; + FlashAmount = 0; + + FString caption; + caption.Format(GAMESIG " %s (%s)", GetVersionString(), GetGitTime()); + + Screen = SDL_CreateWindow (caption, + SDL_WINDOWPOS_UNDEFINED_DISPLAY(vid_adapter), SDL_WINDOWPOS_UNDEFINED_DISPLAY(vid_adapter), + width, height, (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0)); + + if (Screen == NULL) + return; + + Renderer = NULL; + Texture = NULL; + ResetSDLRenderer (); + + for (i = 0; i < 256; i++) + { + GammaTable[0][i] = GammaTable[1][i] = GammaTable[2][i] = i; + } + + memcpy (SourcePalette, GPalette.BaseColors, sizeof(PalEntry)*256); + UpdateColors (); + +#ifdef __APPLE__ + SetVSync (vid_vsync); +#endif +} + + +SDLFB::~SDLFB () +{ + if(Screen) + { + if (Renderer) + { + if (Texture) + SDL_DestroyTexture (Texture); + SDL_DestroyRenderer (Renderer); + } + + SDL_DestroyWindow (Screen); + } +} + +bool SDLFB::IsValid () +{ + return DFrameBuffer::IsValid() && Screen != NULL; +} + +int SDLFB::GetPageCount () +{ + return 1; +} + +bool SDLFB::Lock (bool buffered) +{ + return DSimpleCanvas::Lock (); +} + +bool SDLFB::Relock () +{ + return DSimpleCanvas::Lock (); +} + +void SDLFB::Unlock () +{ + if (UpdatePending && LockCount == 1) + { + Update (); + } + else if (--LockCount <= 0) + { + Buffer = NULL; + LockCount = 0; + } +} + +void SDLFB::Update () +{ + if (LockCount != 1) + { + if (LockCount > 0) + { + UpdatePending = true; + --LockCount; + } + return; + } + + DrawRateStuff (); + +#ifndef __APPLE__ + if(vid_maxfps && !cl_capfps) + { + SEMAPHORE_WAIT(FPSLimitSemaphore) + } +#endif + + Buffer = NULL; + LockCount = 0; + UpdatePending = false; + + BlitCycles.Reset(); + SDLFlipCycles.Reset(); + BlitCycles.Clock(); + + void *pixels; + int pitch; + if (UsingRenderer) + { + if (SDL_LockTexture (Texture, NULL, &pixels, &pitch)) + return; + } + else + { + if (SDL_LockSurface (Surface)) + return; + + pixels = Surface->pixels; + pitch = Surface->pitch; + } + + if (NotPaletted) + { + GPfx.Convert (MemBuffer, Pitch, + pixels, pitch, Width, Height, + FRACUNIT, FRACUNIT, 0, 0); + } + else + { + if (pitch == Pitch) + { + memcpy (pixels, MemBuffer, Width*Height); + } + else + { + for (int y = 0; y < Height; ++y) + { + memcpy ((BYTE *)pixels+y*pitch, MemBuffer+y*Pitch, Width); + } + } + } + + if (UsingRenderer) + { + SDL_UnlockTexture (Texture); + + SDLFlipCycles.Clock(); + SDL_RenderCopy(Renderer, Texture, NULL, &UpdateRect); + SDL_RenderPresent(Renderer); + SDLFlipCycles.Unclock(); + } + else + { + SDL_UnlockSurface (Surface); + + SDLFlipCycles.Clock(); + SDL_UpdateWindowSurface (Screen); + SDLFlipCycles.Unclock(); + } + + BlitCycles.Unclock(); + + if (NeedGammaUpdate) + { + bool Windowed = false; + NeedGammaUpdate = false; + CalcGamma ((Windowed || rgamma == 0.f) ? Gamma : (Gamma * rgamma), GammaTable[0]); + CalcGamma ((Windowed || ggamma == 0.f) ? Gamma : (Gamma * ggamma), GammaTable[1]); + CalcGamma ((Windowed || bgamma == 0.f) ? Gamma : (Gamma * bgamma), GammaTable[2]); + NeedPalUpdate = true; + } + + if (NeedPalUpdate) + { + NeedPalUpdate = false; + UpdateColors (); + } +} + +void SDLFB::UpdateColors () +{ + if (NotPaletted) + { + PalEntry palette[256]; + + for (int i = 0; i < 256; ++i) + { + palette[i].r = GammaTable[0][SourcePalette[i].r]; + palette[i].g = GammaTable[1][SourcePalette[i].g]; + palette[i].b = GammaTable[2][SourcePalette[i].b]; + } + if (FlashAmount) + { + DoBlending (palette, palette, + 256, GammaTable[0][Flash.r], GammaTable[1][Flash.g], GammaTable[2][Flash.b], + FlashAmount); + } + GPfx.SetPalette (palette); + } + else + { + SDL_Color colors[256]; + + for (int i = 0; i < 256; ++i) + { + colors[i].r = GammaTable[0][SourcePalette[i].r]; + colors[i].g = GammaTable[1][SourcePalette[i].g]; + colors[i].b = GammaTable[2][SourcePalette[i].b]; + } + if (FlashAmount) + { + DoBlending ((PalEntry *)colors, (PalEntry *)colors, + 256, GammaTable[2][Flash.b], GammaTable[1][Flash.g], GammaTable[0][Flash.r], + FlashAmount); + } + SDL_SetPaletteColors (Surface->format->palette, colors, 0, 256); + } +} + +PalEntry *SDLFB::GetPalette () +{ + return SourcePalette; +} + +void SDLFB::UpdatePalette () +{ + NeedPalUpdate = true; +} + +bool SDLFB::SetGamma (float gamma) +{ + Gamma = gamma; + NeedGammaUpdate = true; + return true; +} + +bool SDLFB::SetFlash (PalEntry rgb, int amount) +{ + Flash = rgb; + FlashAmount = amount; + NeedPalUpdate = true; + return true; +} + +void SDLFB::GetFlash (PalEntry &rgb, int &amount) +{ + rgb = Flash; + amount = FlashAmount; +} + +// Q: Should I gamma adjust the returned palette? +void SDLFB::GetFlashedPalette (PalEntry pal[256]) +{ + memcpy (pal, SourcePalette, 256*sizeof(PalEntry)); + if (FlashAmount) + { + DoBlending (pal, pal, 256, Flash.r, Flash.g, Flash.b, FlashAmount); + } +} + +void SDLFB::SetFullscreen (bool fullscreen) +{ + SDL_SetWindowFullscreen (Screen, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); + if (!fullscreen) + { + // Restore proper window size + SDL_SetWindowSize (Screen, Width, Height); + } + + ResetSDLRenderer (); +} + +bool SDLFB::IsFullscreen () +{ + return (SDL_GetWindowFlags (Screen) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0; +} + +void SDLFB::ResetSDLRenderer () +{ + if (Renderer) + { + if (Texture) + SDL_DestroyTexture (Texture); + SDL_DestroyRenderer (Renderer); + } + + UsingRenderer = !vid_forcesurface; + if (UsingRenderer) + { + Renderer = SDL_CreateRenderer (Screen, -1,SDL_RENDERER_ACCELERATED|SDL_RENDERER_TARGETTEXTURE| + (vid_vsync ? SDL_RENDERER_PRESENTVSYNC : 0)); + if (!Renderer) + return; + + Uint32 fmt; + switch(vid_displaybits) + { + default: fmt = SDL_PIXELFORMAT_ARGB8888; break; + case 30: fmt = SDL_PIXELFORMAT_ARGB2101010; break; + case 24: fmt = SDL_PIXELFORMAT_RGB888; break; + case 16: fmt = SDL_PIXELFORMAT_RGB565; break; + case 15: fmt = SDL_PIXELFORMAT_ARGB1555; break; + } + Texture = SDL_CreateTexture (Renderer, fmt, SDL_TEXTUREACCESS_STREAMING, Width, Height); + + { + NotPaletted = true; + + Uint32 format; + SDL_QueryTexture(Texture, &format, NULL, NULL, NULL); + + Uint32 Rmask, Gmask, Bmask, Amask; + int bpp; + SDL_PixelFormatEnumToMasks(format, &bpp, &Rmask, &Gmask, &Bmask, &Amask); + GPfx.SetFormat (bpp, Rmask, Gmask, Bmask); + } + } + else + { + Surface = SDL_GetWindowSurface (Screen); + + if (Surface->format->palette == NULL) + { + NotPaletted = true; + GPfx.SetFormat (Surface->format->BitsPerPixel, Surface->format->Rmask, Surface->format->Gmask, Surface->format->Bmask); + } + else + NotPaletted = false; + } + + // Calculate update rectangle + if (IsFullscreen ()) + { + int w, h; + SDL_GetWindowSize (Screen, &w, &h); + UpdateRect.w = w; + UpdateRect.h = h; + ScaleWithAspect (UpdateRect.w, UpdateRect.h, Width, Height); + UpdateRect.x = (w - UpdateRect.w)/2; + UpdateRect.y = (h - UpdateRect.h)/2; + } + else + { + // In windowed mode we just update the whole window. + UpdateRect.x = 0; + UpdateRect.y = 0; + UpdateRect.w = Width; + UpdateRect.h = Height; + } +} + +void SDLFB::SetVSync (bool vsync) +{ +#ifdef __APPLE__ + if (CGLContextObj context = CGLGetCurrentContext()) + { + // Apply vsync for native backend only (where OpenGL context is set) + +#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050 + // Inconsistency between 10.4 and 10.5 SDKs: + // third argument of CGLSetParameter() is const long* on 10.4 and const GLint* on 10.5 + // So, GLint typedef'ed to long instead of int to workaround this issue + typedef long GLint; +#endif // prior to 10.5 + + const GLint value = vsync ? 1 : 0; + CGLSetParameter(context, kCGLCPSwapInterval, &value); + } +#else + ResetSDLRenderer (); +#endif // __APPLE__ +} + +ADD_STAT (blit) +{ + FString out; + out.Format ("blit=%04.1f ms flip=%04.1f ms", + BlitCycles.TimeMS(), SDLFlipCycles.TimeMS()); + return out; +} diff --git a/src/sdl/sdlvideo.h b/src/posix/sdl/sdlvideo.h similarity index 92% rename from src/sdl/sdlvideo.h rename to src/posix/sdl/sdlvideo.h index 3cd38a140..072167b5a 100644 --- a/src/sdl/sdlvideo.h +++ b/src/posix/sdl/sdlvideo.h @@ -1,22 +1,21 @@ -#include "hardware.h" -#include "v_video.h" - -class SDLVideo : public IVideo -{ - public: - SDLVideo (int parm); - ~SDLVideo (); - - EDisplayType GetDisplayType () { return DISPLAY_Both; } - void SetWindowedScale (float scale); - - DFrameBuffer *CreateFrameBuffer (int width, int height, bool fs, DFrameBuffer *old); - - void StartModeIterator (int bits, bool fs); - bool NextMode (int *width, int *height, bool *letterbox); - -private: - int IteratorMode; - int IteratorBits; - bool IteratorFS; -}; +#include "hardware.h" +#include "v_video.h" + +class SDLVideo : public IVideo +{ + public: + SDLVideo (int parm); + ~SDLVideo (); + + EDisplayType GetDisplayType () { return DISPLAY_Both; } + void SetWindowedScale (float scale); + + DFrameBuffer *CreateFrameBuffer (int width, int height, bool fs, DFrameBuffer *old); + + void StartModeIterator (int bits, bool fs); + bool NextMode (int *width, int *height, bool *letterbox); + +private: + int IteratorMode; + int IteratorBits; +}; diff --git a/src/sdl/st_start.cpp b/src/posix/st_start.cpp similarity index 96% rename from src/sdl/st_start.cpp rename to src/posix/st_start.cpp index 33a5abe0b..060548b53 100644 --- a/src/sdl/st_start.cpp +++ b/src/posix/st_start.cpp @@ -1,354 +1,354 @@ -/* -** st_start.cpp -** Handles the startup screen. -** -**--------------------------------------------------------------------------- -** Copyright 2006-2007 Randy Heit -** 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. -**--------------------------------------------------------------------------- -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include -#include -#include -#include - -#include "st_start.h" -#include "doomdef.h" -#include "i_system.h" -#include "c_cvars.h" - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -class FTTYStartupScreen : public FStartupScreen -{ - public: - FTTYStartupScreen(int max_progress); - ~FTTYStartupScreen(); - - void Progress(); - void NetInit(const char *message, int num_players); - void NetProgress(int count); - void NetMessage(const char *format, ...); // cover for printf - void NetDone(); - bool NetLoop(bool (*timer_callback)(void *), void *userdata); - protected: - bool DidNetInit; - int NetMaxPos, NetCurPos; - const char *TheNetMessage; - termios OldTermIOS; -}; - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -void I_ShutdownJoysticks(); - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -static void DeleteStartupScreen(); - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -FStartupScreen *StartScreen; - -CUSTOM_CVAR(Int, showendoom, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - if (self < 0) self = 0; - else if (self > 2) self=2; -} - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -static const char SpinnyProgressChars[4] = { '|', '/', '-', '\\' }; - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// FStartupScreen :: CreateInstance -// -// Initializes the startup screen for the detected game. -// Sets the size of the progress bar and displays the startup screen. -// -//========================================================================== - -FStartupScreen *FStartupScreen::CreateInstance(int max_progress) -{ - atterm(DeleteStartupScreen); - return new FTTYStartupScreen(max_progress); -} - -//=========================================================================== -// -// DeleteStartupScreen -// -// Makes sure the startup screen has been deleted before quitting. -// -//=========================================================================== - -void DeleteStartupScreen() -{ - if (StartScreen != NULL) - { - delete StartScreen; - StartScreen = NULL; - } -} - -//=========================================================================== -// -// FTTYStartupScreen Constructor -// -// Sets the size of the progress bar and displays the startup screen. -// -//=========================================================================== - -FTTYStartupScreen::FTTYStartupScreen(int max_progress) - : FStartupScreen(max_progress) -{ - DidNetInit = false; - NetMaxPos = 0; - NetCurPos = 0; - TheNetMessage = NULL; -} - -//=========================================================================== -// -// FTTYStartupScreen Destructor -// -// Called just before entering graphics mode to deconstruct the startup -// screen. -// -//=========================================================================== - -FTTYStartupScreen::~FTTYStartupScreen() -{ - NetDone(); // Just in case it wasn't called yet and needs to be. -} - -//=========================================================================== -// -// FTTYStartupScreen :: Progress -// -// If there was a progress bar, this would move it. But the basic TTY -// startup screen doesn't have one, so this function does nothing. -// -//=========================================================================== - -void FTTYStartupScreen::Progress() -{ -} - -//=========================================================================== -// -// FTTYStartupScreen :: NetInit -// -// Sets stdin for unbuffered I/O, displays the given message, and shows -// a progress meter. -// -//=========================================================================== - -void FTTYStartupScreen::NetInit(const char *message, int numplayers) -{ - if (!DidNetInit) - { - termios rawtermios; - - fprintf (stderr, "Press 'Q' to abort network game synchronization."); - // Set stdin to raw mode so we can get keypresses in ST_CheckNetAbort() - // immediately without waiting for an EOL. - tcgetattr (STDIN_FILENO, &OldTermIOS); - rawtermios = OldTermIOS; - rawtermios.c_lflag &= ~(ICANON | ECHO); - tcsetattr (STDIN_FILENO, TCSANOW, &rawtermios); - DidNetInit = true; - } - if (numplayers == 1) - { - // Status message without any real progress info. - fprintf (stderr, "\n%s.", message); - } - else - { - fprintf (stderr, "\n%s: ", message); - } - fflush (stderr); - TheNetMessage = message; - NetMaxPos = numplayers; - NetCurPos = 0; - NetProgress(1); // You always know about yourself -} - -//=========================================================================== -// -// FTTYStartupScreen :: NetDone -// -// Restores the old stdin tty settings. -// -//=========================================================================== - -void FTTYStartupScreen::NetDone() -{ - // Restore stdin settings - if (DidNetInit) - { - tcsetattr (STDIN_FILENO, TCSANOW, &OldTermIOS); - printf ("\n"); - DidNetInit = false; - } -} - -//=========================================================================== -// -// FTTYStartupScreen :: NetMessage -// -// Call this between NetInit() and NetDone() instead of Printf() to -// display messages, because the progress meter is mixed in the same output -// stream as normal messages. -// -//=========================================================================== - -void FTTYStartupScreen::NetMessage(const char *format, ...) -{ - FString str; - va_list argptr; - - va_start (argptr, format); - str.VFormat (format, argptr); - va_end (argptr); - fprintf (stderr, "\r%-40s\n", str.GetChars()); -} - -//=========================================================================== -// -// FTTYStartupScreen :: NetProgress -// -// Sets the network progress meter. If count is 0, it gets bumped by 1. -// Otherwise, it is set to count. -// -//=========================================================================== - -void FTTYStartupScreen::NetProgress(int count) -{ - int i; - - if (count == 0) - { - NetCurPos++; - } - else if (count > 0) - { - NetCurPos = count; - } - if (NetMaxPos == 0) - { - // Spinny-type progress meter, because we're a guest waiting for the host. - fprintf (stderr, "\r%s: %c", TheNetMessage, SpinnyProgressChars[NetCurPos & 3]); - fflush (stderr); - } - else if (NetMaxPos > 1) - { - // Dotty-type progress meter. - fprintf (stderr, "\r%s: ", TheNetMessage); - for (i = 0; i < NetCurPos; ++i) - { - fputc ('.', stderr); - } - fprintf (stderr, "%*c[%2d/%2d]", NetMaxPos + 1 - NetCurPos, ' ', NetCurPos, NetMaxPos); - fflush (stderr); - } -} - -//=========================================================================== -// -// FTTYStartupScreen :: NetLoop -// -// The timer_callback function is called at least two times per second -// and passed the userdata value. It should return true to stop the loop and -// return control to the caller or false to continue the loop. -// -// ST_NetLoop will return true if the loop was halted by the callback and -// false if the loop was halted because the user wants to abort the -// network synchronization. -// -//=========================================================================== - -bool FTTYStartupScreen::NetLoop(bool (*timer_callback)(void *), void *userdata) -{ - fd_set rfds; - struct timeval tv; - int retval; - char k; - - for (;;) - { - // Don't flood the network with packets on startup. - tv.tv_sec = 0; - tv.tv_usec = 500000; - - FD_ZERO (&rfds); - FD_SET (STDIN_FILENO, &rfds); - - retval = select (1, &rfds, NULL, NULL, &tv); - - if (retval == -1) - { - // Error - } - else if (retval == 0) - { - if (timer_callback (userdata)) - { - fputc ('\n', stderr); - return true; - } - } - else if (read (STDIN_FILENO, &k, 1) == 1) - { - // Check input on stdin - if (k == 'q' || k == 'Q') - { - fprintf (stderr, "\nNetwork game synchronization aborted."); - return false; - } - } - } -} - -void ST_Endoom() -{ - I_ShutdownJoysticks(); - exit(0); -} +/* +** st_start.cpp +** Handles the startup screen. +** +**--------------------------------------------------------------------------- +** Copyright 2006-2007 Randy Heit +** 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. +**--------------------------------------------------------------------------- +** +*/ + +// HEADER FILES ------------------------------------------------------------ + +#include +#include +#include +#include + +#include "st_start.h" +#include "doomdef.h" +#include "i_system.h" +#include "c_cvars.h" + +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +class FTTYStartupScreen : public FStartupScreen +{ + public: + FTTYStartupScreen(int max_progress); + ~FTTYStartupScreen(); + + void Progress(); + void NetInit(const char *message, int num_players); + void NetProgress(int count); + void NetMessage(const char *format, ...); // cover for printf + void NetDone(); + bool NetLoop(bool (*timer_callback)(void *), void *userdata); + protected: + bool DidNetInit; + int NetMaxPos, NetCurPos; + const char *TheNetMessage; + termios OldTermIOS; +}; + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +void I_ShutdownJoysticks(); + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static void DeleteStartupScreen(); + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +FStartupScreen *StartScreen; + +CUSTOM_CVAR(Int, showendoom, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if (self < 0) self = 0; + else if (self > 2) self=2; +} + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static const char SpinnyProgressChars[4] = { '|', '/', '-', '\\' }; + +// CODE -------------------------------------------------------------------- + +//========================================================================== +// +// FStartupScreen :: CreateInstance +// +// Initializes the startup screen for the detected game. +// Sets the size of the progress bar and displays the startup screen. +// +//========================================================================== + +FStartupScreen *FStartupScreen::CreateInstance(int max_progress) +{ + atterm(DeleteStartupScreen); + return new FTTYStartupScreen(max_progress); +} + +//=========================================================================== +// +// DeleteStartupScreen +// +// Makes sure the startup screen has been deleted before quitting. +// +//=========================================================================== + +void DeleteStartupScreen() +{ + if (StartScreen != NULL) + { + delete StartScreen; + StartScreen = NULL; + } +} + +//=========================================================================== +// +// FTTYStartupScreen Constructor +// +// Sets the size of the progress bar and displays the startup screen. +// +//=========================================================================== + +FTTYStartupScreen::FTTYStartupScreen(int max_progress) + : FStartupScreen(max_progress) +{ + DidNetInit = false; + NetMaxPos = 0; + NetCurPos = 0; + TheNetMessage = NULL; +} + +//=========================================================================== +// +// FTTYStartupScreen Destructor +// +// Called just before entering graphics mode to deconstruct the startup +// screen. +// +//=========================================================================== + +FTTYStartupScreen::~FTTYStartupScreen() +{ + NetDone(); // Just in case it wasn't called yet and needs to be. +} + +//=========================================================================== +// +// FTTYStartupScreen :: Progress +// +// If there was a progress bar, this would move it. But the basic TTY +// startup screen doesn't have one, so this function does nothing. +// +//=========================================================================== + +void FTTYStartupScreen::Progress() +{ +} + +//=========================================================================== +// +// FTTYStartupScreen :: NetInit +// +// Sets stdin for unbuffered I/O, displays the given message, and shows +// a progress meter. +// +//=========================================================================== + +void FTTYStartupScreen::NetInit(const char *message, int numplayers) +{ + if (!DidNetInit) + { + termios rawtermios; + + fprintf (stderr, "Press 'Q' to abort network game synchronization."); + // Set stdin to raw mode so we can get keypresses in ST_CheckNetAbort() + // immediately without waiting for an EOL. + tcgetattr (STDIN_FILENO, &OldTermIOS); + rawtermios = OldTermIOS; + rawtermios.c_lflag &= ~(ICANON | ECHO); + tcsetattr (STDIN_FILENO, TCSANOW, &rawtermios); + DidNetInit = true; + } + if (numplayers == 1) + { + // Status message without any real progress info. + fprintf (stderr, "\n%s.", message); + } + else + { + fprintf (stderr, "\n%s: ", message); + } + fflush (stderr); + TheNetMessage = message; + NetMaxPos = numplayers; + NetCurPos = 0; + NetProgress(1); // You always know about yourself +} + +//=========================================================================== +// +// FTTYStartupScreen :: NetDone +// +// Restores the old stdin tty settings. +// +//=========================================================================== + +void FTTYStartupScreen::NetDone() +{ + // Restore stdin settings + if (DidNetInit) + { + tcsetattr (STDIN_FILENO, TCSANOW, &OldTermIOS); + printf ("\n"); + DidNetInit = false; + } +} + +//=========================================================================== +// +// FTTYStartupScreen :: NetMessage +// +// Call this between NetInit() and NetDone() instead of Printf() to +// display messages, because the progress meter is mixed in the same output +// stream as normal messages. +// +//=========================================================================== + +void FTTYStartupScreen::NetMessage(const char *format, ...) +{ + FString str; + va_list argptr; + + va_start (argptr, format); + str.VFormat (format, argptr); + va_end (argptr); + fprintf (stderr, "\r%-40s\n", str.GetChars()); +} + +//=========================================================================== +// +// FTTYStartupScreen :: NetProgress +// +// Sets the network progress meter. If count is 0, it gets bumped by 1. +// Otherwise, it is set to count. +// +//=========================================================================== + +void FTTYStartupScreen::NetProgress(int count) +{ + int i; + + if (count == 0) + { + NetCurPos++; + } + else if (count > 0) + { + NetCurPos = count; + } + if (NetMaxPos == 0) + { + // Spinny-type progress meter, because we're a guest waiting for the host. + fprintf (stderr, "\r%s: %c", TheNetMessage, SpinnyProgressChars[NetCurPos & 3]); + fflush (stderr); + } + else if (NetMaxPos > 1) + { + // Dotty-type progress meter. + fprintf (stderr, "\r%s: ", TheNetMessage); + for (i = 0; i < NetCurPos; ++i) + { + fputc ('.', stderr); + } + fprintf (stderr, "%*c[%2d/%2d]", NetMaxPos + 1 - NetCurPos, ' ', NetCurPos, NetMaxPos); + fflush (stderr); + } +} + +//=========================================================================== +// +// FTTYStartupScreen :: NetLoop +// +// The timer_callback function is called at least two times per second +// and passed the userdata value. It should return true to stop the loop and +// return control to the caller or false to continue the loop. +// +// ST_NetLoop will return true if the loop was halted by the callback and +// false if the loop was halted because the user wants to abort the +// network synchronization. +// +//=========================================================================== + +bool FTTYStartupScreen::NetLoop(bool (*timer_callback)(void *), void *userdata) +{ + fd_set rfds; + struct timeval tv; + int retval; + char k; + + for (;;) + { + // Don't flood the network with packets on startup. + tv.tv_sec = 0; + tv.tv_usec = 500000; + + FD_ZERO (&rfds); + FD_SET (STDIN_FILENO, &rfds); + + retval = select (1, &rfds, NULL, NULL, &tv); + + if (retval == -1) + { + // Error + } + else if (retval == 0) + { + if (timer_callback (userdata)) + { + fputc ('\n', stderr); + return true; + } + } + else if (read (STDIN_FILENO, &k, 1) == 1) + { + // Check input on stdin + if (k == 'q' || k == 'Q') + { + fprintf (stderr, "\nNetwork game synchronization aborted."); + return false; + } + } + } +} + +void ST_Endoom() +{ + I_ShutdownJoysticks(); + exit(0); +} diff --git a/src/resourcefiles/resourcefile.cpp b/src/resourcefiles/resourcefile.cpp index 8a4f07fd7..15a4337b1 100644 --- a/src/resourcefiles/resourcefile.cpp +++ b/src/resourcefiles/resourcefile.cpp @@ -150,11 +150,28 @@ void FResourceLump::LumpNameSetup(const char *iname) // //========================================================================== +static bool IsWadInFolder(const FResourceFile* const archive, const char* const resPath) +{ + // Checks a special case when was put in + // directory inside + + if (NULL == archive) + { + return false; + } + + const FString dirName = ExtractFileBase(archive->Filename); + const FString fileName = ExtractFileBase(resPath, true); + const FString filePath = dirName + '/' + fileName; + + return 0 == filePath.CompareNoCase(resPath); +} + void FResourceLump::CheckEmbedded() { // Checks for embedded archives const char *c = strstr(FullName, ".wad"); - if (c && strlen(c) == 4 && !strchr(FullName, '/')) + if (c && strlen(c) == 4 && (!strchr(FullName, '/') || IsWadInFolder(Owner, FullName))) { // Mark all embedded WADs Flags |= LUMPF_EMBEDDED; diff --git a/src/sc_man_scanner.re b/src/sc_man_scanner.re index 1ebd1e65a..9537f51b1 100644 --- a/src/sc_man_scanner.re +++ b/src/sc_man_scanner.re @@ -185,7 +185,7 @@ std2: 'random' { RET(TK_Random); } 'random2' { RET(TK_Random2); } 'frandom' { RET(TK_FRandom); } - 'pick' { RET(TK_Pick); } + 'randompick' { RET(TK_RandomPick); } L (L|D)* { RET(TK_Identifier); } diff --git a/src/sc_man_tokens.h b/src/sc_man_tokens.h index ab6feba89..c7f9ec020 100644 --- a/src/sc_man_tokens.h +++ b/src/sc_man_tokens.h @@ -126,6 +126,7 @@ xx(TK_Array, "'array'") xx(TK_In, "'in'") xx(TK_SizeOf, "'sizeof'") xx(TK_AlignOf, "'alignof'") +xx(TK_RandomPick, "'randompick'") xx(TK_States, "'states'") xx(TK_Loop, "'loop'") xx(TK_Fail, "'fail'") diff --git a/src/sdl/SDLMain.m b/src/sdl/SDLMain.m deleted file mode 100644 index 78c4e3d2b..000000000 --- a/src/sdl/SDLMain.m +++ /dev/null @@ -1,387 +0,0 @@ -/* SDLMain.m - main entry point for our Cocoa-ized SDL app - Initial Version: Darrell Walisser - Non-NIB-Code & other changes: Max Horn - - Feel free to customize this file to suit your needs -*/ - -#import "SDL.h" -#import -#import /* for MAXPATHLEN */ -#import - -@interface SDLMain : NSObject -@end - -/* For some reaon, Apple removed setAppleMenu from the headers in 10.4, - but the method still is there and works. To avoid warnings, we declare - it ourselves here. */ -@interface NSApplication(SDL_Missing_Methods) -- (void)setAppleMenu:(NSMenu *)menu; -@end - -/* Use this flag to determine whether we use SDLMain.nib or not */ -#define SDL_USE_NIB_FILE 0 - -/* Use this flag to determine whether we use CPS (docking) or not */ -#define SDL_USE_CPS 1 -#ifdef SDL_USE_CPS -/* Portions of CPS.h */ -typedef struct CPSProcessSerNum -{ - UInt32 lo; - UInt32 hi; -} CPSProcessSerNum; - -extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); -extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); -extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); - -#endif /* SDL_USE_CPS */ - -static int gArgc; -static char **gArgv; -static BOOL gFinderLaunch; -static BOOL gCalledAppMainline = FALSE; - -static NSString *getApplicationName(void) -{ - NSDictionary *dict; - NSString *appName = 0; - - /* Determine the application name */ - dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()); - if (dict) - appName = [dict objectForKey: @"CFBundleName"]; - - if (![appName length]) - appName = [[NSProcessInfo processInfo] processName]; - - return appName; -} - -#if SDL_USE_NIB_FILE -/* A helper category for NSString */ -@interface NSString (ReplaceSubString) -- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString; -@end -#endif - -@interface SDLApplication : NSApplication -@end - -@implementation SDLApplication -/* Invoked from the Quit menu item */ -- (void)terminate:(id)sender -{ - /* Post a SDL_QUIT event */ - SDL_Event event; - event.type = SDL_QUIT; - SDL_PushEvent(&event); -} -@end - -/* The main class of the application, the application's delegate */ -@implementation SDLMain - -/* Set the working directory to the .app's parent directory */ -- (void) setupWorkingDirectory:(BOOL)shouldChdir -{ - if (shouldChdir) - { - char parentdir[MAXPATHLEN]; - CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); - CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url); - if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, MAXPATHLEN)) { - assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */ - } - CFRelease(url); - CFRelease(url2); - } - -} - -#if SDL_USE_NIB_FILE - -/* Fix menu to contain the real app name instead of "SDL App" */ -- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName -{ - NSRange aRange; - NSEnumerator *enumerator; - NSMenuItem *menuItem; - - aRange = [[aMenu title] rangeOfString:@"SDL App"]; - if (aRange.length != 0) - [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]]; - - enumerator = [[aMenu itemArray] objectEnumerator]; - while ((menuItem = [enumerator nextObject])) - { - aRange = [[menuItem title] rangeOfString:@"SDL App"]; - if (aRange.length != 0) - [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]]; - if ([menuItem hasSubmenu]) - [self fixMenu:[menuItem submenu] withAppName:appName]; - } - [ aMenu sizeToFit ]; -} - -#else - -static void setApplicationMenu(void) -{ - /* warning: this code is very odd */ - NSMenu *appleMenu; - NSMenuItem *menuItem; - NSString *title; - NSString *appName; - - appName = getApplicationName(); - appleMenu = [[NSMenu alloc] initWithTitle:@""]; - - /* Add menu items */ - title = [@"About " stringByAppendingString:appName]; - [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; - - [appleMenu addItem:[NSMenuItem separatorItem]]; - - title = [@"Hide " stringByAppendingString:appName]; - [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; - - menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; - [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; - - [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; - - [appleMenu addItem:[NSMenuItem separatorItem]]; - - title = [@"Quit " stringByAppendingString:appName]; - [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; - - - /* Put menu into the menubar */ - menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; - [menuItem setSubmenu:appleMenu]; - [[NSApp mainMenu] addItem:menuItem]; - - /* Tell the application object that this is now the application menu */ - [NSApp setAppleMenu:appleMenu]; - - /* Finally give up our references to the objects */ - [appleMenu release]; - [menuItem release]; -} - -/* Create a window menu */ -static void setupWindowMenu(void) -{ - NSMenu *windowMenu; - NSMenuItem *windowMenuItem; - NSMenuItem *menuItem; - - windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; - - /* "Minimize" item */ - menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; - [windowMenu addItem:menuItem]; - [menuItem release]; - - /* Put menu into the menubar */ - windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; - [windowMenuItem setSubmenu:windowMenu]; - [[NSApp mainMenu] addItem:windowMenuItem]; - - /* Tell the application object that this is now the window menu */ - [NSApp setWindowsMenu:windowMenu]; - - /* Finally give up our references to the objects */ - [windowMenu release]; - [windowMenuItem release]; -} - -/* Replacement for NSApplicationMain */ -static void CustomApplicationMain (int argc, char **argv) -{ - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - SDLMain *sdlMain; - - /* Ensure the application object is initialised */ - [SDLApplication sharedApplication]; - -#ifdef SDL_USE_CPS - { - CPSProcessSerNum PSN; - /* Tell the dock about us */ - if (!CPSGetCurrentProcess(&PSN)) - if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) - if (!CPSSetFrontProcess(&PSN)) - [SDLApplication sharedApplication]; - } -#endif /* SDL_USE_CPS */ - - /* Set up the menubar */ - [NSApp setMainMenu:[[NSMenu alloc] init]]; - setApplicationMenu(); - setupWindowMenu(); - - /* Create SDLMain and make it the app delegate */ - sdlMain = [[SDLMain alloc] init]; - [NSApp setDelegate:sdlMain]; - - /* Start the main event loop */ - [NSApp run]; - - [sdlMain release]; - [pool release]; -} - -#endif - - -/* - * Catch document open requests...this lets us notice files when the app - * was launched by double-clicking a document, or when a document was - * dragged/dropped on the app's icon. You need to have a - * CFBundleDocumentsType section in your Info.plist to get this message, - * apparently. - * - * Files are added to gArgv, so to the app, they'll look like command line - * arguments. Previously, apps launched from the finder had nothing but - * an argv[0]. - * - * This message may be received multiple times to open several docs on launch. - * - * This message is ignored once the app's mainline has been called. - */ -- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename -{ - const char *temparg; - size_t arglen; - char *arg; - char **newargv; - - if (!gFinderLaunch) /* MacOS is passing command line args. */ - return FALSE; - - if (gCalledAppMainline) /* app has started, ignore this document. */ - return FALSE; - - temparg = [filename UTF8String]; - arglen = SDL_strlen(temparg) + 1; - arg = (char *) SDL_malloc(arglen); - if (arg == NULL) - return FALSE; - - newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2)); - if (newargv == NULL) - { - SDL_free(arg); - return FALSE; - } - gArgv = newargv; - - SDL_strlcpy(arg, temparg, arglen); - gArgv[gArgc++] = arg; - gArgv[gArgc] = NULL; - return TRUE; -} - - -/* Called when the internal event loop has just started running */ -- (void) applicationDidFinishLaunching: (NSNotification *) note -{ - int status; - - /* Set the working directory to the .app's parent directory */ - [self setupWorkingDirectory:gFinderLaunch]; - -#if SDL_USE_NIB_FILE - /* Set the main menu to contain the real app name instead of "SDL App" */ - [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()]; -#endif - - /* Hand off to main application code */ - gCalledAppMainline = TRUE; - status = SDL_main (gArgc, gArgv); - - /* We're done, thank you for playing */ - exit(status); -} -@end - - -@implementation NSString (ReplaceSubString) - -- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString -{ - unsigned int bufferSize; - unsigned int selfLen = [self length]; - unsigned int aStringLen = [aString length]; - unichar *buffer; - NSRange localRange; - NSString *result; - - bufferSize = selfLen + aStringLen - aRange.length; - buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar)); - - /* Get first part into buffer */ - localRange.location = 0; - localRange.length = aRange.location; - [self getCharacters:buffer range:localRange]; - - /* Get middle part into buffer */ - localRange.location = 0; - localRange.length = aStringLen; - [aString getCharacters:(buffer+aRange.location) range:localRange]; - - /* Get last part into buffer */ - localRange.location = aRange.location + aRange.length; - localRange.length = selfLen - localRange.location; - [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange]; - - /* Build output string */ - result = [NSString stringWithCharacters:buffer length:bufferSize]; - - NSDeallocateMemoryPages(buffer, bufferSize); - - return result; -} - -@end - - - -#ifdef main -# undef main -#endif - - -/* Main entry point to executable - should *not* be SDL_main! */ -int main (int argc, char **argv) -{ - /* Copy the arguments into a global variable */ - /* This is passed if we are launched by double-clicking */ - if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { - gArgv = (char **) SDL_malloc(sizeof (char *) * 2); - gArgv[0] = argv[0]; - gArgv[1] = NULL; - gArgc = 1; - gFinderLaunch = YES; - } else { - int i; - gArgc = argc; - gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1)); - for (i = 0; i <= argc; i++) - gArgv[i] = argv[i]; - gFinderLaunch = NO; - } - -#if SDL_USE_NIB_FILE - [SDLApplication poseAsClass:[NSApplication class]]; - NSApplicationMain (argc, argv); -#else - CustomApplicationMain (argc, argv); -#endif - return 0; -} - diff --git a/src/sdl/i_gui.cpp b/src/sdl/i_gui.cpp deleted file mode 100644 index b40fb7517..000000000 --- a/src/sdl/i_gui.cpp +++ /dev/null @@ -1,131 +0,0 @@ - -// Moved from sdl/i_system.cpp - -#include - -#include - -#include "bitmap.h" -#include "v_palette.h" -#include "textures.h" - -extern SDL_Surface *cursorSurface; -extern SDL_Rect cursorBlit; - -#ifdef USE_XCURSOR -// Xlib has its own GC, so don't let it interfere. -#define GC XGC -#include -#undef GC - -bool UseXCursor; -SDL_Cursor *X11Cursor; -SDL_Cursor *FirstCursor; - -// Hack! Hack! SDL does not provide a clean way to get the XDisplay. -// On the other hand, there are no more planned updates for SDL 1.2, -// so we should be fine making assumptions. -struct SDL_PrivateVideoData -{ - int local_X11; - Display *X11_Display; -}; - -struct SDL_VideoDevice -{ - const char *name; - int (*functions[9])(); - SDL_VideoInfo info; - SDL_PixelFormat *displayformatalphapixel; - int (*morefuncs[9])(); - Uint16 *gamma; - int (*somefuncs[9])(); - unsigned int texture; // Only here if SDL was compiled with OpenGL support. Ack! - int is_32bit; - int (*itsafuncs[13])(); - SDL_Surface *surfaces[3]; - SDL_Palette *physpal; - SDL_Color *gammacols; - char *wm_strings[2]; - int offsets[2]; - SDL_GrabMode input_grab; - int handles_any_size; - SDL_PrivateVideoData *hidden; // Why did they have to bury this so far in? -}; - -extern SDL_VideoDevice *current_video; -#define SDL_Display (current_video->hidden->X11_Display) - -SDL_Cursor *CreateColorCursor(FTexture *cursorpic) -{ - return NULL; -} -#endif - -bool I_SetCursor(FTexture *cursorpic) -{ - if (cursorpic != NULL && cursorpic->UseType != FTexture::TEX_Null) - { - // Must be no larger than 32x32. - if (cursorpic->GetWidth() > 32 || cursorpic->GetHeight() > 32) - { - return false; - } - -#ifdef USE_XCURSOR - if (UseXCursor) - { - if (FirstCursor == NULL) - { - FirstCursor = SDL_GetCursor(); - } - X11Cursor = CreateColorCursor(cursorpic); - if (X11Cursor != NULL) - { - SDL_SetCursor(X11Cursor); - return true; - } - } -#endif - if (cursorSurface == NULL) - cursorSurface = SDL_CreateRGBSurface (0, 32, 32, 32, MAKEARGB(0,255,0,0), MAKEARGB(0,0,255,0), MAKEARGB(0,0,0,255), MAKEARGB(255,0,0,0)); - - SDL_ShowCursor(0); - SDL_LockSurface(cursorSurface); - BYTE buffer[32*32*4]; - memset(buffer, 0, 32*32*4); - FBitmap bmp(buffer, 32*4, 32, 32); - cursorpic->CopyTrueColorPixels(&bmp, 0, 0); - memcpy(cursorSurface->pixels, bmp.GetPixels(), 32*32*4); - SDL_UnlockSurface(cursorSurface); - } - else - { - SDL_ShowCursor(1); - - if (cursorSurface != NULL) - { - SDL_FreeSurface(cursorSurface); - cursorSurface = NULL; - } -#ifdef USE_XCURSOR - if (X11Cursor != NULL) - { - SDL_SetCursor(FirstCursor); - SDL_FreeCursor(X11Cursor); - X11Cursor = NULL; - } -#endif - } - return true; -} - -void I_SetMainWindowVisible(bool visible) -{ - -} - -const char* I_GetBackEndName() -{ - return "SDL"; -} diff --git a/src/sdl/i_input.cpp b/src/sdl/i_input.cpp deleted file mode 100644 index bf676db70..000000000 --- a/src/sdl/i_input.cpp +++ /dev/null @@ -1,505 +0,0 @@ -#include -#include -#include "doomtype.h" -#include "c_dispatch.h" -#include "doomdef.h" -#include "doomstat.h" -#include "m_argv.h" -#include "i_input.h" -#include "v_video.h" - -#include "d_main.h" -#include "d_event.h" -#include "d_gui.h" -#include "c_console.h" -#include "c_cvars.h" -#include "i_system.h" -#include "dikeys.h" -#include "templates.h" -#include "s_sound.h" - -static void I_CheckGUICapture (); -static void I_CheckNativeMouse (); - -bool GUICapture; -static bool NativeMouse = true; - -extern int paused; - -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) -CVAR (Bool, sdl_nokeyrepeat, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) - -EXTERN_CVAR (Bool, fullscreen) - -extern int WaitingForKey, chatmodeon; -extern constate_e ConsoleState; - -extern SDL_Surface *cursorSurface; -extern SDL_Rect cursorBlit; - -static BYTE KeySymToDIK[SDLK_LAST], DownState[SDLK_LAST]; - -static WORD DIKToKeySym[256] = -{ - 0, SDLK_ESCAPE, '1', '2', '3', '4', '5', '6', - '7', '8', '9', '0', '-', '=', SDLK_BACKSPACE, SDLK_TAB, - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', - 'o', 'p', '[', ']', SDLK_RETURN, SDLK_LCTRL, 'a', 's', - 'd', 'f', 'g', 'h', 'j', 'k', 'l', SDLK_SEMICOLON, - '\'', '`', SDLK_LSHIFT, '\\', 'z', 'x', 'c', 'v', - 'b', 'n', 'm', ',', '.', '/', SDLK_RSHIFT, SDLK_KP_MULTIPLY, - SDLK_LALT, ' ', SDLK_CAPSLOCK, SDLK_F1, SDLK_F2, SDLK_F3, SDLK_F4, SDLK_F5, - SDLK_F6, SDLK_F7, SDLK_F8, SDLK_F9, SDLK_F10, SDLK_NUMLOCK, SDLK_SCROLLOCK, SDLK_KP7, - SDLK_KP8, SDLK_KP9, SDLK_KP_MINUS, SDLK_KP4, SDLK_KP5, SDLK_KP6, SDLK_KP_PLUS, SDLK_KP1, - SDLK_KP2, SDLK_KP3, SDLK_KP0, SDLK_KP_PERIOD, 0, 0, 0, SDLK_F11, - SDLK_F12, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, SDLK_F13, SDLK_F14, SDLK_F15, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, SDLK_KP_EQUALS, 0, 0, - 0, SDLK_AT, SDLK_COLON, 0, 0, 0, 0, 0, - 0, 0, 0, 0, SDLK_KP_ENTER, SDLK_RCTRL, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, SDLK_KP_DIVIDE, 0, SDLK_SYSREQ, - SDLK_RALT, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, SDLK_PAUSE, 0, SDLK_HOME, - SDLK_UP, SDLK_PAGEUP, 0, SDLK_LEFT, 0, SDLK_RIGHT, 0, SDLK_END, - SDLK_DOWN, SDLK_PAGEDOWN, SDLK_INSERT, SDLK_DELETE, 0, 0, 0, 0, - 0, 0, 0, SDLK_LSUPER, SDLK_RSUPER, SDLK_MENU, SDLK_POWER, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static void FlushDIKState (int low=0, int high=NUM_KEYS-1) -{ -} - -static void InitKeySymMap () -{ - for (int i = 0; i < 256; ++i) - { - KeySymToDIK[DIKToKeySym[i]] = i; - } - KeySymToDIK[0] = 0; - KeySymToDIK[SDLK_RSHIFT] = DIK_LSHIFT; - KeySymToDIK[SDLK_RCTRL] = DIK_LCONTROL; - KeySymToDIK[SDLK_RALT] = DIK_LMENU; - // Depending on your Linux flavor, you may get SDLK_PRINT or SDLK_SYSREQ - KeySymToDIK[SDLK_PRINT] = DIK_SYSRQ; -} - -static void I_CheckGUICapture () -{ - bool wantCapt; - bool repeat; - int oldrepeat, interval; - - SDL_GetKeyRepeat(&oldrepeat, &interval); - - if (menuactive == MENU_Off) - { - wantCapt = ConsoleState == c_down || ConsoleState == c_falling || chatmodeon; - } - else - { - wantCapt = (menuactive == MENU_On || menuactive == MENU_OnNoPause); - } - - if (wantCapt != GUICapture) - { - GUICapture = wantCapt; - if (wantCapt) - { - int x, y; - SDL_GetMouseState (&x, &y); - cursorBlit.x = x; - cursorBlit.y = y; - - FlushDIKState (); - memset (DownState, 0, sizeof(DownState)); - repeat = !sdl_nokeyrepeat; - SDL_EnableUNICODE (1); - } - else - { - repeat = false; - SDL_EnableUNICODE (0); - } - } - if (wantCapt) - { - repeat = !sdl_nokeyrepeat; - } - else - { - repeat = false; - } - if (repeat != (oldrepeat != 0)) - { - if (repeat) - { - SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); - } - else - { - SDL_EnableKeyRepeat (0, 0); - } - } -} - -void I_SetMouseCapture() -{ -} - -void I_ReleaseMouseCapture() -{ -} - -static void CenterMouse () -{ - SDL_WarpMouse (screen->GetWidth()/2, screen->GetHeight()/2); - SDL_PumpEvents (); - SDL_GetRelativeMouseState (NULL, NULL); -} - -static void PostMouseMove (int x, int y) -{ - static int lastx = 0, lasty = 0; - event_t ev = { 0,0,0,0,0,0,0 }; - - if (m_filter) - { - ev.x = (x + lastx) / 2; - ev.y = (y + lasty) / 2; - } - else - { - ev.x = x; - ev.y = y; - } - lastx = x; - lasty = y; - if (ev.x | ev.y) - { - ev.type = EV_Mouse; - D_PostEvent (&ev); - } -} - -static void MouseRead () -{ - int x, y; - - if (NativeMouse) - { - return; - } - - SDL_GetRelativeMouseState (&x, &y); - if (!m_noprescale) - { - x *= 3; - y *= 2; - } - if (x | y) - { - CenterMouse (); - PostMouseMove (x, -y); - } -} - -static void WheelMoved(event_t *event) -{ - if (GUICapture) - { - if (event->type != EV_KeyUp) - { - SDLMod mod = SDL_GetModState(); - event->type = EV_GUI_Event; - event->subtype = event->data1 == KEY_MWHEELUP ? EV_GUI_WheelUp : EV_GUI_WheelDown; - event->data1 = 0; - event->data3 = ((mod & KMOD_SHIFT) ? GKM_SHIFT : 0) | - ((mod & KMOD_CTRL) ? GKM_CTRL : 0) | - ((mod & KMOD_ALT) ? GKM_ALT : 0); - D_PostEvent(event); - } - } - else - { - D_PostEvent(event); - } -} - -CUSTOM_CVAR(Int, mouse_capturemode, 1, CVAR_GLOBALCONFIG|CVAR_ARCHIVE) -{ - if (self < 0) self = 0; - else if (self > 2) self = 2; -} - -static bool inGame() -{ - 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; - } -} - -static void I_CheckNativeMouse () -{ - bool focus = (SDL_GetAppState() & (SDL_APPINPUTFOCUS|SDL_APPACTIVE)) - == (SDL_APPINPUTFOCUS|SDL_APPACTIVE); - bool fs = (SDL_GetVideoSurface ()->flags & SDL_FULLSCREEN) != 0; - - bool wantNative = !focus || (!use_mouse || GUICapture || paused || demoplayback || !inGame()); - - if (wantNative != NativeMouse) - { - NativeMouse = wantNative; - SDL_ShowCursor (wantNative ? cursorSurface == NULL : 0); - if (wantNative) - { - SDL_WM_GrabInput (SDL_GRAB_OFF); - FlushDIKState (KEY_MOUSE1, KEY_MOUSE8); - } - else - { - SDL_WM_GrabInput (SDL_GRAB_ON); - CenterMouse (); - } - } -} - -void MessagePump (const SDL_Event &sev) -{ - static int lastx = 0, lasty = 0; - int x, y; - event_t event = { 0,0,0,0,0,0,0 }; - - switch (sev.type) - { - case SDL_QUIT: - exit (0); - - case SDL_ACTIVEEVENT: - if (sev.active.state == SDL_APPINPUTFOCUS) - { - if (sev.active.gain == 0) - { // kill focus - FlushDIKState (); - } - S_SetSoundPaused(sev.active.gain); - } - break; - - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: - case SDL_MOUSEMOTION: - if (!GUICapture || sev.button.button == 4 || sev.button.button == 5) - { - if(sev.type != SDL_MOUSEMOTION) - { - event.type = sev.type == SDL_MOUSEBUTTONDOWN ? EV_KeyDown : EV_KeyUp; - /* These button mappings work with my Gentoo system using the - * evdev driver and a Logitech MX510 mouse. Whether or not they - * carry over to other Linux systems, I have no idea, but I sure - * hope so. (Though buttons 11 and 12 are kind of useless, since - * they also trigger buttons 4 and 5.) - */ - switch (sev.button.button) - { - case 1: event.data1 = KEY_MOUSE1; break; - case 2: event.data1 = KEY_MOUSE3; break; - case 3: event.data1 = KEY_MOUSE2; break; - case 4: event.data1 = KEY_MWHEELUP; break; - case 5: event.data1 = KEY_MWHEELDOWN; break; - case 6: event.data1 = KEY_MOUSE4; break; /* dunno; not generated by my mouse */ - case 7: event.data1 = KEY_MOUSE5; break; /* ditto */ - case 8: event.data1 = KEY_MOUSE4; break; - case 9: event.data1 = KEY_MOUSE5; break; - case 10: event.data1 = KEY_MOUSE6; break; - case 11: event.data1 = KEY_MOUSE7; break; - case 12: event.data1 = KEY_MOUSE8; break; - default: printf("SDL mouse button %s %d\n", - sev.type == SDL_MOUSEBUTTONDOWN ? "down" : "up", sev.button.button); break; - } - if (event.data1 != 0) - { - //DIKState[ActiveDIKState][event.data1] = (event.type == EV_KeyDown); - if (event.data1 == KEY_MWHEELUP || event.data1 == KEY_MWHEELDOWN) - { - WheelMoved(&event); - } - else - { - D_PostEvent(&event); - } - } - } - } - else if (sev.type == SDL_MOUSEMOTION || (sev.button.button >= 1 && sev.button.button <= 3)) - { - int x, y; - SDL_GetMouseState (&x, &y); - - cursorBlit.x = event.data1 = x; - cursorBlit.y = event.data2 = y; - event.type = EV_GUI_Event; - if(sev.type == SDL_MOUSEMOTION) - event.subtype = EV_GUI_MouseMove; - else - { - event.subtype = sev.type == SDL_MOUSEBUTTONDOWN ? EV_GUI_LButtonDown : EV_GUI_LButtonUp; - event.subtype += (sev.button.button - 1) * 3; - } - D_PostEvent(&event); - } - break; - - case SDL_KEYDOWN: - case SDL_KEYUP: - if (sev.key.keysym.sym >= SDLK_LAST) - break; - - if (!GUICapture) - { - event.type = sev.type == SDL_KEYDOWN ? EV_KeyDown : EV_KeyUp; - event.data1 = KeySymToDIK[sev.key.keysym.sym]; - if (event.data1) - { - if (sev.key.keysym.sym < 256) - { - event.data2 = sev.key.keysym.sym; - } - D_PostEvent (&event); - } - } - else - { - event.type = EV_GUI_Event; - event.subtype = sev.type == SDL_KEYDOWN ? EV_GUI_KeyDown : EV_GUI_KeyUp; - event.data3 = ((sev.key.keysym.mod & KMOD_SHIFT) ? GKM_SHIFT : 0) | - ((sev.key.keysym.mod & KMOD_CTRL) ? GKM_CTRL : 0) | - ((sev.key.keysym.mod & KMOD_ALT) ? GKM_ALT : 0); - - if (sev.key.keysym.sym < SDLK_LAST) - { - if (event.subtype == EV_GUI_KeyDown) - { - if (DownState[sev.key.keysym.sym]) - { - event.subtype = EV_GUI_KeyRepeat; - } - DownState[sev.key.keysym.sym] = 1; - } - else - { - DownState[sev.key.keysym.sym] = 0; - } - } - - switch (sev.key.keysym.sym) - { - case SDLK_KP_ENTER: event.data1 = GK_RETURN; break; - case SDLK_PAGEUP: event.data1 = GK_PGUP; break; - case SDLK_PAGEDOWN: event.data1 = GK_PGDN; break; - case SDLK_END: event.data1 = GK_END; break; - case SDLK_HOME: event.data1 = GK_HOME; break; - case SDLK_LEFT: event.data1 = GK_LEFT; break; - case SDLK_RIGHT: event.data1 = GK_RIGHT; break; - case SDLK_UP: event.data1 = GK_UP; break; - case SDLK_DOWN: event.data1 = GK_DOWN; break; - case SDLK_DELETE: event.data1 = GK_DEL; break; - case SDLK_ESCAPE: event.data1 = GK_ESCAPE; break; - case SDLK_F1: event.data1 = GK_F1; break; - case SDLK_F2: event.data1 = GK_F2; break; - case SDLK_F3: event.data1 = GK_F3; break; - case SDLK_F4: event.data1 = GK_F4; break; - case SDLK_F5: event.data1 = GK_F5; break; - case SDLK_F6: event.data1 = GK_F6; break; - case SDLK_F7: event.data1 = GK_F7; break; - case SDLK_F8: event.data1 = GK_F8; break; - case SDLK_F9: event.data1 = GK_F9; break; - case SDLK_F10: event.data1 = GK_F10; break; - case SDLK_F11: event.data1 = GK_F11; break; - case SDLK_F12: event.data1 = GK_F12; break; - default: - if (sev.key.keysym.sym < 256) - { - event.data1 = sev.key.keysym.sym; - } - break; - } - event.data2 = sev.key.keysym.unicode & 0xff; - if (event.data1 < 128) - { - event.data1 = toupper(event.data1); - D_PostEvent (&event); - } - if (!iscntrl(event.data2) && event.subtype != EV_GUI_KeyUp) - { - event.subtype = EV_GUI_Char; - event.data1 = event.data2; - event.data2 = sev.key.keysym.mod & KMOD_ALT; - event.data3 = 0; - D_PostEvent (&event); - } - } - break; - - case SDL_JOYBUTTONDOWN: - case SDL_JOYBUTTONUP: - if (!GUICapture) - { - event.type = sev.type == SDL_JOYBUTTONDOWN ? EV_KeyDown : EV_KeyUp; - event.data1 = KEY_FIRSTJOYBUTTON + sev.jbutton.button; - if(event.data1 != 0) - D_PostEvent(&event); - } - break; - } -} - -void I_GetEvent () -{ - SDL_Event sev; - - while (SDL_PollEvent (&sev)) - { - MessagePump (sev); - } - if (use_mouse) - { - MouseRead (); - } -} - -void I_StartTic () -{ - I_CheckGUICapture (); - I_CheckNativeMouse (); - I_GetEvent (); -} - -void I_ProcessJoysticks (); -void I_StartFrame () -{ - if (KeySymToDIK[SDLK_BACKSPACE] == 0) - { - InitKeySymMap (); - } - - I_ProcessJoysticks(); -} diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 93802c8e8..84d1d8101 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -37,7 +37,6 @@ #include #include #else -#include #include #include #include diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index fa04cfa51..2133e07c6 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -13,7 +13,6 @@ #include #include #else -#include #define FALSE 0 #define TRUE 1 #endif diff --git a/src/tempfiles.h b/src/tempfiles.h index beeb2bc1d..406c54153 100644 --- a/src/tempfiles.h +++ b/src/tempfiles.h @@ -38,6 +38,8 @@ #pragma once #endif +#include + // Returns a file name suitable for use as a temp file. // If you create a file with this name (and presumably you // will), it will be deleted automatically by this class's diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 147a4c192..c2d3c8505 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1056,13 +1056,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile) PARAM_ANGLE_OPT (angle) { angle = 0; } PARAM_INT_OPT (flags) { flags = 0; } PARAM_ANGLE_OPT (pitch) { pitch = 0; } + PARAM_INT_OPT (ptr) { ptr = AAPTR_TARGET; } + + AActor *ref = COPY_AAPTR(self, ptr); int aimmode = flags & CMF_AIMMODE; AActor * targ; AActor * missile; - if (self->target != NULL || aimmode == 2) + if (ref != NULL || aimmode == 2) { if (ti) { @@ -1079,14 +1082,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomMissile) self->x += x; self->y += y; self->z += z; - missile = P_SpawnMissileXYZ(self->x, self->y, self->z + 32*FRACUNIT, self, self->target, ti, false); + missile = P_SpawnMissileXYZ(self->x, self->y, self->z + 32*FRACUNIT, self, ref, ti, false); self->x -= x; self->y -= y; self->z -= z; break; case 1: - missile = P_SpawnMissileXYZ(self->x+x, self->y+y, self->z + self->GetBobOffset() + spawnheight, self, self->target, ti, false); + missile = P_SpawnMissileXYZ(self->x+x, self->y+y, self->z + self->GetBobOffset() + spawnheight, self, ref, ti, false); break; case 2: @@ -1209,6 +1212,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); } PARAM_FIXED_OPT (range) { range = MISSILERANGE; } PARAM_INT_OPT (flags) { flags = 0; } + PARAM_INT_OPT (ptr) { ptr = AAPTR_TARGET; } + + AActor *ref = COPY_AAPTR(self, ptr); if (range == 0) range = MISSILERANGE; @@ -1218,9 +1224,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomBulletAttack) int bslope = 0; int laflags = (flags & CBAF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0; - if (self->target || (flags & CBAF_AIMFACING)) + if (ref != NULL || (flags & CBAF_AIMFACING)) { - if (!(flags & CBAF_AIMFACING)) A_FaceTarget (self); + if (!(flags & CBAF_AIMFACING)) + { + A_Face(self, ref); + } bangle = self->angle; if (!(flags & CBAF_NOPITCH)) bslope = P_AimLineAttack (self, bangle, MISSILERANGE); @@ -1837,9 +1846,12 @@ static int DoGiveInventory(AActor *receiver, bool orresult, VM_ARGS) int paramnum = NAP-1; PARAM_CLASS (mi, AInventory); PARAM_INT_OPT (amount) { amount = 1; } - PARAM_INT_OPT (setreceiver) { setreceiver = AAPTR_DEFAULT; } - receiver = COPY_AAPTR(receiver, setreceiver); + if (!orresult) + { + PARAM_INT_OPT(setreceiver) { setreceiver = AAPTR_DEFAULT; } + receiver = COPY_AAPTR(receiver, setreceiver); + } if (receiver == NULL) { // If there's nothing to receive it, it's obviously a fail, right? ACTION_SET_RESULT(false); @@ -1855,6 +1867,11 @@ static int DoGiveInventory(AActor *receiver, bool orresult, VM_ARGS) if (mi) { AInventory *item = static_cast(Spawn(mi, 0, 0, 0, NO_REPLACE)); + if (item == NULL) + { + ACTION_SET_RESULT(false); + return numret; + } if (item->IsKindOf(RUNTIME_CLASS(AHealth))) { item->Amount *= amount; @@ -1958,14 +1975,17 @@ int DoTakeInventory(AActor *receiver, bool orresult, VM_ARGS) PARAM_CLASS (itemtype, AInventory); PARAM_INT_OPT (amount) { amount = 0; } PARAM_INT_OPT (flags) { flags = 0; } - PARAM_INT_OPT (setreceiver) { setreceiver = AAPTR_DEFAULT; } if (itemtype == NULL) { ACTION_SET_RESULT(true); return numret; } - receiver = COPY_AAPTR(receiver, setreceiver); + if (!orresult) + { + PARAM_INT_OPT(setreceiver) { setreceiver = AAPTR_DEFAULT; } + receiver = COPY_AAPTR(receiver, setreceiver); + } if (receiver == NULL) { ACTION_SET_RESULT(false); @@ -2776,9 +2796,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetScale) PARAM_ACTION_PROLOGUE; PARAM_FIXED (scalex); PARAM_FIXED_OPT (scaley) { scaley = scalex; } + PARAM_INT_OPT (ptr) { ptr = AAPTR_DEFAULT; } - self->scaleX = scalex; - self->scaleY = scaley; + AActor *ref = COPY_AAPTR(self, ptr); + + if (ref != NULL) + { + ref->scaleX = scalex; + ref->scaleY = scaley; + } return 0; } @@ -2888,7 +2914,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSight) // Useful for maps with many multi-actor special effects. // //=========================================================================== -static bool DoCheckSightOrRange(AActor *self, AActor *camera, double range) +static bool DoCheckSightOrRange(AActor *self, AActor *camera, double range, bool twodi) { if (camera == NULL) { @@ -2911,8 +2937,9 @@ static bool DoCheckSightOrRange(AActor *self, AActor *camera, double range) { dz = 0; } - if ((dx*dx) + (dy*dy) + (dz*dz) <= range) - { // Within range + double distance = (dx * dx) + (dy * dy) + (twodi == 0? (dz * dz) : 0); + if (distance <= range){ + // Within range return true; } @@ -2929,6 +2956,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSightOrRange) PARAM_ACTION_PROLOGUE; PARAM_FLOAT(range); PARAM_STATE(jump); + PARAM_BOOL_OPT(twodi) { twodi = false; } ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! @@ -2938,13 +2966,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSightOrRange) if (playeringame[i]) { // Always check from each player. - if (DoCheckSightOrRange(self, players[i].mo, range)) + if (DoCheckSightOrRange(self, players[i].mo, range, twodi)) { return numret; } // If a player is viewing from a non-player, check that too. if (players[i].camera != NULL && players[i].camera->player == NULL && - DoCheckSightOrRange(self, players[i].camera, range)) + DoCheckSightOrRange(self, players[i].camera, range, twodi)) { return numret; } @@ -2960,7 +2988,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckSightOrRange) // Jumps if this actor is out of range of all players. // //=========================================================================== -static bool DoCheckRange(AActor *self, AActor *camera, double range) +static bool DoCheckRange(AActor *self, AActor *camera, double range, bool twodi) { if (camera == NULL) { @@ -2980,7 +3008,8 @@ static bool DoCheckRange(AActor *self, AActor *camera, double range) else{ dz = 0; } - if ((dx*dx) + (dy*dy) + (dz*dz) <= range){ + double distance = (dx * dx) + (dy * dy) + (twodi == 0? (dz * dz) : 0); + if (distance <= range){ // Within range return true; } @@ -2992,6 +3021,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckRange) PARAM_ACTION_PROLOGUE; PARAM_FLOAT(range); PARAM_STATE(jump); + PARAM_BOOL_OPT(twodi) { twodi = false; } ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! @@ -3001,13 +3031,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckRange) if (playeringame[i]) { // Always check from each player. - if (DoCheckRange(self, players[i].mo, range)) + if (DoCheckRange(self, players[i].mo, range, twodi)) { return numret; } // If a player is viewing from a non-player, check that too. if (players[i].camera != NULL && players[i].camera->player == NULL && - DoCheckRange(self, players[i].camera, range)) + DoCheckRange(self, players[i].camera, range, twodi)) { return numret; } @@ -4264,8 +4294,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetAngle) PARAM_ACTION_PROLOGUE; PARAM_ANGLE_OPT(angle) { angle = 0; } PARAM_INT_OPT(flags) { flags = 0; } + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } - self->SetAngle(angle, !!(flags & SPF_INTERPOLATE)); + AActor *ref = COPY_AAPTR(self, ptr); + if (ref != NULL) + { + ref->SetAngle(angle, !!(flags & SPF_INTERPOLATE)); + } return 0; } @@ -4282,15 +4317,23 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetPitch) PARAM_ACTION_PROLOGUE; PARAM_ANGLE(pitch); PARAM_INT_OPT(flags) { flags = 0; } + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } - if (self->player != NULL || (flags & SPF_FORCECLAMP)) + AActor *ref = COPY_AAPTR(self, ptr); + + if (ref == NULL) + { + return 0; + } + + if (ref->player != NULL || (flags & SPF_FORCECLAMP)) { // clamp the pitch we set int min, max; - if (self->player != NULL) + if (ref->player != NULL) { - min = self->player->MinPitch; - max = self->player->MaxPitch; + min = ref->player->MinPitch; + max = ref->player->MaxPitch; } else { @@ -4300,7 +4343,30 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetPitch) pitch = clamp(pitch, min, max); } - self->SetPitch(pitch, !!(flags & SPF_INTERPOLATE)); + ref->SetPitch(pitch, !!(flags & SPF_INTERPOLATE)); + return 0; +} + +//=========================================================================== +// +// [Nash] A_SetRoll +// +// Set actor's roll (in degrees). +// +//=========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRoll) +{ + PARAM_ACTION_PROLOGUE; + PARAM_ANGLE (roll); + PARAM_INT_OPT (flags); { flags = 0; } + PARAM_INT_OPT (ptr); { ptr = AAPTR_DEFAULT; } + AActor *ref = COPY_AAPTR(self, ptr); + + if (ref != NULL) + { + ref->SetRoll(roll, !!(flags & SPF_INTERPOLATE)); + } return 0; } @@ -4316,18 +4382,26 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ScaleVelocity) { PARAM_ACTION_PROLOGUE; PARAM_FIXED(scale); + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + + AActor *ref = COPY_AAPTR(self, ptr); + + if (ref == NULL) + { + return 0; + } INTBOOL was_moving = self->velx | self->vely | self->velz; - self->velx = FixedMul(self->velx, scale); - self->vely = FixedMul(self->vely, scale); - self->velz = FixedMul(self->velz, scale); + ref->velx = FixedMul(ref->velx, scale); + ref->vely = FixedMul(ref->vely, scale); + ref->velz = FixedMul(ref->velz, scale); // If the actor was previously moving but now is not, and is a player, // update its player variables. (See A_Stop.) if (was_moving) { - CheckStopped(self); + CheckStopped(ref); } return 0; } @@ -4345,12 +4419,20 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeVelocity) PARAM_FIXED_OPT (y) { y = 0; } PARAM_FIXED_OPT (z) { z = 0; } PARAM_INT_OPT (flags) { flags = 0; } + PARAM_INT_OPT (ptr) { ptr = AAPTR_DEFAULT; } - INTBOOL was_moving = self->velx | self->vely | self->velz; + AActor *ref = COPY_AAPTR(self, ptr); + + if (ref == NULL) + { + return 0; + } + + INTBOOL was_moving = ref->velx | ref->vely | ref->velz; fixed_t vx = x, vy = y, vz = z; - fixed_t sina = finesine[self->angle >> ANGLETOFINESHIFT]; - fixed_t cosa = finecosine[self->angle >> ANGLETOFINESHIFT]; + fixed_t sina = finesine[ref->angle >> ANGLETOFINESHIFT]; + fixed_t cosa = finecosine[ref->angle >> ANGLETOFINESHIFT]; if (flags & 1) // relative axes - make x, y relative to actor's current angle { @@ -4359,15 +4441,15 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ChangeVelocity) } if (flags & 2) // discard old velocity - replace old velocity with new velocity { - self->velx = vx; - self->vely = vy; - self->velz = vz; + ref->velx = vx; + ref->vely = vy; + ref->velz = vz; } else // add new velocity to old velocity { - self->velx += vx; - self->vely += vy; - self->velz += vz; + ref->velx += vx; + ref->vely += vy; + ref->velz += vz; } if (was_moving) @@ -4560,12 +4642,19 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) fixed_t prevX = self->x; fixed_t prevY = self->y; fixed_t prevZ = self->z; + fixed_t aboveFloor = spot->z - spot->floorz; + fixed_t finalz = spot->floorz + aboveFloor; + + if (spot->z + self->height > spot->ceilingz) + finalz = spot->ceilingz - self->height; + else if (spot->z < spot->floorz) + finalz = spot->floorz; + //Take precedence and cooperate with telefragging first. bool tele_result = P_TeleportMove(self, spot->x, spot->y, spot->z, flags & TF_TELEFRAG); - if (!tele_result && (flags & TF_FORCED)) + if (flags & TF_FORCED) { - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! //If for some reason the original move didn't work, regardless of telefrag, force it to move. self->SetOrigin(spot->x, spot->y, spot->z); tele_result = true; @@ -4894,6 +4983,8 @@ enum WARPF WARPF_TOFLOOR = 0x100, WARPF_TESTONLY = 0x200, WARPF_ABSOLUTEPOSITION = 0x400, + WARPF_BOB = 0x800, + WARPF_MOVEPTR = 0x1000, }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) @@ -4909,19 +5000,29 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) AActor *reference = COPY_AAPTR(self, destination_selector); + //If there is no actor to warp to, fail. if (!reference) { ACTION_SET_RESULT(false); return numret; } - fixed_t oldx = self->x; - fixed_t oldy = self->y; - fixed_t oldz = self->z; + AActor *caller = self; + + if (flags & WARPF_MOVEPTR) + { + AActor *temp = reference; + reference = caller; + caller = temp; + } + + fixed_t oldx = caller->x; + fixed_t oldy = caller->y; + fixed_t oldz = caller->z; if (!(flags & WARPF_ABSOLUTEANGLE)) { - angle += (flags & WARPF_USECALLERANGLE) ? self->angle : reference->angle; + angle += (flags & WARPF_USECALLERANGLE) ? caller->angle : reference->angle; } if (!(flags & WARPF_ABSOLUTEPOSITION)) @@ -4943,7 +5044,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) { // set correct xy - self->SetOrigin( + caller->SetOrigin( reference->x + xofs, reference->y + yofs, reference->z); @@ -4954,10 +5055,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) if (zofs) { // extra unlink, link and environment calculation - self->SetOrigin( - self->x, - self->y, - self->floorz + zofs); + caller->SetOrigin( + caller->x, + caller->y, + caller->floorz + zofs); } else { @@ -4965,12 +5066,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) // already identified floor // A_Teleport does the same thing anyway - self->z = self->floorz; + caller->z = caller->floorz; } } else { - self->SetOrigin( + caller->SetOrigin( reference->x + xofs, reference->y + yofs, reference->z + zofs); @@ -4980,50 +5081,56 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) { if (flags & WARPF_TOFLOOR) { - self->SetOrigin(xofs, yofs, self->floorz + zofs); + caller->SetOrigin(xofs, yofs, caller->floorz + zofs); } else { - self->SetOrigin(xofs, yofs, zofs); + caller->SetOrigin(xofs, yofs, zofs); } } - if ((flags & WARPF_NOCHECKPOSITION) || P_TestMobjLocation(self)) + if ((flags & WARPF_NOCHECKPOSITION) || P_TestMobjLocation(caller)) { if (flags & WARPF_TESTONLY) { - self->SetOrigin(oldx, oldy, oldz); + caller->SetOrigin(oldx, oldy, oldz); } else { - self->angle = angle; + caller->angle = angle; if (flags & WARPF_STOP) { - self->velx = 0; - self->vely = 0; - self->velz = 0; + caller->velx = 0; + caller->vely = 0; + caller->velz = 0; } if (flags & WARPF_WARPINTERPOLATION) { - self->PrevX += self->x - oldx; - self->PrevY += self->y - oldy; - self->PrevZ += self->z - oldz; + caller->PrevX += caller->x - oldx; + caller->PrevY += caller->y - oldy; + caller->PrevZ += caller->z - oldz; } else if (flags & WARPF_COPYINTERPOLATION) { - self->PrevX = self->x + reference->PrevX - reference->x; - self->PrevY = self->y + reference->PrevY - reference->y; - self->PrevZ = self->z + reference->PrevZ - reference->z; + caller->PrevX = caller->x + reference->PrevX - reference->x; + caller->PrevY = caller->y + reference->PrevY - reference->y; + caller->PrevZ = caller->z + reference->PrevZ - reference->z; } else if (!(flags & WARPF_INTERPOLATE)) { - self->PrevX = self->x; - self->PrevY = self->y; - self->PrevZ = self->z; + caller->PrevX = caller->x; + caller->PrevY = caller->y; + caller->PrevZ = caller->z; + } + + if ((flags & WARPF_BOB) && (reference->flags2 & MF2_FLOATBOB)) + { + caller->z += reference->GetBobOffset(); } } + if (success_state) { ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! @@ -5036,7 +5143,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Warp) } else { - self->SetOrigin(oldx, oldy, oldz); + caller->SetOrigin(oldx, oldy, oldz); ACTION_SET_RESULT(false); } return numret; @@ -5375,55 +5482,86 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetSpeed) { PARAM_ACTION_PROLOGUE; PARAM_INT(speed); + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } - self->Speed = speed; + AActor *ref = COPY_AAPTR(self, ptr); + + if (ref != NULL) + { + ref->Speed = speed; + } return 0; } +static bool DoCheckSpecies(AActor *mo, FName species, bool exclude) +{ + return (!(species) || mo->Species == NAME_None || (species && ((exclude) ? (mo->Species != species) : (mo->Species == species)))); +} + +static bool DoCheckFilter(AActor *mo, PClassActor *filter, bool exclude) +{ + const PClass *c1 = mo->GetClass(); + return (!(filter) || (filter == NULL) || (filter && ((exclude) ? (c1 != filter) : (c1 == filter)))); +} + //=========================================================================== // // Common A_Damage handler // -// A_Damage* (int amount, str damagetype, int flags) +// A_Damage* (int amount, str damagetype, int flags, str filter, str species) // Damages the specified actor by the specified amount. Negative values heal. +// Flags: See below. +// Filter: Specified actor is the only type allowed to be affected. +// Species: Specified species is the only type allowed to be affected. +// +// Examples: +// A_Damage(20,"Normal",DMSS_FOILINVUL,0,"DemonicSpecies") <--Only actors +// with a species "DemonicSpecies" will be affected. Use 0 to not filter by actor. // //=========================================================================== enum DMSS { - DMSS_FOILINVUL = 1, - DMSS_AFFECTARMOR = 2, - DMSS_KILL = 4, - DMSS_NOFACTOR = 8, - DMSS_FOILBUDDHA = 16, - DMSS_NOPROTECT = 32, + DMSS_FOILINVUL = 1, //Foil invulnerability + DMSS_AFFECTARMOR = 2, //Make it affect armor + DMSS_KILL = 4, //Damages them for their current health + DMSS_NOFACTOR = 8, //Ignore DamageFactors + DMSS_FOILBUDDHA = 16, //Can kill actors with Buddha flag, except the player. + DMSS_NOPROTECT = 32, //Ignores PowerProtection entirely + DMSS_EXFILTER = 64, //Changes filter into a blacklisted class instead of whitelisted. + DMSS_EXSPECIES = 128, // ^ but with species instead. + DMSS_EITHER = 256, //Allow either type or species to be affected. }; -static void DoDamage(AActor *dmgtarget, AActor *self, int amount, FName DamageType, int flags) +static void DoDamage(AActor *dmgtarget, AActor *self, int amount, FName DamageType, int flags, PClassActor *filter, FName species) { - int dmgFlags = 0; - if (flags & DMSS_FOILINVUL) - dmgFlags += DMG_FOILINVUL; - if (flags & DMSS_FOILBUDDHA) - dmgFlags += DMG_FOILBUDDHA; - if ((flags & DMSS_KILL) || (flags & DMSS_NOFACTOR)) //Kill implies NoFactor - dmgFlags += DMG_NO_FACTOR; - if (!(flags & DMSS_AFFECTARMOR) || (flags & DMSS_KILL)) //Kill overrides AffectArmor - dmgFlags += DMG_NO_ARMOR; - if (flags & DMSS_KILL) //Kill adds the value of the damage done to it. Allows for more controlled extreme death types. - amount += dmgtarget->health; - if (flags & DMSS_NOPROTECT) //Ignore PowerProtection. - dmgFlags += DMG_NO_PROTECT; - - if (amount > 0) + bool filterpass = DoCheckFilter(dmgtarget, filter, (flags & DMSS_EXFILTER) ? true : false), + speciespass = DoCheckSpecies(dmgtarget, species, (flags & DMSS_EXSPECIES) ? true : false); + if ((flags & DMSS_EITHER) ? (filterpass || speciespass) : (filterpass && speciespass)) { - //Should wind up passing them through just fine. - P_DamageMobj(dmgtarget, self, self, amount, DamageType, dmgFlags); - } - else if (amount < 0) - { - amount = -amount; - P_GiveBody(dmgtarget, amount); + int dmgFlags = 0; + if (flags & DMSS_FOILINVUL) + dmgFlags += DMG_FOILINVUL; + if (flags & DMSS_FOILBUDDHA) + dmgFlags += DMG_FOILBUDDHA; + if ((flags & DMSS_KILL) || (flags & DMSS_NOFACTOR)) //Kill implies NoFactor + dmgFlags += DMG_NO_FACTOR; + if (!(flags & DMSS_AFFECTARMOR) || (flags & DMSS_KILL)) //Kill overrides AffectArmor + dmgFlags += DMG_NO_ARMOR; + if (flags & DMSS_KILL) //Kill adds the value of the damage done to it. Allows for more controlled extreme death types. + amount += dmgtarget->health; + if (flags & DMSS_NOPROTECT) //Ignore PowerProtection. + dmgFlags += DMG_NO_PROTECT; + + if (amount > 0) + { //Should wind up passing them through just fine. + P_DamageMobj(dmgtarget, self, self, amount, DamageType, dmgFlags); + } + else if (amount < 0) + { + amount = -amount; + P_GiveBody(dmgtarget, amount); + } } } @@ -5438,8 +5576,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSelf) PARAM_INT (amount); PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } - DoDamage(self, self, amount, damagetype, flags); + DoDamage(self, self, amount, damagetype, flags, filter, species); return 0; } @@ -5454,9 +5594,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageTarget) PARAM_INT (amount); PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } if (self->target != NULL) - DoDamage(self->target, self, amount, damagetype, flags); + DoDamage(self->target, self, amount, damagetype, flags, filter, species); return 0; } @@ -5471,9 +5613,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageTracer) PARAM_INT (amount); PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } if (self->tracer != NULL) - DoDamage(self->tracer, self, amount, damagetype, flags); + DoDamage(self->tracer, self, amount, damagetype, flags, filter, species); return 0; } @@ -5488,9 +5632,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageMaster) PARAM_INT (amount); PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } if (self->master != NULL) - DoDamage(self->master, self, amount, damagetype, flags); + DoDamage(self->master, self, amount, damagetype, flags, filter, species); return 0; } @@ -5505,6 +5651,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageChildren) PARAM_INT (amount); PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } TThinkerIterator it; AActor *mo; @@ -5512,7 +5660,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageChildren) while ( (mo = it.Next()) ) { if (mo->master == self) - DoDamage(mo, self, amount, damagetype, flags); + DoDamage(mo, self, amount, damagetype, flags, filter, species); } return 0; } @@ -5528,6 +5676,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSiblings) PARAM_INT (amount); PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } TThinkerIterator it; AActor *mo; @@ -5537,7 +5687,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSiblings) while ((mo = it.Next())) { if (mo->master == self->master && mo != self) - DoDamage(mo, self, amount, damagetype, flags); + DoDamage(mo, self, amount, damagetype, flags, filter, species); } } return 0; @@ -5551,36 +5701,43 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_DamageSiblings) //=========================================================================== enum KILS { - KILS_FOILINVUL = 1 << 0, - KILS_KILLMISSILES = 1 << 1, - KILS_NOMONSTERS = 1 << 2, - KILS_FOILBUDDHA = 1 << 3, + KILS_FOILINVUL = 1 << 0, + KILS_KILLMISSILES = 1 << 1, + KILS_NOMONSTERS = 1 << 2, + KILS_FOILBUDDHA = 1 << 3, + KILS_EXFILTER = 1 << 4, + KILS_EXSPECIES = 1 << 5, + KILS_EITHER = 1 << 6, }; -static void DoKill(AActor *killtarget, AActor *self, FName damagetype, int flags) +static void DoKill(AActor *killtarget, AActor *self, FName damagetype, int flags, PClassActor *filter, FName species) { - int dmgFlags = DMG_NO_ARMOR + DMG_NO_FACTOR; - - if (KILS_FOILINVUL) - dmgFlags += DMG_FOILINVUL; - if (KILS_FOILBUDDHA) - dmgFlags += DMG_FOILBUDDHA; - - if ((killtarget->flags & MF_MISSILE) && (flags & KILS_KILLMISSILES)) + bool filterpass = DoCheckFilter(killtarget, filter, (flags & KILS_EXFILTER) ? true : false), + speciespass = DoCheckSpecies(killtarget, species, (flags & KILS_EXSPECIES) ? true : false); + if ((flags & KILS_EITHER) ? (filterpass || speciespass) : (filterpass && speciespass)) //Check this first. I think it'll save the engine a lot more time this way. { - // [MC] Now that missiles can set masters, lets put in a check to properly - // destroy projectiles. BUT FIRST! New feature~! Check to see if it's - // invulnerable. Disregarded if foilinvul is on, but never works on a - // missile with NODAMAGE since that's the whole point of it. - if ((!(killtarget->flags2 & MF2_INVULNERABLE) || (flags & KILS_FOILINVUL)) && - (!(killtarget->flags2 & MF7_BUDDHA) || (flags & KILS_FOILBUDDHA)) && !(killtarget->flags5 & MF5_NODAMAGE)) + int dmgFlags = DMG_NO_ARMOR + DMG_NO_FACTOR; + + if (KILS_FOILINVUL) + dmgFlags += DMG_FOILINVUL; + if (KILS_FOILBUDDHA) + dmgFlags += DMG_FOILBUDDHA; + + if ((killtarget->flags & MF_MISSILE) && (flags & KILS_KILLMISSILES)) { - P_ExplodeMissile(killtarget, NULL, NULL); + //[MC] Now that missiles can set masters, lets put in a check to properly destroy projectiles. BUT FIRST! New feature~! + //Check to see if it's invulnerable. Disregarded if foilinvul is on, but never works on a missile with NODAMAGE + //since that's the whole point of it. + if ((!(killtarget->flags2 & MF2_INVULNERABLE) || (flags & KILS_FOILINVUL)) && + (!(killtarget->flags2 & MF7_BUDDHA) || (flags & KILS_FOILBUDDHA)) && !(killtarget->flags5 & MF5_NODAMAGE)) + { + P_ExplodeMissile(killtarget, NULL, NULL); + } + } + if (!(flags & KILS_NOMONSTERS)) + { + P_DamageMobj(killtarget, self, self, killtarget->health, damagetype, dmgFlags); } - } - if (!(flags & KILS_NOMONSTERS)) - { - P_DamageMobj(killtarget, self, self, killtarget->health, damagetype, dmgFlags); } } @@ -5595,9 +5752,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillTarget) PARAM_ACTION_PROLOGUE; PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } if (self->target != NULL) - DoKill(self->target, self, damagetype, flags); + DoKill(self->target, self, damagetype, flags, filter, species); return 0; } @@ -5611,9 +5770,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillTracer) PARAM_ACTION_PROLOGUE; PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } if (self->tracer != NULL) - DoKill(self->tracer, self, damagetype, flags); + DoKill(self->tracer, self, damagetype, flags, filter, species); return 0; } @@ -5627,9 +5788,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillMaster) PARAM_ACTION_PROLOGUE; PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } if (self->master != NULL) - DoKill(self->master, self, damagetype, flags); + DoKill(self->master, self, damagetype, flags, filter, species); return 0; } @@ -5643,14 +5806,18 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillChildren) PARAM_ACTION_PROLOGUE; PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } TThinkerIterator it; AActor *mo; while ( (mo = it.Next()) ) { - if (mo->master == self) - DoKill(mo, self, damagetype, flags); + if (mo->master == self) + { + DoKill(mo, self, damagetype, flags, filter, species); + } } return 0; } @@ -5665,6 +5832,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillSiblings) PARAM_ACTION_PROLOGUE; PARAM_NAME_OPT (damagetype) { damagetype = NAME_None; } PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } TThinkerIterator it; AActor *mo; @@ -5674,7 +5843,9 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillSiblings) while ( (mo = it.Next()) ) { if (mo->master == self->master && mo != self) - DoKill(mo, self, damagetype, flags); + { + DoKill(mo, self, damagetype, flags, filter, species); + } } } return 0; @@ -5688,29 +5859,37 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_KillSiblings) enum RMVF_flags { - RMVF_MISSILES = 1 << 0, - RMVF_NOMONSTERS = 1 << 1, - RMVF_MISC = 1 << 2, - RMVF_EVERYTHING = 1 << 3, + RMVF_MISSILES = 1 << 0, + RMVF_NOMONSTERS = 1 << 1, + RMVF_MISC = 1 << 2, + RMVF_EVERYTHING = 1 << 3, + RMVF_EXFILTER = 1 << 4, + RMVF_EXSPECIES = 1 << 5, + RMVF_EITHER = 1 << 6, }; -static void DoRemove(AActor *removetarget, int flags) +static void DoRemove(AActor *removetarget, int flags, PClassActor *filter, FName species) { - if ((flags & RMVF_EVERYTHING)) + bool filterpass = DoCheckFilter(removetarget, filter, (flags & RMVF_EXFILTER) ? true : false), + speciespass = DoCheckSpecies(removetarget, species, (flags & RMVF_EXSPECIES) ? true : false); + if ((flags & RMVF_EITHER) ? (filterpass || speciespass) : (filterpass && speciespass)) { - P_RemoveThing(removetarget); - } - if ((flags & RMVF_MISC) && !((removetarget->flags3 & MF3_ISMONSTER) && (removetarget->flags & MF_MISSILE))) - { - P_RemoveThing(removetarget); - } - if ((removetarget->flags3 & MF3_ISMONSTER) && !(flags & RMVF_NOMONSTERS)) - { - P_RemoveThing(removetarget); - } - if ((removetarget->flags & MF_MISSILE) && (flags & RMVF_MISSILES)) - { - P_RemoveThing(removetarget); + if ((flags & RMVF_EVERYTHING)) + { + P_RemoveThing(removetarget); + } + if ((flags & RMVF_MISC) && !((removetarget->flags3 & MF3_ISMONSTER) && (removetarget->flags & MF_MISSILE))) + { + P_RemoveThing(removetarget); + } + if ((removetarget->flags3 & MF3_ISMONSTER) && !(flags & RMVF_NOMONSTERS)) + { + P_RemoveThing(removetarget); + } + if ((removetarget->flags & MF_MISSILE) && (flags & RMVF_MISSILES)) + { + P_RemoveThing(removetarget); + } } } @@ -5723,10 +5902,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveTarget) { PARAM_ACTION_PROLOGUE; PARAM_INT_OPT(flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } if (self->target != NULL) { - DoRemove(self->target, flags); + DoRemove(self->target, flags, filter, species); } return 0; } @@ -5740,10 +5921,12 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveTracer) { PARAM_ACTION_PROLOGUE; PARAM_INT_OPT(flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } if (self->tracer != NULL) { - DoRemove(self->tracer, flags); + DoRemove(self->tracer, flags, filter, species); } return 0; } @@ -5756,11 +5939,13 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveTracer) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveMaster) { PARAM_ACTION_PROLOGUE; - PARAM_INT_OPT(flags) { flags = 0; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } if (self->master != NULL) { - DoRemove(self->master, flags); + DoRemove(self->master, flags, filter, species); } return 0; } @@ -5773,8 +5958,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveMaster) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveChildren) { PARAM_ACTION_PROLOGUE; - PARAM_BOOL_OPT(removeall) { removeall = false; } - PARAM_INT_OPT(flags) { flags = 0; } + PARAM_BOOL_OPT (removeall) { removeall = false; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } TThinkerIterator it; AActor *mo; @@ -5783,7 +5970,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveChildren) { if (mo->master == self && (mo->health <= 0 || removeall)) { - DoRemove(mo, flags); + DoRemove(mo, flags, filter, species); } } return 0; @@ -5797,8 +5984,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveChildren) DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveSiblings) { PARAM_ACTION_PROLOGUE; - PARAM_BOOL_OPT(removeall) { removeall = false; } - PARAM_INT_OPT(flags) { flags = 0; } + PARAM_BOOL_OPT (removeall) { removeall = false; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } TThinkerIterator it; AActor *mo; @@ -5809,7 +5998,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RemoveSiblings) { if (mo->master == self->master && mo != self && (mo->health <= 0 || removeall)) { - DoRemove(mo, flags); + DoRemove(mo, flags, filter, species); } } } @@ -5825,13 +6014,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Remove) { PARAM_ACTION_PROLOGUE; PARAM_INT (removee); - PARAM_INT_OPT (flags) { flags = 0; } + PARAM_INT_OPT (flags) { flags = 0; } + PARAM_CLASS_OPT (filter, AActor){ filter = NULL; } + PARAM_NAME_OPT (species) { species = NAME_None; } AActor *reference = COPY_AAPTR(self, removee); - if (reference != NULL) { - DoRemove(reference, flags); + DoRemove(reference, flags, filter, species); } return 0; } @@ -5895,3 +6085,137 @@ DEFINE_ACTION_FUNCTION(AActor, A_SwapTeleFog) } return 0; } + +//=========================================================================== +// +// A_SetFloatBobPhase +// +// Changes the FloatBobPhase of the actor. +//=========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetFloatBobPhase) +{ + PARAM_ACTION_PROLOGUE; + PARAM_INT(bob); + + //Respect float bob phase limits. + if (self && (bob >= 0 && bob <= 63)) + { + self->FloatBobPhase = bob; + } + return 0; +} + +//=========================================================================== +// A_SetHealth +// +// Changes the health of the actor. +// Takes a pointer as well. +//=========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetHealth) +{ + PARAM_ACTION_PROLOGUE; + PARAM_INT (health); + PARAM_INT_OPT (ptr) { ptr = AAPTR_DEFAULT; } + + AActor *mobj = COPY_AAPTR(self, ptr); + + if (!mobj) + { + return 0; + } + + player_t *player = mobj->player; + if (player) + { + if (health <= 0) + player->mo->health = mobj->health = player->health = 1; //Copied from the buddha cheat. + else + player->mo->health = mobj->health = player->health = health; + } + else if (mobj) + { + if (health <= 0) + mobj->health = 1; + else + mobj->health = health; + } + return 0; +} + +//=========================================================================== +// A_ResetHealth +// +// Resets the health of the actor to default, except if their dead. +// Takes a pointer. +//=========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_ResetHealth) +{ + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + + AActor *mobj = COPY_AAPTR(self, ptr); + + if (!mobj) + { + return 0; + } + + player_t *player = mobj->player; + if (player && (player->mo->health > 0)) + { + player->health = player->mo->health = player->mo->GetDefault()->health; //Copied from the resurrect cheat. + } + else if (mobj && (mobj->health > 0)) + { + mobj->health = mobj->SpawnHealth(); + } + return 0; +} + +//=========================================================================== +// +// A_SetRipperLevel(int level) +// +// Sets the ripper level/requirement of the calling actor. +// Also sets the minimum and maximum levels to rip through. +//=========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipperLevel) +{ + PARAM_ACTION_PROLOGUE; + PARAM_INT(level); + self->RipperLevel = level; + return 0; +} + +//=========================================================================== +// +// A_SetRipMin(int min) +// +// Sets the ripper level/requirement of the calling actor. +// Also sets the minimum and maximum levels to rip through. +//=========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipMin) +{ + PARAM_ACTION_PROLOGUE; + PARAM_INT(min); + self->RipLevelMin = min; + return 0; +} + +//=========================================================================== +// +// A_SetRipMin(int min) +// +// Sets the ripper level/requirement of the calling actor. +// Also sets the minimum and maximum levels to rip through. +//=========================================================================== +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipMax) +{ + PARAM_ACTION_PROLOGUE; + PARAM_INT(max); + self->RipLevelMax = max; + return 0; +} diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index 5b7c1f0f4..8064b910d 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -369,7 +369,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) return new FxRandom(rng, min, max, sc); } - else if (sc.CheckToken(TK_Pick)) + else if (sc.CheckToken(TK_RandomPick)) { FRandom *rng; TArray list; @@ -396,7 +396,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) break; sc.MustGetToken(','); } - return new FxPick(rng, list, sc); + return new FxRandomPick(rng, list, sc); } else if (sc.CheckToken(TK_FRandom)) { diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index fab33a95b..1aac01c29 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -636,7 +636,7 @@ public: // //========================================================================== -class FxPick : public FxExpression +class FxRandomPick : public FxExpression { protected: FRandom *rng; @@ -644,8 +644,8 @@ protected: public: - FxPick(FRandom *, TArray &expr, const FScriptPosition &pos); - ~FxPick(); + FxRandomPick(FRandom *, TArray &expr, const FScriptPosition &pos); + ~FxRandomPick(); FxExpression *Resolve(FCompileContext&); ExpEmit Emit(VMFunctionBuilder *build); diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 148df60e7..871ee35af 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -88,6 +88,7 @@ DEFINE_MEMBER_VARIABLE(radius, AActor) DEFINE_MEMBER_VARIABLE(reactiontime, AActor) DEFINE_MEMBER_VARIABLE(meleerange, AActor) DEFINE_MEMBER_VARIABLE(Speed, AActor) +DEFINE_MEMBER_VARIABLE(roll, AActor) ExpEmit::ExpEmit(VMFunctionBuilder *build, int type) : RegNum(build->Registers[type].Get(1)), RegType(type), Konst(false), Fixed(false) @@ -2104,7 +2105,7 @@ ExpEmit FxRandom::Emit(VMFunctionBuilder *build) // // //========================================================================== -FxPick::FxPick(FRandom *r, TArray &expr, const FScriptPosition &pos) +FxRandomPick::FxRandomPick(FRandom *r, TArray &expr, const FScriptPosition &pos) : FxExpression(pos) { assert(expr.Size() > 0); @@ -2123,7 +2124,7 @@ FxPick::FxPick(FRandom *r, TArray &expr, const FScriptPosition &p // //========================================================================== -FxPick::~FxPick() +FxRandomPick::~FxRandomPick() { } @@ -2133,7 +2134,7 @@ FxPick::~FxPick() // //========================================================================== -FxExpression *FxPick::Resolve(FCompileContext &ctx) +FxExpression *FxRandomPick::Resolve(FCompileContext &ctx) { CHECKRESOLVED(); for (unsigned int index = 0; index < choices.Size(); index++) @@ -2165,7 +2166,7 @@ FxExpression *FxPick::Resolve(FCompileContext &ctx) // //========================================================================== -ExpEmit FxPick::Emit(VMFunctionBuilder *build) +ExpEmit FxRandomPick::Emit(VMFunctionBuilder *build) { unsigned i; diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index ab551d804..6e47a2a86 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -1485,6 +1485,45 @@ DEFINE_PROPERTY(telefogdesttype, S, Actor) } } +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(ripperlevel, I, Actor) +{ + PROP_INT_PARM(id, 0); + if (id < 0) + { + I_Error ("RipperLevel must not be negative"); + } + defaults->RipperLevel = id; +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(riplevelmin, I, Actor) +{ + PROP_INT_PARM(id, 0); + if (id < 0) + { + I_Error ("RipLevelMin must not be negative"); + } + defaults->RipLevelMin = id; +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(riplevelmax, I, Actor) +{ + PROP_INT_PARM(id, 0); + if (id < 0) + { + I_Error ("RipLevelMax must not be negative"); + } + defaults->RipLevelMax = id; +} + //========================================================================== // // Special inventory properties diff --git a/src/timidity/instrum.cpp b/src/timidity/instrum.cpp index 5ab55201e..7454ca7a4 100644 --- a/src/timidity/instrum.cpp +++ b/src/timidity/instrum.cpp @@ -485,7 +485,7 @@ fail: sample_t *tmp; for (i = sp->data_length, tmp = sp->data; i; --i) { - a = abs(*tmp++); + a = fabsf(*tmp++); if (a > maxamp) maxamp = a; } diff --git a/src/v_text.cpp b/src/v_text.cpp index 64b95c041..cad9bb5d2 100644 --- a/src/v_text.cpp +++ b/src/v_text.cpp @@ -128,7 +128,6 @@ void DCanvas::DrawTextV(FFont *font, int normalcolor, int x, int y, const char * { va_list *more_p; DWORD data; - void *ptrval; switch (tag) { @@ -150,15 +149,9 @@ void DCanvas::DrawTextV(FFont *font, int normalcolor, int x, int y, const char * // We don't handle these. :( case DTA_DestWidth: case DTA_DestHeight: - *(DWORD *)tags = TAG_IGNORE; - data = va_arg (tags, DWORD); - break; - - // Translation is specified explicitly by the text. case DTA_Translation: - *(DWORD *)tags = TAG_IGNORE; - ptrval = va_arg (tags, void*); - break; + assert("Bad parameter for DrawText" && false); + return; case DTA_CleanNoMove_1: boolval = va_arg (tags, INTBOOL); diff --git a/src/version.h b/src/version.h index 6863f0573..09b830438 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4517 +#define SAVEVER 4518 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) diff --git a/src/zstring.h b/src/zstring.h index 457a9ef3b..90c80e752 100644 --- a/src/zstring.h +++ b/src/zstring.h @@ -47,6 +47,24 @@ #define PRINTFISH(x) #endif +#ifdef __clang__ +#define IGNORE_FORMAT_PRE \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wformat-invalid-specifier\"") \ + _Pragma("GCC diagnostic ignored \"-Wformat-extra-args\"") +#define IGNORE_FORMAT_POST _Pragma("GCC diagnostic pop") +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 6))) +#define IGNORE_FORMAT_PRE \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wformat=\"") \ + _Pragma("GCC diagnostic ignored \"-Wformat-extra-args\"") +#define IGNORE_FORMAT_POST _Pragma("GCC diagnostic pop") +#else +#define IGNORE_FORMAT_PRE +#define IGNORE_FORMAT_POST +#endif + + struct FStringData { unsigned int Len; // Length of string, excluding terminating null @@ -278,6 +296,16 @@ protected: static FNullStringData NullString; friend struct FStringData; + +private: + // Prevent these from being called as current practices are to use Compare. + // Without this FStrings will be accidentally compared against char* ptrs. + bool operator == (const FString &illegal) const; + bool operator != (const FString &illegal) const; + bool operator < (const FString &illegal) const; + bool operator > (const FString &illegal) const; + bool operator <= (const FString &illegal) const; + bool operator >= (const FString &illegal) const; }; namespace StringFormat diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index d20a7d0ed..ebc14cdda 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -28,6 +28,9 @@ ACTOR Actor native //: Thinker DeathType Normal TeleFogSourceType "TeleportFog" TeleFogDestType "TeleportFog" + RipperLevel 0 + RipLevelMin 0 + RipLevelMax 0 // Variables for the expression evaluator // NOTE: fixed_t and angle_t are only used here to ensure proper conversion @@ -65,6 +68,7 @@ ACTOR Actor native //: Thinker native int reactiontime; native fixed_t meleerange; native fixed_t speed; + native angle_t roll; native bool CheckClass(class checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false); native bool IsPointerEqual(int ptr_select1, int ptr_select2); @@ -207,8 +211,8 @@ ACTOR Actor native //: Thinker action native A_StopSoundEx(coerce name slot); action native A_SeekerMissile(int threshold, int turnmax, int flags = 0, int chance = 50, int distance = 10); action native A_Jump(int chance = 256, state label, ...); - action native A_CustomMissile(class missiletype, float spawnheight = 32, int spawnofs_xy = 0, float angle = 0, int flags = 0, float pitch = 0); - action native A_CustomBulletAttack(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", float range = 0, int flags = 0); + action native A_CustomMissile(class missiletype, float spawnheight = 32, int spawnofs_xy = 0, float angle = 0, int flags = 0, float pitch = 0, int ptr = AAPTR_TARGET); + action native A_CustomBulletAttack(float/*angle*/ spread_xy, float/*angle*/ spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", float range = 0, int flags = 0, int ptr = AAPTR_TARGET); action native A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = "", color color2 = "", int flags = 0, int aim = 0, float maxdiff = 0, class pufftype = "BulletPuff", float/*angle*/ spread_xy = 0, float/*angle*/ spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = "none", float spawnofs_z = 0); action native A_JumpIfHealthLower(int health, state label, int ptr_selector = AAPTR_DEFAULT); action native A_JumpIfCloser(float distance, state label); @@ -230,7 +234,7 @@ ACTOR Actor native //: Thinker action native A_FadeIn(float reduce = 0.1, int flags = 0); action native A_FadeOut(float reduce = 0.1, int flags = 1); //bool remove == true action native A_FadeTo(float target, float amount = 0.1, int flags = 0); - action native A_SetScale(float scalex, float scaley = 0); + action native A_SetScale(float scalex, float scaley = 0, int ptr = AAPTR_DEFAULT); action native A_SetMass(int mass); action native A_SpawnDebris(class spawntype, bool transfer_translation = false, float mult_h = 1, float mult_v = 1); action native A_CheckSight(state label); @@ -240,12 +244,6 @@ ACTOR Actor native //: Thinker action native A_ChangeFlag(string flagname, bool value); action native A_CheckFlag(string flagname, state label, int check_pointer = AAPTR_DEFAULT); action native A_JumpIf(bool expression, state label); - action native A_RemoveMaster(int flags = 0); - action native A_RemoveChildren(bool removeall = false, int flags = 0); - action native A_RemoveSiblings(bool removeall = false, int flags = 0); - action native A_KillMaster(name damagetype = "none", int flags = 0); - action native A_KillChildren(name damagetype = "none", int flags = 0); - action native A_KillSiblings(name damagetype = "none", int flags = 0); action native A_RaiseMaster(bool copy = 0); action native A_RaiseChildren(bool copy = 0); action native A_RaiseSiblings(bool copy = 0); @@ -253,7 +251,7 @@ ACTOR Actor native //: Thinker action native A_CheckCeiling(state label); action native A_PlayerSkinCheck(state label); action native A_BasicAttack(int meleedamage, sound meleesound, class missiletype, float missileheight); - action native A_Teleport(state teleportstate = "", class targettype = "BossSpot", class fogtype = "TeleportFog", int flags = 0, float mindist = 128, float maxdist = 0); + action native A_Teleport(state teleportstate = "", class targettype = "BossSpot", class fogtype = "TeleportFog", int flags = 0, float mindist = 0, float maxdist = 0); action native A_Warp(int ptr_destination, float xofs = 0, float yofs = 0, float zofs = 0, float angle = 0, int flags = 0, state success_state = ""); action native A_ThrowGrenade(class itemtype, float zheight = 0, float xyvel = 0, float zvel = 0, bool useammo = true); action native A_Weave(int xspeed, int yspeed, float xdist, float ydist); @@ -281,9 +279,6 @@ ACTOR Actor native //: Thinker action native A_CheckLOF(state jump, int flags = 0, float range = 0, float minrange = 0, float angle = 0, float pitch = 0, float offsetheight = 0, float offsetwidth = 0, int ptr_target = AAPTR_DEFAULT); action native A_JumpIfTargetInLOS (state label, float/*angle*/ fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0); action native A_JumpIfInTargetLOS (state label, float/*angle*/ fov = 0, int flags = 0, float dist_max = 0, float dist_close = 0); - action native A_DamageMaster(int amount, name damagetype = "none", int flags = 0); - action native A_DamageChildren(int amount, name damagetype = "none", int flags = 0); - action native A_DamageSiblings(int amount, name damagetype = "none", int flags = 0); action native A_SelectWeapon(class whichweapon); action native A_Punch(); action native A_Feathers(); @@ -297,10 +292,11 @@ ACTOR Actor native //: Thinker action native A_DropWeaponPieces(class p1, class p2, class p3); action native A_PigPain (); action native A_MonsterRefire(int chance, state label); - action native A_SetAngle(float angle = 0, int flags = 0); - action native A_SetPitch(float pitch, int flags = 0); - action native A_ScaleVelocity(float scale); - action native A_ChangeVelocity(float x = 0, float y = 0, float z = 0, int flags = 0); + action native A_SetAngle(float angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT); + action native A_SetPitch(float pitch, int flags = 0, int ptr = AAPTR_DEFAULT); + action native A_SetRoll(float/*angle*/ roll, int flags = 0, int ptr = AAPTR_DEFAULT); + action native A_ScaleVelocity(float scale, int ptr = AAPTR_DEFAULT); + action native A_ChangeVelocity(float x = 0, float y = 0, float z = 0, int flags = 0, int ptr = AAPTR_DEFAULT); action native A_SetArg(int pos, int value); action native A_SetUserVar(name varname, int value); action native A_SetUserArray(name varname, int index, int value); @@ -309,24 +305,39 @@ ACTOR Actor native //: Thinker action native A_SetTics(int tics); action native A_SetDamageType(name damagetype); action native A_DropItem(class item, int dropamount = -1, int chance = 256); - action native A_SetSpeed(float speed); - action native A_DamageSelf(int amount, name damagetype = "none", int flags = 0); - action native A_DamageTarget(int amount, name damagetype = "none", int flags = 0); - action native A_DamageTracer(int amount, name damagetype = "none", int flags = 0); - action native A_KillTarget(name damagetype = "none", int flags = 0); - action native A_KillTracer(name damagetype = "none", int flags = 0); - action native A_RemoveTarget(int flags = 0); - action native A_RemoveTracer(int flags = 0); - action native A_Remove(int removee, int flags = 0); + action native A_SetSpeed(float speed, int ptr = AAPTR_DEFAULT); + action native A_DamageSelf(int amount, name damagetype = "none", int flags = 0, class filter = "None", name species = "None"); + action native A_DamageTarget(int amount, name damagetype = "none", int flags = 0, class filter = "None", name species = "None"); + action native A_DamageMaster(int amount, name damagetype = "none", int flags = 0, class filter = "None", name species = "None"); + action native A_DamageTracer(int amount, name damagetype = "none", int flags = 0, class filter = "None", name species = "None"); + action native A_DamageChildren(int amount, name damagetype = "none", int flags = 0, class filter = "None", name species = "None"); + action native A_DamageSiblings(int amount, name damagetype = "none", int flags = 0, class filter = "None", name species = "None"); + action native A_KillTarget(name damagetype = "none", int flags = 0, class filter = "None", name species = "None"); + action native A_KillMaster(name damagetype = "none", int flags = 0, class filter = "None", name species = "None"); + action native A_KillTracer(name damagetype = "none", int flags = 0, class filter = "None", name species = "None"); + action native A_KillChildren(name damagetype = "none", int flags = 0, class filter = "None", name species = "None"); + action native A_KillSiblings(name damagetype = "none", int flags = 0, class filter = "None", name species = "None"); + action native A_RemoveTarget(int flags = 0, class filter = "None", name species = "None"); + action native A_RemoveMaster(int flags = 0, class filter = "None", name species = "None"); + action native A_RemoveTracer(int flags = 0, class filter = "None", name species = "None"); + action native A_RemoveChildren(bool removeall = false, int flags = 0, class filter = "None", name species = "None"); + action native A_RemoveSiblings(bool removeall = false, int flags = 0, class filter = "None", name species = "None"); + action native A_Remove(int removee, int flags = 0, class filter = "None", name species = "None"); action native A_GiveToChildren(class itemtype, int amount = 0); action native A_GiveToSiblings(class itemtype, int amount = 0); action native A_TakeFromChildren(class itemtype, int amount = 0); action native A_TakeFromSiblings(class itemtype, int amount = 0); action native A_SetTeleFog(name oldpos, name newpos); action native A_SwapTeleFog(); + action native A_SetFloatBobPhase(int bob); + action native A_SetHealth(int health, int ptr = AAPTR_DEFAULT); + action native A_ResetHealth(int ptr = AAPTR_DEFAULT); + action native A_SetRipperLevel(int level); + action native A_SetRipMin(int min); + action native A_SetRipMax(int max); - action native A_CheckSightOrRange(float distance, state label); - action native A_CheckRange(float distance, state label); + action native A_CheckSightOrRange(float distance, state label, bool two_dimension = false); + action native A_CheckRange(float distance, state label, bool two_dimension = false); action native A_RearrangePointers(int newtarget, int newmaster = AAPTR_DEFAULT, int newtracer = AAPTR_DEFAULT, int flags=0); action native A_TransferPointer(int ptr_source, int ptr_recepient, int sourcefield, int recepientfield=AAPTR_DEFAULT, int flags=0); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 75af8e747..0b792fa13 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -345,8 +345,10 @@ Const Int WARPF_TOFLOOR = 0x100; Const Int WARPF_TESTONLY = 0x200; Const Int WAPRF_ABSOLUTEPOSITION = 0x400; Const Int WARPF_ABSOLUTEPOSITION = 0x400; +Const Int WARPF_BOB = 0x800; +Const Int WARPF_MOVEPTR = 0x1000; -// flags for A_SetPitch/SetAngle +// flags for A_SetPitch/SetAngle/SetRoll const int SPF_FORCECLAMP = 1; const int SPF_INTERPOLATE = 2; @@ -396,19 +398,30 @@ enum }; // Flags for A_Kill (Master/Target/Tracer/Children/Siblings) series - -const int KILS_FOILINVUL = 1; -const int KILS_KILLMISSILES = 2; -const int KILS_NOMONSTERS = 4; -const int KILS_FOILBUDDHA = 8; +enum +{ + KILS_FOILINVUL = 0x00000001, + KILS_KILLMISSILES = 0x00000002, + KILS_NOMONSTERS = 0x00000004, + KILS_FOILBUDDHA = 0x00000008, + KILS_EXFILTER = 0x00000010, + KILS_EXSPECIES = 0x00000020, + KILS_EITHER = 0x00000040, +}; // Flags for A_Damage (Master/Target/Tracer/Children/Siblings/Self) series -const int DMSS_FOILINVUL = 1; -const int DMSS_AFFECTARMOR = 2; -const int DMSS_KILL = 4; -const int DMSS_NOFACTOR = 8; -const int DMSS_FOILBUDDHA = 16; -const int DMSS_NOPROTECT = 32; +enum +{ + DMSS_FOILINVUL = 0x00000001, + DMSS_AFFECTARMOR = 0x00000002, + DMSS_KILL = 0x00000004, + DMSS_NOFACTOR = 0x00000008, + DMSS_FOILBUDDHA = 0x00000010, + DMSS_NOPROTECT = 0x00000020, + DMSS_EXFILTER = 0x00000040, + DMSS_EXSPECIES = 0x00000080, + DMSS_EITHER = 0x00000100, +}; // Flags for A_AlertMonsters const int AMF_TARGETEMITTER = 1; @@ -418,10 +431,13 @@ const int AMF_EMITFROMTARGET = 4; // Flags for A_Remove* enum { - RMVF_MISSILES = 1 << 0, - RMVF_NOMONSTERS = 1 << 1, - RMVF_MISC = 1 << 2, - RMVF_EVERYTHING = 1 << 3, + RMVF_MISSILES = 0x00000001, + RMVF_NOMONSTERS = 0x00000002, + RMVF_MISC = 0x00000004, + RMVF_EVERYTHING = 0x00000008, + RMVF_EXFILTER = 0x00000010, + RMVF_EXSPECIES = 0x00000020, + RMVF_EITHER = 0x00000040, }; // Flags for A_Fade* diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 4e33029b4..978480e4d 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1586,6 +1586,10 @@ OptionMenu VideoModeMenu Title "VIDEO MODE" Option "Fullscreen", "fullscreen", "YesNo" + IfOption(Mac) + { + Option "Retina/HiDPI support", "vid_hidpi", "YesNo" + } Option "Aspect ratio", "menu_screenratios", "Ratios" Option "Force aspect ratio", "vid_aspect", "ForceRatios" Option "Enable 5:4 aspect ratio","vid_tft", "YesNo"