diff --git a/platform/macosx/OSX.h b/platform/macosx/OSX.h new file mode 100644 index 000000000..95847462e --- /dev/null +++ b/platform/macosx/OSX.h @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#ifndef LOVE_OSX_H +#define LOVE_OSX_H + +#include + +namespace love +{ +namespace osx +{ + +/** + * Returns the filepath of the first detected love file in the Resources folder + * in love.app. + * Returns an empty string if no love file is found. + **/ +std::string getLoveInResources(); + +/** + * Checks for drop-file events. Returns the filepath if an event occurred, or + * an empty string otherwise. + **/ +std::string checkDropEvents(); + +} // osx +} // love + +#endif // LOVE_OSX_H diff --git a/platform/macosx/OSX.mm b/platform/macosx/OSX.mm new file mode 100644 index 000000000..6065e7926 --- /dev/null +++ b/platform/macosx/OSX.mm @@ -0,0 +1,72 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#import "osx.h" +#import + +#include + +namespace love +{ +namespace osx +{ + +std::string getLoveInResources() +{ + std::string path; + + // check to see if there are any .love files in Resources - props to stevejohnson/diordna + NSArray *lovePaths = [[NSBundle mainBundle] pathsForResourcesOfType:@"love" inDirectory:nil]; + if ([lovePaths count] > 0) + { + NSString *firstLovePath = [lovePaths objectAtIndex:0]; + path = std::string([firstLovePath UTF8String]); + } + + return path; +} + +std::string checkDropEvents() +{ + std::string dropstr; + SDL_Event event; + + bool initvideo = SDL_WasInit(SDL_INIT_VIDEO) != 0; + if (!initvideo) + SDL_InitSubSystem(SDL_INIT_VIDEO); + + SDL_PumpEvents(); + if (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_DROPFILE, SDL_DROPFILE) > 0) + { + if (event.type == SDL_DROPFILE) + { + dropstr = std::string(event.drop.file); + SDL_free(event.drop.file); + } + } + + if (!initvideo) + SDL_QuitSubSystem(SDL_INIT_VIDEO); + + return dropstr; +} + +} // osx +} // love diff --git a/platform/macosx/SDLMain.h b/platform/macosx/SDLMain.h deleted file mode 100644 index ec8e148c3..000000000 --- a/platform/macosx/SDLMain.h +++ /dev/null @@ -1,12 +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 -#include "SDL/SDL.h" - -@interface SDLMain : NSObject -@end diff --git a/platform/macosx/SDLMain.m b/platform/macosx/SDLMain.m deleted file mode 100644 index 4adae7219..000000000 --- a/platform/macosx/SDLMain.m +++ /dev/null @@ -1,464 +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 "SDLMain.h" -#import /* for MAXPATHLEN */ -#import - -/* 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 */ -/* We can't submit to the Mac App Store with this enabled: */ -/* http://www.philhassey.com/blog/2011/02/ */ -/*#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); -} - -/* Hack to make Cocoa ignore keystrokes that aren't shortcuts, otherwise it beeps on every key press */ -- (void)sendEvent:(NSEvent *)theEvent { - if (NSKeyDown == [theEvent type] || NSKeyUp == [theEvent type]) { - if ([theEvent modifierFlags] & NSCommandKeyMask) - [super sendEvent: theEvent]; - } else { - [super sendEvent: theEvent]; - } -} -@end - -/* The main class of the application, the application's delegate */ -@implementation SDLMain - -/* Set the working directory to the .app's parent directory */ -/*CHANGED to Bundle's Resource Directory. */ -- (void) setupWorkingDirectory:(BOOL)shouldChdir -{ - if (shouldChdir) - { - /* - char parentdir[PATH_MAX]; - //CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); - CFURLRef url = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); - CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url); - if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, PATH_MAX)) { - assert ( chdir (parentdir) == 0 ); // chdir to the binary app's parent // - } - CFRelease(url); - CFRelease(url2); - */ - CFBundleRef mainBundle = CFBundleGetMainBundle(); - CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle); - char path[PATH_MAX]; - if (!CFURLGetFileSystemRepresentation(resourcesURL, TRUE, (UInt8 *)path, PATH_MAX)) - { - // error! - } - CFRelease(resourcesURL); - chdir(path); - } - -} - -#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]; - - /* 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]; - } -#else - { - ProcessSerialNumber psn; - - if (!GetCurrentProcess(&psn)) { - TransformProcessType(&psn, kProcessTransformToForegroundApplication); - SetFrontProcess(&psn); - } - } -#endif /* SDL_USE_CPS */ - - /* Set up the menubar */ - [NSApp setMainMenu:[[[NSMenu alloc] init] autorelease]]; - 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; - - // Disabled because the method for detecting this doesn't work in OS 10.9. -// 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 Resources folder */ - [self setupWorkingDirectory:gCalledAppMainline]; - -#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 - - /* Set up the app to receive menu events via keyboard shortcut */ - setenv("SDL_ENABLEAPPEVENTS", "1", 1); - - /* 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; - } - - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - /* check to see if there are any .love files in Resources - props to stevejohnson/diordna */ - NSArray *lovePaths = [[NSBundle mainBundle] pathsForResourcesOfType:@"love" inDirectory:nil]; - - if ([lovePaths count] > 0) /* there are, load the first one we found and run it */ - { - NSString *firstLovePath = [lovePaths objectAtIndex:0]; - gCalledAppMainline = YES; - - const char *temparg; - size_t arglen; - char *arg; - char **newargv; - - temparg = [firstLovePath UTF8String]; - arglen = SDL_strlen(temparg) + 1; - - arg = (char *)SDL_malloc(arglen); - if (arg == NULL) - return FALSE; - - const char *fusedstr = "--fused"; - size_t fusedarglen = SDL_strlen(fusedstr) + 1; - - char *fusedarg = (char *) SDL_malloc(fusedarglen); - if (fusedarg == NULL) - { - SDL_free(arg); - return FALSE; - } - - newargv = (char **) realloc(gArgv, sizeof(char *) * (gArgc + 3)); - if (newargv == NULL) - { - SDL_free(arg); - SDL_free(fusedarg); - return FALSE; - } - - gArgv = newargv; - SDL_strlcpy(arg, temparg, arglen); - SDL_strlcpy(fusedarg, fusedstr, fusedarglen); - gArgv[gArgc++] = arg; - gArgv[gArgc++] = fusedarg; // run in pseudo-fused mode - gArgv[gArgc] = NULL; - } - - [pool drain]; - -#if SDL_USE_NIB_FILE - [SDLApplication poseAsClass:[NSApplication class]]; - NSApplicationMain (argc, argv); -#else - CustomApplicationMain (argc, argv); -#endif - return 0; -} diff --git a/platform/macosx/love-framework.xcodeproj/project.pbxproj b/platform/macosx/love-framework.xcodeproj/project.pbxproj index 09d70a6a3..440ad1029 100644 --- a/platform/macosx/love-framework.xcodeproj/project.pbxproj +++ b/platform/macosx/love-framework.xcodeproj/project.pbxproj @@ -135,9 +135,8 @@ FA08F63016C7542600F007B5 /* DevilHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AA7781A230065F346E2313A /* DevilHandler.cpp */; }; FA08F63116C7542600F007B5 /* wrap_Image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0B0728FA73B107B37A956A09 /* wrap_Image.cpp */; }; FA08F63216C7542600F007B5 /* wrap_ImageData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 076840774B0B6E721D0C18D0 /* wrap_ImageData.cpp */; }; - FA08F63316C7542D00F007B5 /* Joystick.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 677F545C76EA3B247329358D /* Joystick.cpp */; }; - FA08F63416C7542D00F007B5 /* Joystick.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 55B425307C0C1C4B3EFC3A5F /* Joystick.cpp */; }; - FA08F63516C7542D00F007B5 /* wrap_Joystick.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 139411436818381E493F00F5 /* wrap_Joystick.cpp */; }; + FA08F63416C7542D00F007B5 /* JoystickModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 55B425307C0C1C4B3EFC3A5F /* JoystickModule.cpp */; }; + FA08F63516C7542D00F007B5 /* wrap_JoystickModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 139411436818381E493F00F5 /* wrap_JoystickModule.cpp */; }; FA08F63616C7543400F007B5 /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 524741891BB93848039F4174 /* Keyboard.cpp */; }; FA08F63716C7543400F007B5 /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 43BC2B1C505E5EFF650C31E3 /* Keyboard.cpp */; }; FA08F63816C7543400F007B5 /* wrap_Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 19F40DF6507028212FEB1D77 /* wrap_Keyboard.cpp */; }; @@ -208,6 +207,18 @@ FA08F67B16C754BA00F007B5 /* Window.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 351B09E51FDC338622F44624 /* Window.cpp */; }; FA08F67C16C754BA00F007B5 /* Window.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6CDD4F3320303D222C180CD0 /* Window.cpp */; }; FA0CDE3D1710F9A50056E8D7 /* FormatHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0CDE3B1710F9A50056E8D7 /* FormatHandler.h */; }; + FA1EF7C41799FEAC00FF380C /* wrap_System.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA34E7D4174B55AF00E04D3F /* wrap_System.cpp */; }; + FA1EF7C51799FEB200FF380C /* wrap_System.h in Headers */ = {isa = PBXBuildFile; fileRef = FA34E7D5174B55AF00E04D3F /* wrap_System.h */; }; + FA34E7CD174B513F00E04D3F /* System.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA34E7CB174B513F00E04D3F /* System.cpp */; }; + FA34E7CE174B513F00E04D3F /* System.h in Headers */ = {isa = PBXBuildFile; fileRef = FA34E7CC174B513F00E04D3F /* System.h */; }; + FA34E7D2174B515D00E04D3F /* System.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA34E7D0174B515D00E04D3F /* System.cpp */; }; + FA34E7D3174B515D00E04D3F /* System.h in Headers */ = {isa = PBXBuildFile; fileRef = FA34E7D1174B515D00E04D3F /* System.h */; }; + FA3D9E0D16E68DE600CA6630 /* Cursor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA3D9E0B16E68DE600CA6630 /* Cursor.cpp */; }; + FA3D9E0E16E68DE600CA6630 /* Cursor.h in Headers */ = {isa = PBXBuildFile; fileRef = FA3D9E0C16E68DE600CA6630 /* Cursor.h */; }; + FA3D9E1116E68EAE00CA6630 /* Cursor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA3D9E0F16E68EAE00CA6630 /* Cursor.cpp */; }; + FA3D9E1216E68EAE00CA6630 /* Cursor.h in Headers */ = {isa = PBXBuildFile; fileRef = FA3D9E1016E68EAE00CA6630 /* Cursor.h */; }; + FA3D9E1516E6D41100CA6630 /* wrap_Cursor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA3D9E1316E6D41000CA6630 /* wrap_Cursor.cpp */; }; + FA3D9E1616E6D41100CA6630 /* wrap_Cursor.h in Headers */ = {isa = PBXBuildFile; fileRef = FA3D9E1416E6D41000CA6630 /* wrap_Cursor.h */; }; FA435EA317B36E9C004C3F22 /* Polyline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA435EA117B36E9C004C3F22 /* Polyline.cpp */; }; FA435EA417B36E9C004C3F22 /* Polyline.h in Headers */ = {isa = PBXBuildFile; fileRef = FA435EA217B36E9C004C3F22 /* Polyline.h */; }; FA5454C216F1310000D30303 /* MathModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA5454C016F1310000D30303 /* MathModule.cpp */; }; @@ -222,7 +233,6 @@ FA577AC816C7513C00860150 /* Ogg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A7116C719F400860150 /* Ogg.framework */; }; FA577ACA16C7514100860150 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A7C16C71A2600860150 /* OpenGL.framework */; }; FA577ACB16C7514400860150 /* physfs.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A7316C719F900860150 /* physfs.framework */; }; - FA577ACC16C7514700860150 /* SDL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A7516C719FF00860150 /* SDL.framework */; }; FA577ACD16C7514C00860150 /* Vorbis.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A7716C71A0800860150 /* Vorbis.framework */; }; FA5FDC791788D548002F0ED2 /* enet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA5FDC5F1788D548002F0ED2 /* enet.cpp */; }; FA5FDC7A1788D548002F0ED2 /* callbacks.c in Sources */ = {isa = PBXBuildFile; fileRef = FA5FDC611788D548002F0ED2 /* callbacks.c */; }; @@ -251,11 +261,18 @@ FA7175AA178E8418001FE7FE /* lua.h in Headers */ = {isa = PBXBuildFile; fileRef = FA7175A9178E8418001FE7FE /* lua.h */; }; FA7C937A16DCC6C2006F2BEE /* wrap_Math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA7C937516DCC6C2006F2BEE /* wrap_Math.cpp */; }; FA7C937B16DCC6C2006F2BEE /* wrap_Math.h in Headers */ = {isa = PBXBuildFile; fileRef = FA7C937616DCC6C2006F2BEE /* wrap_Math.h */; }; + FA9B4A0816E1578300074F42 /* SDL2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA9B4A0716E1578300074F42 /* SDL2.framework */; }; FA9FC0B0173D6E3E005027FF /* wrap_Window.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA9FC0AE173D6E3E005027FF /* wrap_Window.cpp */; }; FA9FC0B1173D6E3E005027FF /* wrap_Window.h in Headers */ = {isa = PBXBuildFile; fileRef = FA9FC0AF173D6E3E005027FF /* wrap_Window.h */; }; FAAC6B02170A373B008A61C5 /* CompressedData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAAC6B00170A373A008A61C5 /* CompressedData.cpp */; }; FAAC6B03170A373B008A61C5 /* CompressedData.h in Headers */ = {isa = PBXBuildFile; fileRef = FAAC6B01170A373A008A61C5 /* CompressedData.h */; }; FAAFF04416CB11C700CCDE45 /* OpenAL-Soft.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAAFF04316CB11C700CCDE45 /* OpenAL-Soft.framework */; }; + FAB0078F1740C12D00A9664D /* Joystick.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAB0078D1740C12D00A9664D /* Joystick.cpp */; }; + FAB007901740C12D00A9664D /* Joystick.h in Headers */ = {isa = PBXBuildFile; fileRef = FAB0078E1740C12D00A9664D /* Joystick.h */; }; + FAB007931740C28900A9664D /* Joystick.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAB007911740C28900A9664D /* Joystick.cpp */; }; + FAB007941740C28900A9664D /* Joystick.h in Headers */ = {isa = PBXBuildFile; fileRef = FAB007921740C28900A9664D /* Joystick.h */; }; + FAB007971740C87D00A9664D /* wrap_Joystick.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAB007951740C87D00A9664D /* wrap_Joystick.cpp */; }; + FAB007981740C87D00A9664D /* wrap_Joystick.h in Headers */ = {isa = PBXBuildFile; fileRef = FAB007961740C87D00A9664D /* wrap_Joystick.h */; }; FAC5710017402D1100D147E4 /* BezierCurve.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAC570FC17402D1100D147E4 /* BezierCurve.cpp */; }; FAC5710117402D1100D147E4 /* BezierCurve.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC570FD17402D1100D147E4 /* BezierCurve.h */; }; FAC5710217402D1100D147E4 /* wrap_BezierCurve.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAC570FE17402D1100D147E4 /* wrap_BezierCurve.cpp */; }; @@ -373,7 +390,7 @@ 131F69C3368C4B8A55EE0DAD /* wrap_WeldJoint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = wrap_WeldJoint.h; sourceTree = ""; }; 135801A6483528800C676492 /* io.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = io.c; sourceTree = ""; }; 138913BE5126483748FA43D0 /* Joint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Joint.h; sourceTree = ""; }; - 139411436818381E493F00F5 /* wrap_Joystick.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Joystick.cpp; sourceTree = ""; }; + 139411436818381E493F00F5 /* wrap_JoystickModule.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_JoystickModule.cpp; sourceTree = ""; }; 14AE68E14C2C74526A612FA0 /* wrap_Image.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Image.cpp; sourceTree = ""; }; 15093E1B1A14176374C81299 /* wrap_CircleShape.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = wrap_CircleShape.h; sourceTree = ""; }; 153957EB332E1269671E7F4A /* b2CircleShape.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = b2CircleShape.h; sourceTree = ""; }; @@ -453,7 +470,7 @@ 2CAE75B079B828FE6892684A /* udp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = udp.h; sourceTree = ""; }; 2CEC5ED5211174C7583849AD /* Reference.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Reference.h; sourceTree = ""; }; 2D290E902C451D6849051FEF /* b2WeldJoint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = b2WeldJoint.h; sourceTree = ""; }; - 2D7B7DEC4FC87878332E41B3 /* wrap_Joystick.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = wrap_Joystick.h; sourceTree = ""; }; + 2D7B7DEC4FC87878332E41B3 /* wrap_JoystickModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = wrap_JoystickModule.h; sourceTree = ""; }; 2D8E6FAE2A100B5866E96BFF /* runtime.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = runtime.h; sourceTree = ""; }; 2D9475890CDA3D3776435622 /* Timer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Timer.h; sourceTree = ""; }; 2DC90F3C6160198256795C75 /* luasocket.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = luasocket.cpp; sourceTree = ""; }; @@ -523,7 +540,7 @@ 415E1438178736BE0EA908D5 /* select.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = select.c; sourceTree = ""; }; 426B1C4475DC54505B824B7F /* VertexBuffer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = VertexBuffer.cpp; sourceTree = ""; }; 427B4B2517C0516844370E3D /* b2CollidePolygon.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = b2CollidePolygon.cpp; sourceTree = ""; }; - 439E46D768A266780E894800 /* Joystick.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Joystick.h; sourceTree = ""; }; + 439E46D768A266780E894800 /* JoystickModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JoystickModule.h; sourceTree = ""; }; 43A258C229C75C15238E520C /* Decoder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Decoder.h; sourceTree = ""; }; 43BC2B1C505E5EFF650C31E3 /* Keyboard.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Keyboard.cpp; sourceTree = ""; }; 448C492C7AEB7840504F1C9D /* b2EdgeShape.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = b2EdgeShape.h; sourceTree = ""; }; @@ -554,7 +571,7 @@ 4B41232F7AF7793540F46C58 /* timeout.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = timeout.c; sourceTree = ""; }; 4B5F4DF8110020A96B5D3EAB /* b2BroadPhase.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = b2BroadPhase.cpp; sourceTree = ""; }; 4B731754147B27AF73AC5358 /* Volatile.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Volatile.cpp; sourceTree = ""; }; - 4C606AEC342457600C3F0741 /* Joystick.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Joystick.h; sourceTree = ""; }; + 4C606AEC342457600C3F0741 /* JoystickModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JoystickModule.h; sourceTree = ""; }; 4D700D182EAA46273D1E2CC4 /* SpriteBatch.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SpriteBatch.cpp; sourceTree = ""; }; 4D81102E7ABD1C282BE42CE3 /* wrap_MouseJoint.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_MouseJoint.cpp; sourceTree = ""; }; 4DAB28A9235E2CBE75F56848 /* CircleShape.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CircleShape.cpp; sourceTree = ""; }; @@ -585,7 +602,7 @@ 54E85987318206E93DC8189F /* PolygonShape.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PolygonShape.cpp; sourceTree = ""; }; 55A759CE711E157339930E58 /* b2BlockAllocator.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = b2BlockAllocator.cpp; sourceTree = ""; }; 55AE226405CC1A55462E1D89 /* threads.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = threads.h; sourceTree = ""; }; - 55B425307C0C1C4B3EFC3A5F /* Joystick.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Joystick.cpp; sourceTree = ""; }; + 55B425307C0C1C4B3EFC3A5F /* JoystickModule.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = JoystickModule.cpp; sourceTree = ""; }; 561D4A4722E36BAA16D17CC8 /* EdgeShape.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EdgeShape.h; sourceTree = ""; }; 567C0A0C58931DE54733011B /* b2StackAllocator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = b2StackAllocator.h; sourceTree = ""; }; 56D6030A0B8F7397715062B9 /* Image.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Image.cpp; sourceTree = ""; }; @@ -641,7 +658,6 @@ 6590063A6E4B3AEF4550443C /* b2GearJoint.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = b2GearJoint.h; sourceTree = ""; }; 66EC3C0463A703A97445193B /* b2PulleyJoint.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = b2PulleyJoint.cpp; sourceTree = ""; }; 66F8479E6D2D587A592F2024 /* socket.lua.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = socket.lua.h; sourceTree = ""; }; - 677F545C76EA3B247329358D /* Joystick.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Joystick.cpp; sourceTree = ""; }; 678E42771C9B415628A3234D /* wrap_ParticleSystem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = wrap_ParticleSystem.h; sourceTree = ""; }; 68616BD516DB124312B47EB3 /* Image.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Image.h; sourceTree = ""; }; 691C5C5828550E2F60754EF2 /* wrap_Event.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Event.cpp; sourceTree = ""; }; @@ -722,6 +738,18 @@ FA03546B1731F3A700284828 /* simplexnoise1234.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = simplexnoise1234.h; sourceTree = ""; }; FA08F5AE16C7525600F007B5 /* Info-Framework.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-Framework.plist"; sourceTree = ""; }; FA0CDE3B1710F9A50056E8D7 /* FormatHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FormatHandler.h; sourceTree = ""; }; + FA34E7CB174B513F00E04D3F /* System.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = System.cpp; sourceTree = ""; }; + FA34E7CC174B513F00E04D3F /* System.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = System.h; sourceTree = ""; }; + FA34E7D0174B515D00E04D3F /* System.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = System.cpp; sourceTree = ""; }; + FA34E7D1174B515D00E04D3F /* System.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = System.h; sourceTree = ""; }; + FA34E7D4174B55AF00E04D3F /* wrap_System.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_System.cpp; sourceTree = ""; }; + FA34E7D5174B55AF00E04D3F /* wrap_System.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_System.h; sourceTree = ""; }; + FA3D9E0B16E68DE600CA6630 /* Cursor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cursor.cpp; sourceTree = ""; }; + FA3D9E0C16E68DE600CA6630 /* Cursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Cursor.h; sourceTree = ""; }; + FA3D9E0F16E68EAE00CA6630 /* Cursor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cursor.cpp; sourceTree = ""; }; + FA3D9E1016E68EAE00CA6630 /* Cursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Cursor.h; sourceTree = ""; }; + FA3D9E1316E6D41000CA6630 /* wrap_Cursor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Cursor.cpp; sourceTree = ""; }; + FA3D9E1416E6D41000CA6630 /* wrap_Cursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Cursor.h; sourceTree = ""; }; FA435EA117B36E9C004C3F22 /* Polyline.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Polyline.cpp; sourceTree = ""; }; FA435EA217B36E9C004C3F22 /* Polyline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Polyline.h; sourceTree = ""; }; FA5454C016F1310000D30303 /* MathModule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MathModule.cpp; sourceTree = ""; }; @@ -733,7 +761,6 @@ FA577A6F16C719F000860150 /* mpg123.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = mpg123.framework; path = /Library/Frameworks/mpg123.framework; sourceTree = ""; }; FA577A7116C719F400860150 /* Ogg.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Ogg.framework; path = /Library/Frameworks/Ogg.framework; sourceTree = ""; }; FA577A7316C719F900860150 /* physfs.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = physfs.framework; path = /Library/Frameworks/physfs.framework; sourceTree = ""; }; - FA577A7516C719FF00860150 /* SDL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL.framework; path = /Library/Frameworks/SDL.framework; sourceTree = ""; }; FA577A7716C71A0800860150 /* Vorbis.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Vorbis.framework; path = /Library/Frameworks/Vorbis.framework; sourceTree = ""; }; FA577A7916C71A1700860150 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; FA577A7C16C71A2600860150 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = ""; }; @@ -773,11 +800,18 @@ FA7175A9178E8418001FE7FE /* lua.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lua.h; sourceTree = ""; }; FA7C937516DCC6C2006F2BEE /* wrap_Math.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Math.cpp; sourceTree = ""; }; FA7C937616DCC6C2006F2BEE /* wrap_Math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Math.h; sourceTree = ""; }; + FA9B4A0716E1578300074F42 /* SDL2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2.framework; path = /Library/Frameworks/SDL2.framework; sourceTree = ""; }; FA9FC0AE173D6E3E005027FF /* wrap_Window.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Window.cpp; sourceTree = ""; }; FA9FC0AF173D6E3E005027FF /* wrap_Window.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Window.h; sourceTree = ""; }; FAAC6B00170A373A008A61C5 /* CompressedData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CompressedData.cpp; sourceTree = ""; }; FAAC6B01170A373A008A61C5 /* CompressedData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CompressedData.h; sourceTree = ""; }; FAAFF04316CB11C700CCDE45 /* OpenAL-Soft.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "OpenAL-Soft.framework"; path = "/Library/Frameworks/OpenAL-Soft.framework"; sourceTree = ""; }; + FAB0078D1740C12D00A9664D /* Joystick.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Joystick.cpp; sourceTree = ""; }; + FAB0078E1740C12D00A9664D /* Joystick.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Joystick.h; sourceTree = ""; }; + FAB007911740C28900A9664D /* Joystick.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Joystick.cpp; sourceTree = ""; }; + FAB007921740C28900A9664D /* Joystick.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Joystick.h; sourceTree = ""; }; + FAB007951740C87D00A9664D /* wrap_Joystick.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Joystick.cpp; sourceTree = ""; }; + FAB007961740C87D00A9664D /* wrap_Joystick.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Joystick.h; sourceTree = ""; }; FAC570FC17402D1100D147E4 /* BezierCurve.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BezierCurve.cpp; sourceTree = ""; }; FAC570FD17402D1100D147E4 /* BezierCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BezierCurve.h; sourceTree = ""; }; FAC570FE17402D1100D147E4 /* wrap_BezierCurve.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_BezierCurve.cpp; sourceTree = ""; }; @@ -822,6 +856,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + FA9B4A0816E1578300074F42 /* SDL2.framework in Frameworks */, FAAFF04416CB11C700CCDE45 /* OpenAL-Soft.framework in Frameworks */, FA577AB016C7507900860150 /* Cocoa.framework in Frameworks */, FA577AC216C7512D00860150 /* FreeType.framework in Frameworks */, @@ -833,7 +868,6 @@ FA577AC816C7513C00860150 /* Ogg.framework in Frameworks */, FA577ACA16C7514100860150 /* OpenGL.framework in Frameworks */, FA577ACB16C7514400860150 /* physfs.framework in Frameworks */, - FA577ACC16C7514700860150 /* SDL.framework in Frameworks */, FA577ACD16C7514C00860150 /* Vorbis.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -952,9 +986,13 @@ 130737AF4BD12D0356A65C87 /* mouse */ = { isa = PBXGroup; children = ( + FA3D9E0B16E68DE600CA6630 /* Cursor.cpp */, + FA3D9E0C16E68DE600CA6630 /* Cursor.h */, 31E0110E5797041465FF5F95 /* Mouse.cpp */, 63A63DFB339266AC401B545A /* Mouse.h */, 1E017A8673D531394B5A3B16 /* sdl */, + FA3D9E1316E6D41000CA6630 /* wrap_Cursor.cpp */, + FA3D9E1416E6D41000CA6630 /* wrap_Cursor.h */, 22EF17981EBD442773FE41B6 /* wrap_Mouse.cpp */, 4E972C114A6C25A63B5B6EF2 /* wrap_Mouse.h */, ); @@ -1080,6 +1118,8 @@ 1E017A8673D531394B5A3B16 /* sdl */ = { isa = PBXGroup; children = ( + FA3D9E0F16E68EAE00CA6630 /* Cursor.cpp */, + FA3D9E1016E68EAE00CA6630 /* Cursor.h */, 584E16AE09E12536206C46FE /* Mouse.cpp */, 198A44BD71BB61EE517C2A39 /* Mouse.h */, ); @@ -1344,8 +1384,9 @@ 501126AD67DC2A4B527654EA /* joystick */ = { isa = PBXGroup; children = ( - 677F545C76EA3B247329358D /* Joystick.cpp */, - 4C606AEC342457600C3F0741 /* Joystick.h */, + FAB0078D1740C12D00A9664D /* Joystick.cpp */, + FAB0078E1740C12D00A9664D /* Joystick.h */, + 4C606AEC342457600C3F0741 /* JoystickModule.h */, 687216AD6FA406C838284B91 /* sdl */, ); path = joystick; @@ -1381,6 +1422,7 @@ 130737AF4BD12D0356A65C87 /* mouse */, 67F10C1D58A96C1C53563B5C /* physics */, 4BAB08EE4A6B4A1A01DA50A4 /* sound */, + FA34E7CA174B512200E04D3F /* system */, 02E0744773D13AD65E7C49DC /* thread */, 6D590DDD41E72A60262E4A4F /* timer */, 153D76205F7A4ACD12FB4C0E /* window */, @@ -1522,10 +1564,14 @@ 687216AD6FA406C838284B91 /* sdl */ = { isa = PBXGroup; children = ( - 55B425307C0C1C4B3EFC3A5F /* Joystick.cpp */, - 439E46D768A266780E894800 /* Joystick.h */, - 139411436818381E493F00F5 /* wrap_Joystick.cpp */, - 2D7B7DEC4FC87878332E41B3 /* wrap_Joystick.h */, + FAB007911740C28900A9664D /* Joystick.cpp */, + FAB007921740C28900A9664D /* Joystick.h */, + 55B425307C0C1C4B3EFC3A5F /* JoystickModule.cpp */, + 439E46D768A266780E894800 /* JoystickModule.h */, + FAB007951740C87D00A9664D /* wrap_Joystick.cpp */, + FAB007961740C87D00A9664D /* wrap_Joystick.h */, + 139411436818381E493F00F5 /* wrap_JoystickModule.cpp */, + 2D7B7DEC4FC87878332E41B3 /* wrap_JoystickModule.h */, ); path = sdl; sourceTree = ""; @@ -1708,9 +1754,31 @@ name = Resources; sourceTree = ""; }; + FA34E7CA174B512200E04D3F /* system */ = { + isa = PBXGroup; + children = ( + FA34E7CF174B514F00E04D3F /* sdl */, + FA34E7CB174B513F00E04D3F /* System.cpp */, + FA34E7CC174B513F00E04D3F /* System.h */, + FA34E7D4174B55AF00E04D3F /* wrap_System.cpp */, + FA34E7D5174B55AF00E04D3F /* wrap_System.h */, + ); + path = system; + sourceTree = ""; + }; + FA34E7CF174B514F00E04D3F /* sdl */ = { + isa = PBXGroup; + children = ( + FA34E7D0174B515D00E04D3F /* System.cpp */, + FA34E7D1174B515D00E04D3F /* System.h */, + ); + path = sdl; + sourceTree = ""; + }; FA577A6616C7199700860150 /* Frameworks */ = { isa = PBXGroup; children = ( + FA9B4A0716E1578300074F42 /* SDL2.framework */, FA577A7916C71A1700860150 /* Cocoa.framework */, FA577A6716C719D900860150 /* FreeType.framework */, FA577A6B16C719E400860150 /* Game_Music_Emu.framework */, @@ -1722,7 +1790,6 @@ FAAFF04316CB11C700CCDE45 /* OpenAL-Soft.framework */, FA577A7C16C71A2600860150 /* OpenGL.framework */, FA577A7316C719F900860150 /* physfs.framework */, - FA577A7516C719FF00860150 /* SDL.framework */, FA577A7716C71A0800860150 /* Vorbis.framework */, ); name = Frameworks; @@ -1850,7 +1917,13 @@ FAC86E6A1724555D00EED715 /* DrawGable.h in Headers */, FAC86E6C1724555D00EED715 /* Geometry.h in Headers */, FA03546D1731F3A700284828 /* simplexnoise1234.h in Headers */, + FA3D9E0E16E68DE600CA6630 /* Cursor.h in Headers */, + FA3D9E1216E68EAE00CA6630 /* Cursor.h in Headers */, + FA3D9E1616E6D41100CA6630 /* wrap_Cursor.h in Headers */, FA9FC0B1173D6E3E005027FF /* wrap_Window.h in Headers */, + FAB007901740C12D00A9664D /* Joystick.h in Headers */, + FAB007941740C28900A9664D /* Joystick.h in Headers */, + FAB007981740C87D00A9664D /* wrap_Joystick.h in Headers */, FAC5710117402D1100D147E4 /* BezierCurve.h in Headers */, FAC5710317402D1100D147E4 /* wrap_BezierCurve.h in Headers */, FA5FDC7E1788D548002F0ED2 /* callbacks.h in Headers */, @@ -1864,6 +1937,9 @@ FA5FDC861788D548002F0ED2 /* win32.h in Headers */, FA5FDC8F1788D548002F0ED2 /* lua-enet.h in Headers */, FA7175AA178E8418001FE7FE /* lua.h in Headers */, + FA34E7CE174B513F00E04D3F /* System.h in Headers */, + FA34E7D3174B515D00E04D3F /* System.h in Headers */, + FA1EF7C51799FEB200FF380C /* wrap_System.h in Headers */, FA435EA417B36E9C004C3F22 /* Polyline.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2054,9 +2130,8 @@ FA08F63016C7542600F007B5 /* DevilHandler.cpp in Sources */, FA08F63116C7542600F007B5 /* wrap_Image.cpp in Sources */, FA08F63216C7542600F007B5 /* wrap_ImageData.cpp in Sources */, - FA08F63316C7542D00F007B5 /* Joystick.cpp in Sources */, - FA08F63416C7542D00F007B5 /* Joystick.cpp in Sources */, - FA08F63516C7542D00F007B5 /* wrap_Joystick.cpp in Sources */, + FA08F63416C7542D00F007B5 /* JoystickModule.cpp in Sources */, + FA08F63516C7542D00F007B5 /* wrap_JoystickModule.cpp in Sources */, FA08F63616C7543400F007B5 /* Keyboard.cpp in Sources */, FA08F63716C7543400F007B5 /* Keyboard.cpp in Sources */, FA08F63816C7543400F007B5 /* wrap_Keyboard.cpp in Sources */, @@ -2148,7 +2223,13 @@ FAC86E691724555D00EED715 /* DrawGable.cpp in Sources */, FAC86E6B1724555D00EED715 /* Geometry.cpp in Sources */, FA03546C1731F3A700284828 /* simplexnoise1234.cpp in Sources */, + FA3D9E0D16E68DE600CA6630 /* Cursor.cpp in Sources */, + FA3D9E1116E68EAE00CA6630 /* Cursor.cpp in Sources */, + FA3D9E1516E6D41100CA6630 /* wrap_Cursor.cpp in Sources */, FA9FC0B0173D6E3E005027FF /* wrap_Window.cpp in Sources */, + FAB0078F1740C12D00A9664D /* Joystick.cpp in Sources */, + FAB007931740C28900A9664D /* Joystick.cpp in Sources */, + FAB007971740C87D00A9664D /* wrap_Joystick.cpp in Sources */, FAC5710017402D1100D147E4 /* BezierCurve.cpp in Sources */, FAC5710217402D1100D147E4 /* wrap_BezierCurve.cpp in Sources */, FA5FDC791788D548002F0ED2 /* enet.cpp in Sources */, @@ -2161,6 +2242,9 @@ FA5FDC8B1788D548002F0ED2 /* protocol.c in Sources */, FA5FDC8D1788D548002F0ED2 /* unix.c in Sources */, FA5FDC8E1788D548002F0ED2 /* win32.c in Sources */, + FA34E7CD174B513F00E04D3F /* System.cpp in Sources */, + FA34E7D2174B515D00E04D3F /* System.cpp in Sources */, + FA1EF7C41799FEAC00FF380C /* wrap_System.cpp in Sources */, FA435EA317B36E9C004C3F22 /* Polyline.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2190,7 +2274,7 @@ "\"$(SRCROOT)/../../src/libraries/enet/libenet/include\"", /Library/Frameworks/FreeType.framework/Headers, /Library/Frameworks/Lua.framework/Headers, - /Library/Frameworks/SDL.framework/Headers, + /Library/Frameworks/SDL2.framework/Headers, ); LD_RUNPATH_SEARCH_PATHS = "@rpath"; LIBRARY_SEARCH_PATHS = ""; @@ -2223,7 +2307,7 @@ "\"$(SRCROOT)/../../src/libraries/enet/libenet/include\"", /Library/Frameworks/FreeType.framework/Headers, /Library/Frameworks/Lua.framework/Headers, - /Library/Frameworks/SDL.framework/Headers, + /Library/Frameworks/SDL2.framework/Headers, ); LD_RUNPATH_SEARCH_PATHS = "@rpath"; LIBRARY_SEARCH_PATHS = ""; diff --git a/platform/macosx/love.xcodeproj/project.pbxproj b/platform/macosx/love.xcodeproj/project.pbxproj index a1c86304a..14894f0f9 100644 --- a/platform/macosx/love.xcodeproj/project.pbxproj +++ b/platform/macosx/love.xcodeproj/project.pbxproj @@ -10,14 +10,11 @@ 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; A911D3C915DFF25D005B7EB8 /* Game_Music_Emu.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A911D3C715DFF24D005B7EB8 /* Game_Music_Emu.framework */; }; A9255DD11043183600BA1496 /* FreeType.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A93E6E4810420B4A007D418B /* FreeType.framework */; }; - A9255DD21043183600BA1496 /* SDL.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A93E6E5210420B57007D418B /* SDL.framework */; }; A9255DD31043183600BA1496 /* Lua.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A93E6E5310420B57007D418B /* Lua.framework */; }; - A9255DEC1043188D00BA1496 /* SDLMain.m in Sources */ = {isa = PBXBuildFile; fileRef = A9255DEA1043188D00BA1496 /* SDLMain.m */; }; A9255E031043195A00BA1496 /* Vorbis.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A9255E021043195A00BA1496 /* Vorbis.framework */; }; A9255F431043240F00BA1496 /* IL.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A9255F421043240F00BA1496 /* IL.framework */; }; A9255F58104324E100BA1496 /* Ogg.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A9255F51104324D700BA1496 /* Ogg.framework */; }; A93E6E4A10420B4A007D418B /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A93E6E4710420B4A007D418B /* OpenGL.framework */; }; - A93E6E5410420B57007D418B /* SDL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A93E6E5210420B57007D418B /* SDL.framework */; }; A93E6E5510420B57007D418B /* Lua.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A93E6E5310420B57007D418B /* Lua.framework */; }; A93E6EED10420BA8007D418B /* love.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A93E6A3410420AC0007D418B /* love.cpp */; }; A9D307F2106635D3004FEDF8 /* physfs.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A9D307E9106635C3004FEDF8 /* physfs.framework */; }; @@ -27,7 +24,10 @@ A9F169AD109E825000FC83D1 /* libmodplug.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = A9F16926109E7BAD00FC83D1 /* libmodplug.framework */; }; FA08F69616C766E000F007B5 /* love.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA08F69116C765A200F007B5 /* love.framework */; }; FA08F69716C766E700F007B5 /* love.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = FA08F69116C765A200F007B5 /* love.framework */; }; + FA9B4A0A16E1579F00074F42 /* SDL2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA9B4A0916E1579F00074F42 /* SDL2.framework */; }; + FA9B4A0B16E157B500074F42 /* SDL2.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = FA9B4A0916E1579F00074F42 /* SDL2.framework */; }; FAAFF04716CB120000CCDE45 /* OpenAL-Soft.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = FAAFF04616CB120000CCDE45 /* OpenAL-Soft.framework */; }; + FAC8E8D416F3C468004DADF3 /* osx.mm in Sources */ = {isa = PBXBuildFile; fileRef = FAC8E8D316F3C468004DADF3 /* osx.mm */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -48,6 +48,7 @@ dstSubfolderSpec = 10; files = ( FA08F69716C766E700F007B5 /* love.framework in Copy Frameworks */, + FA9B4A0B16E157B500074F42 /* SDL2.framework in Copy Frameworks */, FAAFF04716CB120000CCDE45 /* OpenAL-Soft.framework in Copy Frameworks */, A9F169AC109E825000FC83D1 /* mpg123.framework in Copy Frameworks */, A9F169AD109E825000FC83D1 /* libmodplug.framework in Copy Frameworks */, @@ -56,7 +57,6 @@ A9255F431043240F00BA1496 /* IL.framework in Copy Frameworks */, A9255E031043195A00BA1496 /* Vorbis.framework in Copy Frameworks */, A9255DD11043183600BA1496 /* FreeType.framework in Copy Frameworks */, - A9255DD21043183600BA1496 /* SDL.framework in Copy Frameworks */, A9255DD31043183600BA1496 /* Lua.framework in Copy Frameworks */, A911D3C915DFF25D005B7EB8 /* Game_Music_Emu.framework in Copy Frameworks */, ); @@ -69,18 +69,14 @@ 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 8D1107320486CEB800E47090 /* love.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = love.app; sourceTree = BUILT_PRODUCTS_DIR; }; A911D3C715DFF24D005B7EB8 /* Game_Music_Emu.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Game_Music_Emu.framework; path = /Library/Frameworks/Game_Music_Emu.framework; sourceTree = ""; }; - A9255DEA1043188D00BA1496 /* SDLMain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDLMain.m; sourceTree = ""; }; - A9255DEB1043188D00BA1496 /* SDLMain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDLMain.h; sourceTree = ""; }; A9255E021043195A00BA1496 /* Vorbis.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Vorbis.framework; path = /Library/Frameworks/Vorbis.framework; sourceTree = ""; }; A9255F421043240F00BA1496 /* IL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IL.framework; path = /Library/Frameworks/IL.framework; sourceTree = ""; }; A9255F51104324D700BA1496 /* Ogg.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Ogg.framework; path = /Library/Frameworks/Ogg.framework; sourceTree = ""; }; A93E6A3410420AC0007D418B /* love.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = love.cpp; path = ../../src/love.cpp; sourceTree = ""; }; A93E6E4710420B4A007D418B /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = ""; }; A93E6E4810420B4A007D418B /* FreeType.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FreeType.framework; path = /Library/Frameworks/FreeType.framework; sourceTree = ""; }; - A93E6E5210420B57007D418B /* SDL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL.framework; path = /Library/Frameworks/SDL.framework; sourceTree = ""; }; A93E6E5310420B57007D418B /* Lua.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Lua.framework; path = /Library/Frameworks/Lua.framework; sourceTree = ""; }; A97E3842132A9EDE00198A2F /* love-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "love-Info.plist"; sourceTree = ""; }; - A9B1AE451197293000D496EB /* love_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = love_Prefix.pch; sourceTree = ""; }; A9D307E9106635C3004FEDF8 /* physfs.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = physfs.framework; path = /Library/Frameworks/physfs.framework; sourceTree = ""; }; A9DEC1BF1046EFA60049C70C /* Love.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = Love.icns; path = icons/Love.icns; sourceTree = ""; }; A9DEC1C01046EFA70049C70C /* LoveDocument.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = LoveDocument.icns; path = icons/LoveDocument.icns; sourceTree = ""; }; @@ -88,7 +84,10 @@ A9F169A6109E824900FC83D1 /* mpg123.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = mpg123.framework; path = /Library/Frameworks/mpg123.framework; sourceTree = ""; }; FA08F69116C765A200F007B5 /* love.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = love.framework; sourceTree = BUILT_PRODUCTS_DIR; }; FA577A9316C7217800860150 /* love-framework.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = "love-framework.xcodeproj"; sourceTree = ""; }; + FA9B4A0916E1579F00074F42 /* SDL2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2.framework; path = /Library/Frameworks/SDL2.framework; sourceTree = ""; }; FAAFF04616CB120000CCDE45 /* OpenAL-Soft.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = "OpenAL-Soft.framework"; path = "/Library/Frameworks/OpenAL-Soft.framework"; sourceTree = ""; }; + FAC8E8D316F3C468004DADF3 /* osx.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = osx.mm; sourceTree = ""; }; + FAC8E8D616F3C46E004DADF3 /* osx.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = osx.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -99,8 +98,8 @@ FA08F69616C766E000F007B5 /* love.framework in Frameworks */, 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, A93E6E4A10420B4A007D418B /* OpenGL.framework in Frameworks */, - A93E6E5410420B57007D418B /* SDL.framework in Frameworks */, A93E6E5510420B57007D418B /* Lua.framework in Frameworks */, + FA9B4A0A16E1579F00074F42 /* SDL2.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -110,6 +109,7 @@ 1058C7A0FEA54F0111CA2CBB /* Frameworks */ = { isa = PBXGroup; children = ( + FA9B4A0916E1579F00074F42 /* SDL2.framework */, 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, A93E6E4810420B4A007D418B /* FreeType.framework */, A911D3C715DFF24D005B7EB8 /* Game_Music_Emu.framework */, @@ -122,7 +122,6 @@ FAAFF04616CB120000CCDE45 /* OpenAL-Soft.framework */, A93E6E4710420B4A007D418B /* OpenGL.framework */, A9D307E9106635C3004FEDF8 /* physfs.framework */, - A93E6E5210420B57007D418B /* SDL.framework */, A9255E021043195A00BA1496 /* Vorbis.framework */, ); name = Frameworks; @@ -171,9 +170,8 @@ isa = PBXGroup; children = ( A93E6A3410420AC0007D418B /* love.cpp */, - A9255DEA1043188D00BA1496 /* SDLMain.m */, - A9255DEB1043188D00BA1496 /* SDLMain.h */, - A9B1AE451197293000D496EB /* love_Prefix.pch */, + FAC8E8D616F3C46E004DADF3 /* osx.h */, + FAC8E8D316F3C468004DADF3 /* osx.mm */, ); name = Source; sourceTree = ""; @@ -261,7 +259,7 @@ buildActionMask = 2147483647; files = ( A93E6EED10420BA8007D418B /* love.cpp in Sources */, - A9255DEC1043188D00BA1496 /* SDLMain.m in Sources */, + FAC8E8D416F3C468004DADF3 /* osx.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -279,15 +277,6 @@ ); GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = love_Prefix.pch; - HEADER_SEARCH_PATHS = ( - "\"$(SRCROOT)/../../src\"", - "\"$(SRCROOT)/../../src/libraries\"", - "\"$(SRCROOT)/../../src/modules\"", - /Library/Frameworks/Lua.framework/Headers, - /Library/Frameworks/SDL.framework/Headers, - ); INSTALL_PATH = /Applications; PRODUCT_NAME = love; }; @@ -303,15 +292,6 @@ "\"$(SRCROOT)/build/Release\"", "\"$(SRCROOT)/build/Debug\"", ); - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = love_Prefix.pch; - HEADER_SEARCH_PATHS = ( - "\"$(SRCROOT)/../../src\"", - "\"$(SRCROOT)/../../src/libraries\"", - "\"$(SRCROOT)/../../src/modules\"", - /Library/Frameworks/Lua.framework/Headers, - /Library/Frameworks/SDL.framework/Headers, - ); INSTALL_PATH = /Applications; PRODUCT_NAME = love; }; @@ -346,8 +326,7 @@ "\"$(SRCROOT)/../../src/libraries\"", "\"$(SRCROOT)/../../src/modules\"", /Library/Frameworks/Lua.framework/Headers, - /Library/Frameworks/FreeType.framework/Headers, - /Library/Frameworks/SDL.framework/Headers, + /Library/Frameworks/SDL2.framework/Headers, ); INFOPLIST_FILE = "love-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks"; @@ -400,8 +379,7 @@ "\"$(SRCROOT)/../../src/libraries\"", "\"$(SRCROOT)/../../src/modules\"", /Library/Frameworks/Lua.framework/Headers, - /Library/Frameworks/FreeType.framework/Headers, - /Library/Frameworks/SDL.framework/Headers, + /Library/Frameworks/SDL2.framework/Headers, ); INFOPLIST_FILE = "love-Info.plist"; LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks"; diff --git a/platform/macosx/love_Prefix.pch b/platform/macosx/love_Prefix.pch deleted file mode 100644 index 877e839f1..000000000 --- a/platform/macosx/love_Prefix.pch +++ /dev/null @@ -1,7 +0,0 @@ -// -// Prefix header for all source files of the 'love' target in the 'love' project -// - -#ifdef __OBJC__ - #import -#endif diff --git a/src/common/Reference.cpp b/src/common/Reference.cpp index 89c4bc2ed..3fb44d6f3 100644 --- a/src/common/Reference.cpp +++ b/src/common/Reference.cpp @@ -26,12 +26,14 @@ namespace love const char REFERENCE_TABLE_NAME[] = "love-references"; Reference::Reference() - : L(0), idx(LUA_REFNIL) + : L(0) + , idx(LUA_REFNIL) { } Reference::Reference(lua_State *L) - : L(0), idx(LUA_REFNIL) + : L(L) + , idx(LUA_REFNIL) { ref(L); } diff --git a/src/common/config.h b/src/common/config.h index 75844c127..75e0cc840 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -72,6 +72,7 @@ #if defined(LOVE_MACOSX) # define LOVE_LEGENDARY_LIBSTDCXX_HACK +# define LOVE_LEGENDARY_APP_ARGV_HACK #endif // Autotools config.h diff --git a/src/common/runtime.cpp b/src/common/runtime.cpp index 972f2dab2..c085203c8 100644 --- a/src/common/runtime.cpp +++ b/src/common/runtime.cpp @@ -571,6 +571,9 @@ StringMap::Entry typeEntries[] = {"ImageData", IMAGE_IMAGE_DATA_ID}, {"CompressedData", IMAGE_COMPRESSED_DATA_ID}, + // Joystick + {"Joystick", JOYSTICK_JOYSTICK_ID}, + // Math {"RandomGenerator", MATH_RANDOM_GENERATOR_ID}, {"BezierCurve", MATH_BEZIER_CURVE_ID}, @@ -582,6 +585,9 @@ StringMap::Entry typeEntries[] = {"SoundData", SOUND_SOUND_DATA_ID}, {"Decoder", SOUND_DECODER_ID}, + // Mouse + {"Cursor", MOUSE_CURSOR_ID}, + // Physics {"World", PHYSICS_WORLD_ID}, {"Contact", PHYSICS_CONTACT_ID}, diff --git a/src/common/types.h b/src/common/types.h index b538c5976..3e4804c22 100644 --- a/src/common/types.h +++ b/src/common/types.h @@ -58,6 +58,9 @@ enum Type IMAGE_IMAGE_DATA_ID, IMAGE_COMPRESSED_DATA_ID, + // Joystick + JOYSTICK_JOYSTICK_ID, + // Math MATH_RANDOM_GENERATOR_ID, MATH_BEZIER_CURVE_ID, @@ -69,6 +72,9 @@ enum Type SOUND_SOUND_DATA_ID, SOUND_DECODER_ID, + // Mouse + MOUSE_CURSOR_ID, + // Physics PHYSICS_WORLD_ID, PHYSICS_CONTACT_ID, @@ -135,6 +141,9 @@ const bits GRAPHICS_SHADER_T = (bits(1) << GRAPHICS_SHADER_ID) | OBJECT_T; const bits IMAGE_IMAGE_DATA_T = (bits(1) << IMAGE_IMAGE_DATA_ID) | DATA_T; const bits IMAGE_COMPRESSED_DATA_T = (bits(1) << IMAGE_COMPRESSED_DATA_ID) | DATA_T; +// Joystick. +const bits JOYSTICK_JOYSTICK_T = (bits(1) << JOYSTICK_JOYSTICK_ID) | OBJECT_T; + // Math. const bits MATH_RANDOM_GENERATOR_T = (bits(1) << MATH_RANDOM_GENERATOR_ID) | OBJECT_T; const bits MATH_BEZIER_CURVE_T = (bits(1) << MATH_BEZIER_CURVE_ID) | OBJECT_T; @@ -146,6 +155,9 @@ const bits AUDIO_SOURCE_T = (bits(1) << AUDIO_SOURCE_ID) | OBJECT_T; const bits SOUND_SOUND_DATA_T = (bits(1) << SOUND_SOUND_DATA_ID) | DATA_T; const bits SOUND_DECODER_T = bits(1) << SOUND_DECODER_ID; +// Mouse. +const bits MOUSE_CURSOR_T = (bits(1) << MOUSE_CURSOR_ID) | OBJECT_T; + // Physics. const bits PHYSICS_WORLD_T = (bits(1) << PHYSICS_WORLD_ID) | OBJECT_T; const bits PHYSICS_CONTACT_T = (bits(1) << PHYSICS_CONTACT_ID) | OBJECT_T; diff --git a/src/love.cpp b/src/love.cpp index 94dee7d56..055acecea 100644 --- a/src/love.cpp +++ b/src/love.cpp @@ -34,6 +34,10 @@ extern "C" { #include #endif // LOVE_WINDOWS +#ifdef LOVE_MACOSX +#include "osx.h" +#endif // LOVE_MACOSX + #ifdef LOVE_LEGENDARY_UTF8_ARGV_HACK void get_utf8_arguments(int &argc, char **&argv) @@ -71,6 +75,54 @@ void get_utf8_arguments(int &argc, char **&argv) #endif // LOVE_LEGENDARY_UTF8_ARGV_HACK +#ifdef LOVE_LEGENDARY_APP_ARGV_HACK + +#include + +static void get_app_arguments(int argc, char **argv, int &new_argc, char **&new_argv) +{ + std::vector temp_argv; + for (int i = 0; i < argc; i++) + { + // Don't copy -psn_xxx argument from argv. + if (i == 0 || strncmp(argv[i], "-psn_", 5) != 0) + temp_argv.push_back(std::string(argv[i])); + } + + // Check for a drop file string. + std::string dropfilestr = love::osx::checkDropEvents(); + if (!dropfilestr.empty()) + { + temp_argv.insert(temp_argv.begin() + 1, dropfilestr); + } + else + { + // If it exists, add the love file in love.app/Contents/Resources/ to argv. + std::string loveResourcesPath = love::osx::getLoveInResources(); + if (!loveResourcesPath.empty()) + { + // Run in pseudo-fused mode. + std::vector::iterator it = temp_argv.begin(); + it = temp_argv.insert(it + 1, loveResourcesPath); + temp_argv.insert(it + 1, std::string("--fused")); + } + } + + // Copy temp argv vector to new argv array. + new_argc = (int) temp_argv.size(); + new_argv = new char *[new_argc+1]; + + for (int i = 0; i < new_argc; i++) + { + new_argv[i] = new char[temp_argv[i].length() + 1]; + strcpy(new_argv[i], temp_argv[i].c_str()); + } + + new_argv[new_argc+1] = NULL; +} + +#endif // LOVE_LEGENDARY_APP_ARGV_HACK + static int love_preload(lua_State *L, lua_CFunction f, const char *name) { lua_getglobal(L, "package"); @@ -90,6 +142,14 @@ int main(int argc, char **argv) argv = hack_argv; #endif // LOVE_LEGENDARY_UTF8_ARGV_HACK +#ifdef LOVE_LEGENDARY_APP_ARGV_HACK + int hack_argc = 0; + char **hack_argv = 0; + get_app_arguments(argc, argv, hack_argc, hack_argv); + argc = hack_argc; + argv = hack_argv; +#endif // LOVE_LEGENDARY_APP_ARGV_HACK + // Oh, you just want the version? Okay! if (argc > 1 && strcmp(argv[1],"--version") == 0) { @@ -148,14 +208,14 @@ int main(int argc, char **argv) lua_close(L); -#ifdef LOVE_LEGENDARY_UTF8_ARGV_HACK +#if defined(LOVE_LEGENDARY_UTF8_ARGV_HACK) || defined(LOVE_LEGENDARY_APP_ARGV_HACK) if (hack_argv) { for (int i = 0; i -#include namespace love { @@ -42,7 +44,13 @@ const char *Event::getName() const Event::Event() { - SDL_EnableUNICODE(1); + if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0) + throw love::Exception("%s", SDL_GetError()); +} + +Event::~Event() +{ + SDL_QuitSubSystem(SDL_INIT_EVENTS); } void Event::pump() @@ -50,7 +58,6 @@ void Event::pump() SDL_PumpEvents(); static SDL_Event e; - SDL_EnableUNICODE(1); Message *msg; @@ -86,46 +93,65 @@ void Event::clear() love::event::Event::clear(); } -Message *Event::convert(SDL_Event &e) +Message *Event::convert(const SDL_Event &e) const { - Message *msg = 0; + Message *msg = NULL; + love::keyboard::Keyboard::Key key; love::mouse::Mouse::Button button; - love::joystick::Joystick::Hat hat; - Variant *arg1 = 0, *arg2 = 0, *arg3 = 0; + Variant *arg1, *arg2, *arg3; const char *txt; + std::map::const_iterator keyit; + switch (e.type) { case SDL_KEYDOWN: - if (!keys.find(e.key.keysym.sym, key)) + keyit = keys.find(e.key.keysym.sym); + if (keyit != keys.end()) + key = keyit->second; + else key = love::keyboard::Keyboard::KEY_UNKNOWN; + if (!love::keyboard::Keyboard::getConstant(key, txt)) txt = "unknown"; arg1 = new Variant(txt, strlen(txt)); - txt = convertUnicode(e.key.keysym.unicode); - // We don't want to send unprintable unicode text. - if (txt && (txt[0] >= ' ' && txt[0] != 127)) - { - arg2 = new Variant(txt, strlen(txt)); - msg = new Message("keypressed", arg1, arg2); - arg2->release(); - } - else - msg = new Message("keypressed", arg1); + arg2 = new Variant(e.key.repeat == SDL_TRUE); + msg = new Message("keypressed", arg1, arg2); arg1->release(); + arg2->release(); break; case SDL_KEYUP: - if (!keys.find(e.key.keysym.sym, key)) + keyit = keys.find(e.key.keysym.sym); + if (keyit != keys.end()) + key = keyit->second; + else key = love::keyboard::Keyboard::KEY_UNKNOWN; + if (!love::keyboard::Keyboard::getConstant(key, txt)) txt = "unknown"; arg1 = new Variant(txt, strlen(txt)); msg = new Message("keyreleased", arg1); arg1->release(); break; + case SDL_TEXTINPUT: + txt = e.text.text; + arg1 = new Variant(txt, strlen(txt)); + msg = new Message("textinput", arg1); + arg1->release(); + break; + case SDL_TEXTEDITING: + txt = e.edit.text; + arg1 = new Variant(txt, strlen(txt)); + arg2 = new Variant((double) e.edit.start); + arg3 = new Variant((double) e.edit.length); + msg = new Message("textedit", arg1, arg2, arg3); + arg1->release(); + arg2->release(); + arg3->release(); + break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: - if (buttons.find(e.button.button, button) && love::mouse::Mouse::getConstant(button, txt)) + if (buttons.find(e.button.button, button) && mouse::Mouse::getConstant(button, txt)) { arg1 = new Variant((double) e.button.x); arg2 = new Variant((double) e.button.y); @@ -138,9 +164,77 @@ Message *Event::convert(SDL_Event &e) arg3->release(); } break; + case SDL_MOUSEWHEEL: + if (e.wheel.y != 0) + { + button = (e.wheel.y > 0) ? mouse::Mouse::BUTTON_WHEELUP : mouse::Mouse::BUTTON_WHEELDOWN; + if (!love::mouse::Mouse::getConstant(button, txt)) + break; + + int mx, my; + SDL_GetMouseState(&mx, &my); + + arg1 = new Variant((double) mx); + arg2 = new Variant((double) my); + arg3 = new Variant(txt, strlen(txt)); + msg = new Message("mousepressed", arg1, arg2, arg3); + arg1->release(); + arg2->release(); + arg3->release(); + } + break; case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: - arg1 = new Variant((double)(e.jbutton.which+1)); + case SDL_JOYAXISMOTION: + case SDL_JOYBALLMOTION: + case SDL_JOYHATMOTION: + case SDL_JOYDEVICEADDED: + case SDL_JOYDEVICEREMOVED: + case SDL_CONTROLLERBUTTONDOWN: + case SDL_CONTROLLERBUTTONUP: + case SDL_CONTROLLERAXISMOTION: + msg = convertJoystickEvent(e); + break; + case SDL_WINDOWEVENT: + msg = convertWindowEvent(e); + break; + case SDL_DROPFILE: + SDL_free(e.drop.file); + break; + case SDL_QUIT: + msg = new Message("quit"); + break; + default: + break; + } + + return msg; +} + +Message *Event::convertJoystickEvent(const SDL_Event &e) const +{ + joystick::JoystickModule *joymodule = (joystick::JoystickModule *) Module::findInstance("love.joystick."); + if (!joymodule) + return 0; + + Message *msg = 0; + Proxy proxy; + love::joystick::Joystick::Hat hat; + love::joystick::Joystick::GamepadButton padbutton; + love::joystick::Joystick::GamepadAxis padaxis; + Variant *arg1, *arg2, *arg3; + const char *txt; + + switch (e.type) + { + case SDL_JOYBUTTONDOWN: + case SDL_JOYBUTTONUP: + proxy.flags = JOYSTICK_JOYSTICK_T; + proxy.data = joymodule->getJoystickFromID(e.jbutton.which); + if (!proxy.data) + break; + + arg1 = new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy); arg2 = new Variant((double)(e.jbutton.button+1)); msg = new Message((e.type == SDL_JOYBUTTONDOWN) ? "joystickpressed" : "joystickreleased", @@ -150,7 +244,12 @@ Message *Event::convert(SDL_Event &e) break; case SDL_JOYAXISMOTION: { - arg1 = new Variant((double)(e.jaxis.which+1)); + proxy.flags = JOYSTICK_JOYSTICK_T; + proxy.data = joymodule->getJoystickFromID(e.jaxis.which); + if (!proxy.data) + break; + + arg1 = new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy); arg2 = new Variant((double)(e.jaxis.axis+1)); float value = e.jaxis.value / 32768.0f; if (fabsf(value) < 0.001f) value = 0.0f; @@ -164,52 +263,144 @@ Message *Event::convert(SDL_Event &e) } break; case SDL_JOYHATMOTION: - if (hats.find(e.jhat.value, hat) && love::joystick::Joystick::getConstant(hat, txt)) + if (!joystick::sdl::Joystick::getConstant(e.jhat.value, hat) || !joystick::Joystick::getConstant(hat, txt)) + break; + + proxy.flags = JOYSTICK_JOYSTICK_T; + proxy.data = joymodule->getJoystickFromID(e.jhat.which); + if (!proxy.data) + break; + + arg1 = new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy); + arg2 = new Variant((double)(e.jhat.hat+1)); + arg3 = new Variant(txt, strlen(txt)); + msg = new Message("joystickhat", arg1, arg2, arg3); + arg1->release(); + arg2->release(); + arg3->release(); + break; + case SDL_CONTROLLERBUTTONDOWN: + case SDL_CONTROLLERBUTTONUP: + if (!joystick::sdl::Joystick::getConstant((SDL_GameControllerButton) e.cbutton.button, padbutton)) + break; + + if (!joystick::Joystick::getConstant(padbutton, txt)) + break; + + proxy.flags = JOYSTICK_JOYSTICK_T; + proxy.data = joymodule->getJoystickFromID(e.cbutton.which); + if (!proxy.data) + break; + + arg1 = new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy); + arg2 = new Variant(txt, strlen(txt)); + msg = new Message(e.type == SDL_CONTROLLERBUTTONDOWN ? + "gamepadpressed" : "gamepadreleased", arg1, arg2); + arg1->release(); + arg2->release(); + break; + case SDL_CONTROLLERAXISMOTION: + if (joystick::sdl::Joystick::getConstant((SDL_GameControllerAxis) e.caxis.axis, padaxis)) { - arg1 = new Variant((double)(e.jhat.which+1)); - arg2 = new Variant((double)(e.jhat.hat+1)); - arg3 = new Variant(txt, strlen(txt)); - msg = new Message("joystickhat", arg1, arg2, arg3); + if (!joystick::Joystick::getConstant(padaxis, txt)) + break; + + proxy.flags = JOYSTICK_JOYSTICK_T; + proxy.data = joymodule->getJoystickFromID(e.caxis.which); + if (!proxy.data) + break; + + arg1 = new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy); + + arg2 = new Variant(txt, strlen(txt)); + float value = e.jaxis.value / 32768.0f; + if (fabsf(value) < 0.001f) value = 0.0f; + if (value < -0.99f) value = -1.0f; + if (value > 0.99f) value = 1.0f; + arg3 = new Variant((double) value); + msg = new Message("gamepadaxis", arg1, arg2, arg3); arg1->release(); arg2->release(); arg3->release(); } break; - case SDL_ACTIVEEVENT: + case SDL_JOYDEVICEADDED: + // jdevice.which is the joystick device index. + proxy.data = joymodule->addJoystick(e.jdevice.which); + proxy.flags = JOYSTICK_JOYSTICK_T; + if (proxy.data) { - // SDL can send multiple ACTIVEEVENTS in a single SDL_event... we - // have to work around that by re-sending the ones we miss. - SDL_Event e2 = e; - - arg1 = new Variant(e.active.gain != 0); - if (e.active.state & SDL_APPINPUTFOCUS) - { - msg = new Message("focus", arg1); - e2.active.state &= ~SDL_APPINPUTFOCUS; - } - else if (e.active.state & SDL_APPMOUSEFOCUS) - { - msg = new Message("mousefocus", arg1); - e2.active.state &= ~SDL_APPMOUSEFOCUS; - } - else if (e.active.state & SDL_APPACTIVE) - { - msg = new Message("visible", arg1); - e2.active.state &= ~SDL_APPACTIVE; - } + arg1 = new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy); + msg = new Message("joystickadded", arg1); arg1->release(); - - // Put any missing active events back in SDL's queue. - if (e2.active.state != 0) - SDL_PushEvent(&e2); } break; - case SDL_QUIT: - msg = new Message("quit"); + case SDL_JOYDEVICEREMOVED: + // jdevice.which is the joystick instance ID now. + proxy.data = joymodule->getJoystickFromID(e.jdevice.which); + proxy.flags = JOYSTICK_JOYSTICK_T; + if (proxy.data) + { + joymodule->removeJoystick((joystick::Joystick *) proxy.data); + arg1 = new Variant(JOYSTICK_JOYSTICK_ID, (void *) &proxy); + msg = new Message("joystickremoved", arg1); + arg1->release(); + } break; - case SDL_VIDEORESIZE: - arg1 = new Variant((double) e.resize.w); - arg2 = new Variant((double) e.resize.h); + default: + break; + } + + return msg; +} + +Message *Event::convertWindowEvent(const SDL_Event &e) const +{ + Message *msg = 0; + Variant *arg1, *arg2; + window::Window *win = 0; + + if (e.type != SDL_WINDOWEVENT) + return 0; + + switch (e.window.event) + { + case SDL_WINDOWEVENT_FOCUS_GAINED: + case SDL_WINDOWEVENT_FOCUS_LOST: + // Users won't expect the screensaver to activate if a game is in + // focus. Also, joystick input may not delay the screensaver timer. + if (e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) + SDL_DisableScreenSaver(); + else + SDL_EnableScreenSaver(); + arg1 = new Variant(e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED); + msg = new Message("focus", arg1); + arg1->release(); + break; + case SDL_WINDOWEVENT_ENTER: + case SDL_WINDOWEVENT_LEAVE: + arg1 = new Variant(e.window.event == SDL_WINDOWEVENT_ENTER); + msg = new Message("mousefocus", arg1); + arg1->release(); + break; + case SDL_WINDOWEVENT_SHOWN: + case SDL_WINDOWEVENT_HIDDEN: + arg1 = new Variant(e.window.event == SDL_WINDOWEVENT_SHOWN); + msg = new Message("visible", arg1); + arg1->release(); + break; + case SDL_WINDOWEVENT_RESIZED: + win = (window::Window *) Module::findInstance("love.window."); + if (win) + { + win->onWindowResize(e.window.data1, e.window.data2); + + graphics::Graphics *gfx = (graphics::Graphics *) Module::findInstance("love.graphics."); + if (gfx) + gfx->setViewportSize(e.window.data1, e.window.data2); + } + arg1 = new Variant((double) e.window.data1); + arg2 = new Variant((double) e.window.data2); msg = new Message("resize", arg1, arg2); arg1->release(); arg2->release(); @@ -219,205 +410,221 @@ Message *Event::convert(SDL_Event &e) return msg; } -const char *Event::convertUnicode(Uint16 codepoint) const +std::map Event::createKeyMap() { - // A single unicode character can use up to 4 bytes. - static char str[5] = {'\0'}; - ptrdiff_t length = 0; + using love::keyboard::Keyboard; - if (codepoint == 0) - return 0; + std::map k; - char *end = utf8::unchecked::append(codepoint, str); - length = end - str; + k[SDLK_UNKNOWN] = Keyboard::KEY_UNKNOWN; - if (length <= 0 || !utf8::is_valid(str, str + length)) - return 0; + k[SDLK_RETURN] = Keyboard::KEY_RETURN; + k[SDLK_ESCAPE] = Keyboard::KEY_ESCAPE; + k[SDLK_BACKSPACE] = Keyboard::KEY_BACKSPACE; + k[SDLK_TAB] = Keyboard::KEY_TAB; + k[SDLK_SPACE] = Keyboard::KEY_SPACE; + k[SDLK_EXCLAIM] = Keyboard::KEY_EXCLAIM; + k[SDLK_QUOTEDBL] = Keyboard::KEY_QUOTEDBL; + k[SDLK_HASH] = Keyboard::KEY_HASH; + k[SDLK_DOLLAR] = Keyboard::KEY_DOLLAR; + k[SDLK_AMPERSAND] = Keyboard::KEY_AMPERSAND; + k[SDLK_QUOTE] = Keyboard::KEY_QUOTE; + k[SDLK_LEFTPAREN] = Keyboard::KEY_LEFTPAREN; + k[SDLK_RIGHTPAREN] = Keyboard::KEY_RIGHTPAREN; + k[SDLK_ASTERISK] = Keyboard::KEY_ASTERISK; + k[SDLK_PLUS] = Keyboard::KEY_PLUS; + k[SDLK_COMMA] = Keyboard::KEY_COMMA; + k[SDLK_MINUS] = Keyboard::KEY_MINUS; + k[SDLK_PERIOD] = Keyboard::KEY_PERIOD; + k[SDLK_SLASH] = Keyboard::KEY_SLASH; + k[SDLK_0] = Keyboard::KEY_0; + k[SDLK_1] = Keyboard::KEY_1; + k[SDLK_2] = Keyboard::KEY_2; + k[SDLK_3] = Keyboard::KEY_3; + k[SDLK_4] = Keyboard::KEY_4; + k[SDLK_5] = Keyboard::KEY_5; + k[SDLK_6] = Keyboard::KEY_6; + k[SDLK_7] = Keyboard::KEY_7; + k[SDLK_8] = Keyboard::KEY_8; + k[SDLK_9] = Keyboard::KEY_9; + k[SDLK_COLON] = Keyboard::KEY_COLON; + k[SDLK_SEMICOLON] = Keyboard::KEY_SEMICOLON; + k[SDLK_LESS] = Keyboard::KEY_LESS; + k[SDLK_EQUALS] = Keyboard::KEY_EQUALS; + k[SDLK_GREATER] = Keyboard::KEY_GREATER; + k[SDLK_QUESTION] = Keyboard::KEY_QUESTION; + k[SDLK_AT] = Keyboard::KEY_AT; - // Zero out the rest of the string. - for (ptrdiff_t i = length; i < 5; i++) - str[i] = '\0'; + k[SDLK_LEFTBRACKET] = Keyboard::KEY_LEFTBRACKET; + k[SDLK_BACKSLASH] = Keyboard::KEY_BACKSLASH; + k[SDLK_RIGHTBRACKET] = Keyboard::KEY_RIGHTBRACKET; + k[SDLK_CARET] = Keyboard::KEY_CARET; + k[SDLK_UNDERSCORE] = Keyboard::KEY_UNDERSCORE; + k[SDLK_BACKQUOTE] = Keyboard::KEY_BACKQUOTE; + k[SDLK_a] = Keyboard::KEY_A; + k[SDLK_b] = Keyboard::KEY_B; + k[SDLK_c] = Keyboard::KEY_C; + k[SDLK_d] = Keyboard::KEY_D; + k[SDLK_e] = Keyboard::KEY_E; + k[SDLK_f] = Keyboard::KEY_F; + k[SDLK_g] = Keyboard::KEY_G; + k[SDLK_h] = Keyboard::KEY_H; + k[SDLK_i] = Keyboard::KEY_I; + k[SDLK_j] = Keyboard::KEY_J; + k[SDLK_k] = Keyboard::KEY_K; + k[SDLK_l] = Keyboard::KEY_L; + k[SDLK_m] = Keyboard::KEY_M; + k[SDLK_n] = Keyboard::KEY_N; + k[SDLK_o] = Keyboard::KEY_O; + k[SDLK_p] = Keyboard::KEY_P; + k[SDLK_q] = Keyboard::KEY_Q; + k[SDLK_r] = Keyboard::KEY_R; + k[SDLK_s] = Keyboard::KEY_S; + k[SDLK_t] = Keyboard::KEY_T; + k[SDLK_u] = Keyboard::KEY_U; + k[SDLK_v] = Keyboard::KEY_V; + k[SDLK_w] = Keyboard::KEY_W; + k[SDLK_x] = Keyboard::KEY_X; + k[SDLK_y] = Keyboard::KEY_Y; + k[SDLK_z] = Keyboard::KEY_Z; - return str; + k[SDLK_CAPSLOCK] = Keyboard::KEY_CAPSLOCK; + + k[SDLK_F1] = Keyboard::KEY_F1; + k[SDLK_F2] = Keyboard::KEY_F2; + k[SDLK_F3] = Keyboard::KEY_F3; + k[SDLK_F4] = Keyboard::KEY_F4; + k[SDLK_F5] = Keyboard::KEY_F5; + k[SDLK_F6] = Keyboard::KEY_F6; + k[SDLK_F7] = Keyboard::KEY_F7; + k[SDLK_F8] = Keyboard::KEY_F8; + k[SDLK_F9] = Keyboard::KEY_F9; + k[SDLK_F10] = Keyboard::KEY_F10; + k[SDLK_F11] = Keyboard::KEY_F11; + k[SDLK_F12] = Keyboard::KEY_F12; + + k[SDLK_PRINTSCREEN] = Keyboard::KEY_PRINTSCREEN; + k[SDLK_SCROLLLOCK] = Keyboard::KEY_SCROLLLOCK; + k[SDLK_PAUSE] = Keyboard::KEY_PAUSE; + k[SDLK_INSERT] = Keyboard::KEY_INSERT; + k[SDLK_HOME] = Keyboard::KEY_HOME; + k[SDLK_PAGEUP] = Keyboard::KEY_PAGEUP; + k[SDLK_DELETE] = Keyboard::KEY_DELETE; + k[SDLK_END] = Keyboard::KEY_END; + k[SDLK_PAGEDOWN] = Keyboard::KEY_PAGEDOWN; + k[SDLK_RIGHT] = Keyboard::KEY_RIGHT; + k[SDLK_LEFT] = Keyboard::KEY_LEFT; + k[SDLK_DOWN] = Keyboard::KEY_DOWN; + k[SDLK_UP] = Keyboard::KEY_UP; + + k[SDLK_NUMLOCKCLEAR] = Keyboard::KEY_NUMLOCKCLEAR; + k[SDLK_KP_DIVIDE] = Keyboard::KEY_KP_DIVIDE; + k[SDLK_KP_MULTIPLY] = Keyboard::KEY_KP_MULTIPLY; + k[SDLK_KP_MINUS] = Keyboard::KEY_KP_MINUS; + k[SDLK_KP_PLUS] = Keyboard::KEY_KP_PLUS; + k[SDLK_KP_ENTER] = Keyboard::KEY_KP_ENTER; + k[SDLK_KP_0] = Keyboard::KEY_KP_0; + k[SDLK_KP_1] = Keyboard::KEY_KP_1; + k[SDLK_KP_2] = Keyboard::KEY_KP_2; + k[SDLK_KP_3] = Keyboard::KEY_KP_3; + k[SDLK_KP_4] = Keyboard::KEY_KP_4; + k[SDLK_KP_5] = Keyboard::KEY_KP_5; + k[SDLK_KP_6] = Keyboard::KEY_KP_6; + k[SDLK_KP_7] = Keyboard::KEY_KP_7; + k[SDLK_KP_8] = Keyboard::KEY_KP_8; + k[SDLK_KP_9] = Keyboard::KEY_KP_9; + k[SDLK_KP_PERIOD] = Keyboard::KEY_KP_PERIOD; + k[SDLK_KP_COMMA] = Keyboard::KEY_KP_COMMA; + k[SDLK_KP_EQUALS] = Keyboard::KEY_KP_EQUALS; + + k[SDLK_APPLICATION] = Keyboard::KEY_APPLICATION; + k[SDLK_POWER] = Keyboard::KEY_POWER; + k[SDLK_F13] = Keyboard::KEY_F13; + k[SDLK_F14] = Keyboard::KEY_F14; + k[SDLK_F15] = Keyboard::KEY_F15; + k[SDLK_F16] = Keyboard::KEY_F16; + k[SDLK_F17] = Keyboard::KEY_F17; + k[SDLK_F18] = Keyboard::KEY_F18; + k[SDLK_F19] = Keyboard::KEY_F19; + k[SDLK_F20] = Keyboard::KEY_F20; + k[SDLK_F21] = Keyboard::KEY_F21; + k[SDLK_F22] = Keyboard::KEY_F22; + k[SDLK_F23] = Keyboard::KEY_F23; + k[SDLK_F24] = Keyboard::KEY_F24; + k[SDLK_EXECUTE] = Keyboard::KEY_EXECUTE; + k[SDLK_HELP] = Keyboard::KEY_HELP; + k[SDLK_MENU] = Keyboard::KEY_MENU; + k[SDLK_SELECT] = Keyboard::KEY_SELECT; + k[SDLK_STOP] = Keyboard::KEY_STOP; + k[SDLK_AGAIN] = Keyboard::KEY_AGAIN; + k[SDLK_UNDO] = Keyboard::KEY_UNDO; + k[SDLK_CUT] = Keyboard::KEY_CUT; + k[SDLK_COPY] = Keyboard::KEY_COPY; + k[SDLK_PASTE] = Keyboard::KEY_PASTE; + k[SDLK_FIND] = Keyboard::KEY_FIND; + k[SDLK_MUTE] = Keyboard::KEY_MUTE; + k[SDLK_VOLUMEUP] = Keyboard::KEY_VOLUMEUP; + k[SDLK_VOLUMEDOWN] = Keyboard::KEY_VOLUMEDOWN; + + k[SDLK_ALTERASE] = Keyboard::KEY_ALTERASE; + k[SDLK_SYSREQ] = Keyboard::KEY_SYSREQ; + k[SDLK_CANCEL] = Keyboard::KEY_CANCEL; + k[SDLK_CLEAR] = Keyboard::KEY_CLEAR; + k[SDLK_PRIOR] = Keyboard::KEY_PRIOR; + k[SDLK_RETURN2] = Keyboard::KEY_RETURN2; + k[SDLK_SEPARATOR] = Keyboard::KEY_SEPARATOR; + k[SDLK_OUT] = Keyboard::KEY_OUT; + k[SDLK_OPER] = Keyboard::KEY_OPER; + k[SDLK_CLEARAGAIN] = Keyboard::KEY_CLEARAGAIN; + + k[SDLK_THOUSANDSSEPARATOR] = Keyboard::KEY_THOUSANDSSEPARATOR; + k[SDLK_DECIMALSEPARATOR] = Keyboard::KEY_DECIMALSEPARATOR; + k[SDLK_CURRENCYUNIT] = Keyboard::KEY_CURRENCYUNIT; + k[SDLK_CURRENCYSUBUNIT] = Keyboard::KEY_CURRENCYSUBUNIT; + + k[SDLK_LCTRL] = Keyboard::KEY_LCTRL; + k[SDLK_LSHIFT] = Keyboard::KEY_LSHIFT; + k[SDLK_LALT] = Keyboard::KEY_LALT; + k[SDLK_LGUI] = Keyboard::KEY_LGUI; + k[SDLK_RCTRL] = Keyboard::KEY_RCTRL; + k[SDLK_RSHIFT] = Keyboard::KEY_RSHIFT; + k[SDLK_RALT] = Keyboard::KEY_RALT; + k[SDLK_RGUI] = Keyboard::KEY_RGUI; + + k[SDLK_MODE] = Keyboard::KEY_MODE; + + k[SDLK_AUDIONEXT] = Keyboard::KEY_AUDIONEXT; + k[SDLK_AUDIOPREV] = Keyboard::KEY_AUDIOPREV; + k[SDLK_AUDIOSTOP] = Keyboard::KEY_AUDIOSTOP; + k[SDLK_AUDIOPLAY] = Keyboard::KEY_AUDIOPLAY; + k[SDLK_AUDIOMUTE] = Keyboard::KEY_AUDIOMUTE; + k[SDLK_MEDIASELECT] = Keyboard::KEY_MEDIASELECT; + + k[SDLK_BRIGHTNESSDOWN] = Keyboard::KEY_BRIGHTNESSDOWN; + k[SDLK_BRIGHTNESSUP] = Keyboard::KEY_BRIGHTNESSUP; + k[SDLK_DISPLAYSWITCH] = Keyboard::KEY_DISPLAYSWITCH; + k[SDLK_KBDILLUMTOGGLE] = Keyboard::KEY_KBDILLUMTOGGLE; + k[SDLK_KBDILLUMDOWN] = Keyboard::KEY_KBDILLUMDOWN; + k[SDLK_KBDILLUMUP] = Keyboard::KEY_KBDILLUMUP; + k[SDLK_EJECT] = Keyboard::KEY_EJECT; + k[SDLK_SLEEP] = Keyboard::KEY_SLEEP; + + return k; } -EnumMap::Entry Event::keyEntries[] = -{ - { love::keyboard::Keyboard::KEY_BACKSPACE, SDLK_BACKSPACE}, - { love::keyboard::Keyboard::KEY_TAB, SDLK_TAB}, - { love::keyboard::Keyboard::KEY_CLEAR, SDLK_CLEAR}, - { love::keyboard::Keyboard::KEY_RETURN, SDLK_RETURN}, - { love::keyboard::Keyboard::KEY_PAUSE, SDLK_PAUSE}, - { love::keyboard::Keyboard::KEY_ESCAPE, SDLK_ESCAPE }, - { love::keyboard::Keyboard::KEY_SPACE, SDLK_SPACE }, - { love::keyboard::Keyboard::KEY_EXCLAIM, SDLK_EXCLAIM }, - { love::keyboard::Keyboard::KEY_QUOTEDBL, SDLK_QUOTEDBL }, - { love::keyboard::Keyboard::KEY_HASH, SDLK_HASH }, - { love::keyboard::Keyboard::KEY_DOLLAR, SDLK_DOLLAR }, - { love::keyboard::Keyboard::KEY_AMPERSAND, SDLK_AMPERSAND }, - { love::keyboard::Keyboard::KEY_QUOTE, SDLK_QUOTE }, - { love::keyboard::Keyboard::KEY_LEFTPAREN, SDLK_LEFTPAREN }, - { love::keyboard::Keyboard::KEY_RIGHTPAREN, SDLK_RIGHTPAREN }, - { love::keyboard::Keyboard::KEY_ASTERISK, SDLK_ASTERISK }, - { love::keyboard::Keyboard::KEY_PLUS, SDLK_PLUS }, - { love::keyboard::Keyboard::KEY_COMMA, SDLK_COMMA }, - { love::keyboard::Keyboard::KEY_MINUS, SDLK_MINUS }, - { love::keyboard::Keyboard::KEY_PERIOD, SDLK_PERIOD }, - { love::keyboard::Keyboard::KEY_SLASH, SDLK_SLASH }, - { love::keyboard::Keyboard::KEY_0, SDLK_0 }, - { love::keyboard::Keyboard::KEY_1, SDLK_1 }, - { love::keyboard::Keyboard::KEY_2, SDLK_2 }, - { love::keyboard::Keyboard::KEY_3, SDLK_3 }, - { love::keyboard::Keyboard::KEY_4, SDLK_4 }, - { love::keyboard::Keyboard::KEY_5, SDLK_5 }, - { love::keyboard::Keyboard::KEY_6, SDLK_6 }, - { love::keyboard::Keyboard::KEY_7, SDLK_7 }, - { love::keyboard::Keyboard::KEY_8, SDLK_8 }, - { love::keyboard::Keyboard::KEY_9, SDLK_9 }, - { love::keyboard::Keyboard::KEY_COLON, SDLK_COLON }, - { love::keyboard::Keyboard::KEY_SEMICOLON, SDLK_SEMICOLON }, - { love::keyboard::Keyboard::KEY_LESS, SDLK_LESS }, - { love::keyboard::Keyboard::KEY_EQUALS, SDLK_EQUALS }, - { love::keyboard::Keyboard::KEY_GREATER, SDLK_GREATER }, - { love::keyboard::Keyboard::KEY_QUESTION, SDLK_QUESTION }, - { love::keyboard::Keyboard::KEY_AT, SDLK_AT }, - - { love::keyboard::Keyboard::KEY_LEFTBRACKET, SDLK_LEFTBRACKET }, - { love::keyboard::Keyboard::KEY_BACKSLASH, SDLK_BACKSLASH }, - { love::keyboard::Keyboard::KEY_RIGHTBRACKET, SDLK_RIGHTBRACKET }, - { love::keyboard::Keyboard::KEY_CARET, SDLK_CARET }, - { love::keyboard::Keyboard::KEY_UNDERSCORE, SDLK_UNDERSCORE }, - { love::keyboard::Keyboard::KEY_BACKQUOTE, SDLK_BACKQUOTE }, - { love::keyboard::Keyboard::KEY_A, SDLK_a }, - { love::keyboard::Keyboard::KEY_B, SDLK_b }, - { love::keyboard::Keyboard::KEY_C, SDLK_c }, - { love::keyboard::Keyboard::KEY_D, SDLK_d }, - { love::keyboard::Keyboard::KEY_E, SDLK_e }, - { love::keyboard::Keyboard::KEY_F, SDLK_f }, - { love::keyboard::Keyboard::KEY_G, SDLK_g }, - { love::keyboard::Keyboard::KEY_H, SDLK_h }, - { love::keyboard::Keyboard::KEY_I, SDLK_i }, - { love::keyboard::Keyboard::KEY_J, SDLK_j }, - { love::keyboard::Keyboard::KEY_K, SDLK_k }, - { love::keyboard::Keyboard::KEY_L, SDLK_l }, - { love::keyboard::Keyboard::KEY_M, SDLK_m }, - { love::keyboard::Keyboard::KEY_N, SDLK_n }, - { love::keyboard::Keyboard::KEY_O, SDLK_o }, - { love::keyboard::Keyboard::KEY_P, SDLK_p }, - { love::keyboard::Keyboard::KEY_Q, SDLK_q }, - { love::keyboard::Keyboard::KEY_R, SDLK_r }, - { love::keyboard::Keyboard::KEY_S, SDLK_s }, - { love::keyboard::Keyboard::KEY_T, SDLK_t }, - { love::keyboard::Keyboard::KEY_U, SDLK_u }, - { love::keyboard::Keyboard::KEY_V, SDLK_v }, - { love::keyboard::Keyboard::KEY_W, SDLK_w }, - { love::keyboard::Keyboard::KEY_X, SDLK_x }, - { love::keyboard::Keyboard::KEY_Y, SDLK_y }, - { love::keyboard::Keyboard::KEY_Z, SDLK_z }, - { love::keyboard::Keyboard::KEY_DELETE, SDLK_DELETE }, - - { love::keyboard::Keyboard::KEY_KP0, SDLK_KP0 }, - { love::keyboard::Keyboard::KEY_KP1, SDLK_KP1 }, - { love::keyboard::Keyboard::KEY_KP2, SDLK_KP2 }, - { love::keyboard::Keyboard::KEY_KP3, SDLK_KP3 }, - { love::keyboard::Keyboard::KEY_KP4, SDLK_KP4 }, - { love::keyboard::Keyboard::KEY_KP5, SDLK_KP5 }, - { love::keyboard::Keyboard::KEY_KP6, SDLK_KP6 }, - { love::keyboard::Keyboard::KEY_KP7, SDLK_KP7 }, - { love::keyboard::Keyboard::KEY_KP8, SDLK_KP8 }, - { love::keyboard::Keyboard::KEY_KP9, SDLK_KP9 }, - { love::keyboard::Keyboard::KEY_KP_PERIOD, SDLK_KP_PERIOD }, - { love::keyboard::Keyboard::KEY_KP_DIVIDE, SDLK_KP_DIVIDE }, - { love::keyboard::Keyboard::KEY_KP_MULTIPLY, SDLK_KP_MULTIPLY}, - { love::keyboard::Keyboard::KEY_KP_MINUS, SDLK_KP_MINUS }, - { love::keyboard::Keyboard::KEY_KP_PLUS, SDLK_KP_PLUS }, - { love::keyboard::Keyboard::KEY_KP_ENTER, SDLK_KP_ENTER }, - { love::keyboard::Keyboard::KEY_KP_EQUALS, SDLK_KP_EQUALS }, - - { love::keyboard::Keyboard::KEY_UP, SDLK_UP }, - { love::keyboard::Keyboard::KEY_DOWN, SDLK_DOWN }, - { love::keyboard::Keyboard::KEY_RIGHT, SDLK_RIGHT }, - { love::keyboard::Keyboard::KEY_LEFT, SDLK_LEFT }, - { love::keyboard::Keyboard::KEY_INSERT, SDLK_INSERT }, - { love::keyboard::Keyboard::KEY_HOME, SDLK_HOME }, - { love::keyboard::Keyboard::KEY_END, SDLK_END }, - { love::keyboard::Keyboard::KEY_PAGEUP, SDLK_PAGEUP }, - { love::keyboard::Keyboard::KEY_PAGEDOWN, SDLK_PAGEDOWN }, - - { love::keyboard::Keyboard::KEY_F1, SDLK_F1 }, - { love::keyboard::Keyboard::KEY_F2, SDLK_F2 }, - { love::keyboard::Keyboard::KEY_F3, SDLK_F3 }, - { love::keyboard::Keyboard::KEY_F4, SDLK_F4 }, - { love::keyboard::Keyboard::KEY_F5, SDLK_F5 }, - { love::keyboard::Keyboard::KEY_F6, SDLK_F6 }, - { love::keyboard::Keyboard::KEY_F7, SDLK_F7 }, - { love::keyboard::Keyboard::KEY_F8, SDLK_F8 }, - { love::keyboard::Keyboard::KEY_F9, SDLK_F9 }, - { love::keyboard::Keyboard::KEY_F10, SDLK_F10 }, - { love::keyboard::Keyboard::KEY_F11, SDLK_F11 }, - { love::keyboard::Keyboard::KEY_F12, SDLK_F12 }, - { love::keyboard::Keyboard::KEY_F13, SDLK_F13 }, - { love::keyboard::Keyboard::KEY_F14, SDLK_F14 }, - { love::keyboard::Keyboard::KEY_F15, SDLK_F15 }, - - { love::keyboard::Keyboard::KEY_NUMLOCK, SDLK_NUMLOCK }, - { love::keyboard::Keyboard::KEY_CAPSLOCK, SDLK_CAPSLOCK }, - { love::keyboard::Keyboard::KEY_SCROLLOCK, SDLK_SCROLLOCK }, - { love::keyboard::Keyboard::KEY_RSHIFT, SDLK_RSHIFT }, - { love::keyboard::Keyboard::KEY_LSHIFT, SDLK_LSHIFT }, - { love::keyboard::Keyboard::KEY_RCTRL, SDLK_RCTRL }, - { love::keyboard::Keyboard::KEY_LCTRL, SDLK_LCTRL }, - { love::keyboard::Keyboard::KEY_RALT, SDLK_RALT }, - { love::keyboard::Keyboard::KEY_LALT, SDLK_LALT }, - { love::keyboard::Keyboard::KEY_RMETA, SDLK_RMETA }, - { love::keyboard::Keyboard::KEY_LMETA, SDLK_LMETA }, - { love::keyboard::Keyboard::KEY_LSUPER, SDLK_LSUPER }, - { love::keyboard::Keyboard::KEY_RSUPER, SDLK_RSUPER }, - { love::keyboard::Keyboard::KEY_MODE, SDLK_MODE }, - { love::keyboard::Keyboard::KEY_COMPOSE, SDLK_COMPOSE }, - - { love::keyboard::Keyboard::KEY_HELP, SDLK_HELP }, - { love::keyboard::Keyboard::KEY_PRINT, SDLK_PRINT }, - { love::keyboard::Keyboard::KEY_SYSREQ, SDLK_SYSREQ }, - { love::keyboard::Keyboard::KEY_BREAK, SDLK_BREAK }, - { love::keyboard::Keyboard::KEY_MENU, SDLK_MENU }, - { love::keyboard::Keyboard::KEY_POWER, SDLK_POWER }, - { love::keyboard::Keyboard::KEY_EURO, SDLK_EURO }, - { love::keyboard::Keyboard::KEY_UNDO, SDLK_UNDO }, - - { love::keyboard::Keyboard::KEY_UNKNOWN, SDLK_UNKNOWN }, -}; - -EnumMap Event::keys(Event::keyEntries, sizeof(Event::keyEntries)); +std::map Event::keys = Event::createKeyMap(); EnumMap::Entry Event::buttonEntries[] = { { love::mouse::Mouse::BUTTON_LEFT, SDL_BUTTON_LEFT}, { love::mouse::Mouse::BUTTON_MIDDLE, SDL_BUTTON_MIDDLE}, { love::mouse::Mouse::BUTTON_RIGHT, SDL_BUTTON_RIGHT}, - { love::mouse::Mouse::BUTTON_WHEELUP, SDL_BUTTON_WHEELUP}, - { love::mouse::Mouse::BUTTON_WHEELDOWN, SDL_BUTTON_WHEELDOWN}, { love::mouse::Mouse::BUTTON_X1, SDL_BUTTON_X1}, { love::mouse::Mouse::BUTTON_X2, SDL_BUTTON_X2}, }; EnumMap Event::buttons(Event::buttonEntries, sizeof(Event::buttonEntries)); -EnumMap::Entry Event::hatEntries[] = -{ - {love::joystick::Joystick::HAT_CENTERED, SDL_HAT_CENTERED}, - {love::joystick::Joystick::HAT_UP, SDL_HAT_UP}, - {love::joystick::Joystick::HAT_RIGHT, SDL_HAT_RIGHT}, - {love::joystick::Joystick::HAT_DOWN, SDL_HAT_DOWN}, - {love::joystick::Joystick::HAT_LEFT, SDL_HAT_LEFT}, - {love::joystick::Joystick::HAT_RIGHTUP, SDL_HAT_RIGHTUP}, - {love::joystick::Joystick::HAT_RIGHTDOWN, SDL_HAT_RIGHTDOWN}, - {love::joystick::Joystick::HAT_LEFTUP, SDL_HAT_LEFTUP}, - {love::joystick::Joystick::HAT_LEFTDOWN, SDL_HAT_LEFTDOWN}, -}; - -EnumMap Event::hats(Event::hatEntries, sizeof(Event::hatEntries)); - } // sdl } // event } // love diff --git a/src/modules/event/sdl/Event.h b/src/modules/event/sdl/Event.h index 93ab126df..ab5a0a9a4 100644 --- a/src/modules/event/sdl/Event.h +++ b/src/modules/event/sdl/Event.h @@ -29,6 +29,9 @@ // SDL #include +// STL +#include + namespace love { namespace event @@ -44,6 +47,7 @@ public: const char *getName() const; Event(); + virtual ~Event(); /** * Pumps the event queue. This function gathers all the pending input information @@ -66,15 +70,15 @@ public: private: - Message *convert(SDL_Event &e); - const char *convertUnicode(Uint16 codepoint) const; + Message *convert(const SDL_Event &e) const; + Message *convertJoystickEvent(const SDL_Event &e) const; + Message *convertWindowEvent(const SDL_Event &e) const; + + static std::map createKeyMap(); + static std::map keys; - static EnumMap::Entry keyEntries[]; - static EnumMap keys; static EnumMap::Entry buttonEntries[]; static EnumMap buttons; - static EnumMap::Entry hatEntries[]; - static EnumMap hats; }; // System diff --git a/src/modules/event/sdl/wrap_Event.cpp b/src/modules/event/sdl/wrap_Event.cpp index 5a516f397..551eaf1f6 100644 --- a/src/modules/event/sdl/wrap_Event.cpp +++ b/src/modules/event/sdl/wrap_Event.cpp @@ -127,9 +127,9 @@ extern "C" int luaopen_love_event(lua_State *L) { instance = new Event(); } - catch(Exception &e) + catch (love::Exception &e) { - return luaL_error(L, e.what()); + return luaL_error(L, "%s", e.what()); } } else diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index fde7bb802..c975c6f83 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -108,6 +108,11 @@ public: virtual ~Graphics(); + /** + * Sets the current graphics display viewport dimensions. + **/ + virtual void setViewportSize(int width, int height) = 0; + /** * Sets the current graphics display viewport and initializes the renderer. * @param width The viewport width. diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 97137a050..b551aee47 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -52,7 +52,7 @@ Graphics::Graphics() , created(false) , savedState() { - currentWindow = love::window::sdl::Window::getSingleton(); + currentWindow = love::window::sdl::Window::createSingleton(); if (currentWindow->isCreated()) setMode(currentWindow->getWidth(), currentWindow->getHeight()); @@ -113,6 +113,27 @@ void Graphics::restoreState(const DisplayState &s) setColorMask(s.colorMask[0], s.colorMask[1], s.colorMask[2], s.colorMask[3]); } +void Graphics::setViewportSize(int width, int height) +{ + this->width = width; + this->height = height; + + if (!isCreated()) + return; + + // Set the viewport to top-left corner + gl.setViewport(OpenGL::Viewport(0, 0, width, height)); + + // Reset the projection matrix + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + // Set up orthographic view (no depth) + glOrtho(0.0, width, height, 0.0, -1.0, 1.0); + + glMatrixMode(GL_MODELVIEW); +} + bool Graphics::setMode(int width, int height) { this->width = width; @@ -121,6 +142,10 @@ bool Graphics::setMode(int width, int height) // Okay, setup OpenGL. gl.initContext(); + created = true; + + setViewportSize(width, height); + // Make sure antialiasing works when set elsewhere if (GLEE_VERSION_1_3 || GLEE_ARB_multisample) glEnable(GL_MULTISAMPLE); @@ -147,16 +172,6 @@ bool Graphics::setMode(int width, int height) glEnable(GL_TEXTURE_2D); gl.setTextureUnit(0); - // Set the viewport to top-left corner - gl.setViewport(OpenGL::Viewport(0, 0, width, height)); - - // Reset the projection matrix - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - // Set up orthographic view (no depth) - glOrtho(0.0, width, height, 0.0, -1.0, 1.0); - // Reset modelview matrix glMatrixMode(GL_MODELVIEW); glLoadIdentity(); @@ -179,8 +194,6 @@ bool Graphics::setMode(int width, int height) glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, &matrixLimit); matrixLimit -= 5; - created = true; - return true; } diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 78bd06cac..4cb1fa32e 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -112,6 +112,7 @@ public: void restoreState(const DisplayState &s); + virtual void setViewportSize(int width, int height); virtual bool setMode(int width, int height); virtual void unSetMode(); diff --git a/src/modules/joystick/Joystick.cpp b/src/modules/joystick/Joystick.cpp index fe9a04a62..11870a416 100644 --- a/src/modules/joystick/Joystick.cpp +++ b/src/modules/joystick/Joystick.cpp @@ -18,15 +18,26 @@ * 3. This notice may not be removed or altered from any source distribution. **/ +// LOVE #include "Joystick.h" +// STL +#include + namespace love { namespace joystick { -Joystick::~Joystick() +float Joystick::clampval(float x) const { + if (fabsf(x) < 0.01) + return 0.0f; + + if (x < -0.99f) return -1.0f; + if (x > 0.99f) return 1.0f; + + return x; } bool Joystick::getConstant(const char *in, Joystick::Hat &out) @@ -34,11 +45,41 @@ bool Joystick::getConstant(const char *in, Joystick::Hat &out) return hats.find(in, out); } -bool Joystick::getConstant(Joystick::Hat in, const char *&out) +bool Joystick::getConstant(Joystick::Hat in, const char *&out) { return hats.find(in, out); } +bool Joystick::getConstant(const char *in, Joystick::GamepadAxis &out) +{ + return gpAxes.find(in, out); +} + +bool Joystick::getConstant(Joystick::GamepadAxis in, const char *&out) +{ + return gpAxes.find(in, out); +} + +bool Joystick::getConstant(const char *in, Joystick::GamepadButton &out) +{ + return gpButtons.find(in, out); +} + +bool Joystick::getConstant(Joystick::GamepadButton in, const char *&out) +{ + return gpButtons.find(in, out); +} + +bool Joystick::getConstant(const char *in, Joystick::InputType &out) +{ + return inputTypes.find(in, out); +} + +bool Joystick::getConstant(Joystick::InputType in, const char *&out) +{ + return inputTypes.find(in, out); +} + StringMap::Entry Joystick::hatEntries[] = { {"c", Joystick::HAT_CENTERED}, @@ -54,5 +95,47 @@ StringMap::Entry Joystick::hatEntries[] = StringMap Joystick::hats(Joystick::hatEntries, sizeof(Joystick::hatEntries)); +StringMap::Entry Joystick::gpAxisEntries[] = +{ + {"leftx", GAMEPAD_AXIS_LEFTX}, + {"lefty", GAMEPAD_AXIS_LEFTY}, + {"rightx", GAMEPAD_AXIS_RIGHTX}, + {"righty", GAMEPAD_AXIS_RIGHTY}, + {"triggerleft", GAMEPAD_AXIS_TRIGGERLEFT}, + {"triggerright", GAMEPAD_AXIS_TRIGGERRIGHT}, +}; + +StringMap Joystick::gpAxes(Joystick::gpAxisEntries, sizeof(Joystick::gpAxisEntries)); + +StringMap::Entry Joystick::gpButtonEntries[] = +{ + {"a", GAMEPAD_BUTTON_A}, + {"b", GAMEPAD_BUTTON_B}, + {"x", GAMEPAD_BUTTON_X}, + {"y", GAMEPAD_BUTTON_Y}, + {"back", GAMEPAD_BUTTON_BACK}, + {"guide", GAMEPAD_BUTTON_GUIDE}, + {"start", GAMEPAD_BUTTON_START}, + {"leftstick", GAMEPAD_BUTTON_LEFTSTICK}, + {"rightstick", GAMEPAD_BUTTON_RIGHTSTICK}, + {"leftshoulder", GAMEPAD_BUTTON_LEFTSHOULDER}, + {"rightshoulder", GAMEPAD_BUTTON_RIGHTSHOULDER}, + {"dpup", GAMEPAD_BUTTON_DPAD_UP}, + {"dpdown", GAMEPAD_BUTTON_DPAD_DOWN}, + {"dpleft", GAMEPAD_BUTTON_DPAD_LEFT}, + {"dpright", GAMEPAD_BUTTON_DPAD_RIGHT}, +}; + +StringMap Joystick::gpButtons(Joystick::gpButtonEntries, sizeof(Joystick::gpButtonEntries)); + +StringMap::Entry Joystick::inputTypeEntries[] = +{ + {"axis", Joystick::INPUT_TYPE_AXIS}, + {"button", Joystick::INPUT_TYPE_BUTTON}, + {"hat", Joystick::INPUT_TYPE_HAT}, +}; + +StringMap Joystick::inputTypes(Joystick::inputTypeEntries, sizeof(Joystick::inputTypeEntries)); + } // joystick } // love diff --git a/src/modules/joystick/Joystick.h b/src/modules/joystick/Joystick.h index c0dd71727..58fec07ce 100644 --- a/src/modules/joystick/Joystick.h +++ b/src/modules/joystick/Joystick.h @@ -22,18 +22,23 @@ #define LOVE_JOYSTICK_JOYSTICK_H // LOVE -#include "common/Module.h" +#include "common/Object.h" #include "common/StringMap.h" +// stdlib +#include +#include + namespace love { namespace joystick { -class Joystick : public Module +class Joystick : public Object { public: + // Joystick hat values. enum Hat { HAT_INVALID, @@ -49,19 +54,142 @@ public: HAT_MAX_ENUM = 16 }; - virtual ~Joystick(); + // Valid Gamepad axes. + enum GamepadAxis + { + GAMEPAD_AXIS_INVALID, + GAMEPAD_AXIS_LEFTX, + GAMEPAD_AXIS_LEFTY, + GAMEPAD_AXIS_RIGHTX, + GAMEPAD_AXIS_RIGHTY, + GAMEPAD_AXIS_TRIGGERLEFT, + GAMEPAD_AXIS_TRIGGERRIGHT, + GAMEPAD_AXIS_MAX_ENUM + }; + + // Valid Gamepad buttons. + enum GamepadButton + { + GAMEPAD_BUTTON_INVALID, + GAMEPAD_BUTTON_A, + GAMEPAD_BUTTON_B, + GAMEPAD_BUTTON_X, + GAMEPAD_BUTTON_Y, + GAMEPAD_BUTTON_BACK, + GAMEPAD_BUTTON_GUIDE, + GAMEPAD_BUTTON_START, + GAMEPAD_BUTTON_LEFTSTICK, + GAMEPAD_BUTTON_RIGHTSTICK, + GAMEPAD_BUTTON_LEFTSHOULDER, + GAMEPAD_BUTTON_RIGHTSHOULDER, + GAMEPAD_BUTTON_DPAD_UP, + GAMEPAD_BUTTON_DPAD_DOWN, + GAMEPAD_BUTTON_DPAD_LEFT, + GAMEPAD_BUTTON_DPAD_RIGHT, + GAMEPAD_BUTTON_MAX_ENUM + }; + + // Different types of inputs for a joystick. + enum InputType + { + INPUT_TYPE_AXIS, + INPUT_TYPE_BUTTON, + INPUT_TYPE_HAT, + INPUT_TYPE_MAX_ENUM + }; + + // Represents a gamepad input value, e.g. the "x" button or the left trigger. + struct GamepadInput + { + InputType type; + union + { + GamepadAxis axis; + GamepadButton button; + }; + }; + + // Represents a joystick input value, e.g. button 6 or axis 1. + struct JoystickInput + { + InputType type; + union + { + int axis; + int button; + struct + { + int index; + Hat value; + } hat; + }; + }; + + virtual ~Joystick() {} + + virtual bool open(int deviceindex) = 0; + virtual void close() = 0; + + virtual bool isConnected() const = 0; + + virtual const char *getName() const = 0; + + virtual int getAxisCount() const = 0; + virtual int getButtonCount() const = 0; + virtual int getHatCount() const = 0; + + virtual float getAxis(int axisindex) const = 0; + virtual std::vector getAxes() const = 0; + virtual Hat getHat(int hatindex) const = 0; + + virtual bool isDown(const std::vector &buttonlist) const = 0; + + virtual bool openGamepad(int deviceindex) = 0; + virtual bool isGamepad() const = 0; + + virtual float getGamepadAxis(GamepadAxis axis) const = 0; + virtual bool isGamepadDown(const std::vector &blist) const = 0; + + virtual void *getHandle() const = 0; + + virtual std::string getGUID() const = 0; + virtual int getInstanceID() const = 0; + virtual int getID() const = 0; static bool getConstant(const char *in, Hat &out); - static bool getConstant(Hat in, const char *&out); + static bool getConstant(Hat in, const char *&out); + + static bool getConstant(const char *in, GamepadAxis &out); + static bool getConstant(GamepadAxis in, const char *&out); + + static bool getConstant(const char *in, GamepadButton &out); + static bool getConstant(GamepadButton in, const char *&out); + + static bool getConstant(const char *in, InputType &out); + static bool getConstant(InputType in, const char *&out); + +protected: + + float clampval(float x) const; private: static StringMap::Entry hatEntries[]; static StringMap hats; + static StringMap::Entry gpAxisEntries[]; + static StringMap gpAxes; + + static StringMap::Entry gpButtonEntries[]; + static StringMap gpButtons; + + static StringMap::Entry inputTypeEntries[]; + static StringMap inputTypes; + }; // Joystick } // joystick } // love -#endif // LOVE_JOYSTICK_JOYSTICK_H \ No newline at end of file + +#endif // LOVE_JOYSTICK_JOYSTICK_H diff --git a/src/modules/joystick/JoystickModule.h b/src/modules/joystick/JoystickModule.h new file mode 100644 index 000000000..b437d0bd3 --- /dev/null +++ b/src/modules/joystick/JoystickModule.h @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#ifndef LOVE_JOYSTICK_JOYSTICK_MODULE_H +#define LOVE_JOYSTICK_JOYSTICK_MODULE_H + +// LOVE +#include "common/Module.h" +#include "Joystick.h" + +namespace love +{ +namespace joystick +{ + +class JoystickModule : public Module +{ +public: + + virtual ~JoystickModule() {} + + /** + * Adds a connected Joystick device and opens it for use. + * Returns NULL if the Joystick could not be added. + **/ + virtual Joystick *addJoystick(int deviceindex) = 0; + + /** + * Removes a disconnected Joystick device. + **/ + virtual void removeJoystick(Joystick *joystick) = 0; + + /** + * Gets a connected Joystick from its unique Instance ID. + * Returns NULL if the instance ID does not correspond to a connected stick. + **/ + virtual Joystick *getJoystickFromID(int instanceid) = 0; + + /** + * Gets a connected Joystick. + * Returns NULL if joyindex is not in the range of [0, getJoystickCount()). + **/ + virtual Joystick *getJoystick(int joyindex) = 0; + + /** + * Gets the index of a connected joystick. + * Returns -1 if the joystick is not connected. + **/ + virtual int getIndex(const Joystick *joystick) = 0; + + /** + * Gets the number of currently connected Joysticks. + **/ + virtual int getJoystickCount() const = 0; + + /** + * Determines whether the Joystick at the specified index is a recognized + * Gamepad. + **/ + virtual bool isGamepad(int joyindex) const = 0; + + /** + * Sets the virtual Gamepad mapping for a joystick input value for all + * joystick devices with the specified joystick GUID. + * If any joysticks with the specified GUID are connected, they will be + * added as Gamepads if they aren't already, otherwise their Gamepad mapping + * will be updated. + **/ + virtual bool setGamepadMapping(const std::string &guid, Joystick::GamepadInput gpinput, Joystick::JoystickInput joyinput) = 0; + + /** + * Gets the joystick input value the gamepad input value is bound to for the + * specified joystick GUID. + **/ + virtual Joystick::JoystickInput getGamepadMapping(const std::string &guid, Joystick::GamepadInput gpinput) = 0; + +}; // JoystickModule + +} // joystick +} // love + +#endif // LOVE_JOYSTICK_JOYSTICK_MODULE_H diff --git a/src/modules/joystick/sdl/Joystick.cpp b/src/modules/joystick/sdl/Joystick.cpp index 1926b4238..f56ddc108 100644 --- a/src/modules/joystick/sdl/Joystick.cpp +++ b/src/modules/joystick/sdl/Joystick.cpp @@ -20,9 +20,6 @@ #include "Joystick.h" -// STD -#include - namespace love { namespace joystick @@ -30,206 +27,260 @@ namespace joystick namespace sdl { -Joystick::Joystick() - : joysticks(0) +Joystick::Joystick(int id) + : joyhandle(0) + , controller(0) + , instanceid(-1) + , id(id) { - // Init the SDL joystick system. - if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) - throw love::Exception("%s", SDL_GetError()); +} - // Start joystick event watching. - SDL_JoystickEventState(SDL_ENABLE); - - // Open all connected joysticks. - int numjoysticks = getJoystickCount(); - if (numjoysticks > 0) - this->joysticks = (SDL_Joystick **)calloc(numjoysticks, sizeof(SDL_Joystick *)); - - for (int i = 0; iopen(i); +Joystick::Joystick(int id, int joyindex) + : joyhandle(0) + , controller(0) + , instanceid(-1) + , id(id) +{ + open(joyindex); } Joystick::~Joystick() { - // Closes any open joysticks. - for (int i = 0; i != getJoystickCount(); i++) - { - if (isOpen(i)) - close(i); - } - - free(joysticks); - - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + close(); } -void Joystick::reload() +bool Joystick::open(int deviceindex) { - // Closes any open joysticks. - for (int i = 0; i != getJoystickCount(); i++) + close(); + + joyhandle = SDL_JoystickOpen(deviceindex); + + if (joyhandle) { - if (isOpen(i)) - close(i); + instanceid = SDL_JoystickInstanceID(joyhandle); + + // SDL_JoystickGetGUIDString uses 32 bytes plus the null terminator. + char cstr[33]; + + SDL_JoystickGUID sdlguid = SDL_JoystickGetGUID(joyhandle); + SDL_JoystickGetGUIDString(sdlguid, cstr, (int) sizeof(cstr)); + + guid = std::string(cstr); + + // See if SDL thinks this is a Game Controller. + openGamepad(deviceindex); + + // Prefer the GameController name. + if (controller) + name = SDL_GameControllerName(controller); + else + name = SDL_JoystickName(joyhandle); } - free(joysticks); + return isConnected(); +} - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); +void Joystick::close() +{ + if (controller) + SDL_GameControllerClose(controller); - if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) - throw love::Exception("%s", SDL_GetError()); + if (joyhandle) + SDL_JoystickClose(joyhandle); - int numjoysticks = this->getJoystickCount(); - if (numjoysticks > 0) - this->joysticks = (SDL_Joystick **)calloc(numjoysticks, sizeof(SDL_Joystick *)); + joyhandle = 0; + controller = 0; + instanceid = -1; +} - for (int i = 0; iopen(i); +bool Joystick::isConnected() const +{ + return joyhandle != 0 && SDL_JoystickGetAttached(joyhandle); } const char *Joystick::getName() const { - return "love.joystick.sdl"; + // Use the saved name if this Joystick isn't connected anymore. + if (!isConnected()) + return name.c_str(); + + // Prefer SDL's GameController name, if possible. + if (isGamepad()) + return SDL_GameControllerName(controller); + + return SDL_JoystickName(joyhandle); } -bool Joystick::checkIndex(int index) +int Joystick::getAxisCount() const { - return index >= 0 && index < getJoystickCount(); + return isConnected() ? SDL_JoystickNumAxes(joyhandle) : 0; } -int Joystick::getJoystickCount() +int Joystick::getButtonCount() const { - int num = SDL_NumJoysticks(); - return num < 0 ? 0 : num; + return isConnected() ? SDL_JoystickNumButtons(joyhandle) : 0; } -const char *Joystick::getName(int index) +int Joystick::getHatCount() const { - return SDL_JoystickName(index); + return isConnected() ? SDL_JoystickNumHats(joyhandle) : 0; } -bool Joystick::open(int index) +float Joystick::getAxis(int axisindex) const { - if (isOpen(index)) - return true; - - if (!checkIndex(index)) - return false; - - if (!(joysticks[index] = SDL_JoystickOpen(index))) - return false; - - return true; -} - -bool Joystick::isOpen(int index) -{ - if (!checkIndex(index)) - return false; - - return joysticks[index] != 0 ? true : false; -} - -bool Joystick::verifyJoystick(int index) -{ - if (!checkIndex(index)) - return false; - - if (!isOpen(index)) - return false; - - return true; -} - -int Joystick::getAxisCount(int index) -{ - return verifyJoystick(index) ? SDL_JoystickNumAxes(joysticks[index]) : 0; -} - -int Joystick::getButtonCount(int index) -{ - return verifyJoystick(index) ? SDL_JoystickNumButtons(joysticks[index]) : 0; -} - -int Joystick::getHatCount(int index) -{ - return verifyJoystick(index) ? SDL_JoystickNumHats(joysticks[index]) : 0; -} - -float Joystick::clampval(float x) -{ - if (fabs((double)x) < 0.01) return 0.0f; - if (x < -0.99f) return -1.0f; - if (x > 0.99f) return 1.0f; - return x; -} - -float Joystick::getAxis(int index, int axis) -{ - if (!verifyJoystick(index)) + if (!isConnected() || axisindex < 0 || axisindex >= getAxisCount()) return 0; - if (axis >= getAxisCount(index)) - return 0; - - return clampval(((float)SDL_JoystickGetAxis(joysticks[index], axis))/32768.0f); + return clampval(((float) SDL_JoystickGetAxis(joyhandle, axisindex))/32768.0f); } -int Joystick::getAxes(lua_State *L) +std::vector Joystick::getAxes() const { - int index = luaL_checkint(L, 1) - 1; + std::vector axes; + int count = getAxisCount(); - if (!verifyJoystick(index)) - return 0; + if (!isConnected() || count <= 0) + return axes; - int num = getAxisCount(index); + axes.reserve(count); - for (int i = 0; i= getHatCount()) + return h; + + getConstant(SDL_JoystickGetHat(joyhandle, hatindex), h); + + return h; +} + +bool Joystick::isDown(const std::vector &buttonlist) const +{ + if (!isConnected()) return false; - int num = getButtonCount(index); + int num = getButtonCount(); - for (int button = *buttonlist; button != -1; button = *(++buttonlist)) + for (size_t i = 0; i < buttonlist.size(); i++) { - if (button >= 0 && button < num && SDL_JoystickGetButton(joysticks[index], button) == 1) + int button = buttonlist[i]; + if (button >= 0 && button < num && SDL_JoystickGetButton(joyhandle, button) == 1) return true; } return false; } -Joystick::Hat Joystick::getHat(int index, int hat) +bool Joystick::openGamepad(int deviceindex) { - Hat h = HAT_INVALID; + if (!SDL_IsGameController(deviceindex)) + return false; - if (!verifyJoystick(index)) - return h; + if (isGamepad()) + { + SDL_GameControllerClose(controller); + controller = 0; + } - if (hat >= getHatCount(index)) - return h; - - hats.find(SDL_JoystickGetHat(joysticks[index], hat), h); - - return h; + controller = SDL_GameControllerOpen(deviceindex); + return isGamepad(); } -void Joystick::close(int index) +bool Joystick::isGamepad() const { - if (!checkIndex(index)) - return; + return controller != 0; +} - if (joysticks[index]!=0) +float Joystick::getGamepadAxis(love::joystick::Joystick::GamepadAxis axis) const +{ + if (!isConnected() || !isGamepad()) + return 0.f; + + SDL_GameControllerAxis sdlaxis; + if (!getConstant(axis, sdlaxis)) + return 0.f; + + Sint16 value = SDL_GameControllerGetAxis(controller, sdlaxis); + + return clampval((float) value / 32768.0f); +} + +bool Joystick::isGamepadDown(const std::vector &blist) const +{ + if (!isConnected() || !isGamepad()) + return false; + + SDL_GameControllerButton sdlbutton; + + for (size_t i = 0; i < blist.size(); i++) { - SDL_JoystickClose(joysticks[index]); - joysticks[index] = 0; + if (!getConstant(blist[i], sdlbutton)) + continue; + + if (SDL_GameControllerGetButton(controller, sdlbutton) == 1) + return true; } + + return false; +} + +void *Joystick::getHandle() const +{ + return joyhandle; +} + +std::string Joystick::getGUID() const +{ + // SDL2's GUIDs identify *classes* of devices, instead of unique devices. + return guid; +} + +int Joystick::getInstanceID() const +{ + return instanceid; +} + +int Joystick::getID() const +{ + return id; +} + +bool Joystick::getConstant(Uint8 in, Joystick::Hat &out) +{ + return hats.find(in, out); +} + +bool Joystick::getConstant(Joystick::Hat in, Uint8 &out) +{ + return hats.find(in, out); +} + +bool Joystick::getConstant(SDL_GameControllerAxis in, Joystick::GamepadAxis &out) +{ + return gpAxes.find(in, out); +} + +bool Joystick::getConstant(Joystick::GamepadAxis in, SDL_GameControllerAxis &out) +{ + return gpAxes.find(in, out); +} + +bool Joystick::getConstant(SDL_GameControllerButton in, Joystick::GamepadButton &out) +{ + return gpButtons.find(in, out); +} + +bool Joystick::getConstant(Joystick::GamepadButton in, SDL_GameControllerButton &out) +{ + return gpButtons.find(in, out); } EnumMap::Entry Joystick::hatEntries[] = @@ -247,6 +298,39 @@ EnumMap::Entry Joystick::hatEntrie EnumMap Joystick::hats(Joystick::hatEntries, sizeof(Joystick::hatEntries)); +EnumMap::Entry Joystick::gpAxisEntries[] = +{ + {Joystick::GAMEPAD_AXIS_LEFTX, SDL_CONTROLLER_AXIS_LEFTX}, + {Joystick::GAMEPAD_AXIS_LEFTY, SDL_CONTROLLER_AXIS_LEFTY}, + {Joystick::GAMEPAD_AXIS_RIGHTX, SDL_CONTROLLER_AXIS_RIGHTX}, + {Joystick::GAMEPAD_AXIS_RIGHTY, SDL_CONTROLLER_AXIS_RIGHTY}, + {Joystick::GAMEPAD_AXIS_TRIGGERLEFT, SDL_CONTROLLER_AXIS_TRIGGERLEFT}, + {Joystick::GAMEPAD_AXIS_TRIGGERRIGHT, SDL_CONTROLLER_AXIS_TRIGGERRIGHT}, +}; + +EnumMap Joystick::gpAxes(Joystick::gpAxisEntries, sizeof(Joystick::gpAxisEntries)); + +EnumMap::Entry Joystick::gpButtonEntries[] = +{ + {Joystick::GAMEPAD_BUTTON_A, SDL_CONTROLLER_BUTTON_A}, + {Joystick::GAMEPAD_BUTTON_B, SDL_CONTROLLER_BUTTON_B}, + {Joystick::GAMEPAD_BUTTON_X, SDL_CONTROLLER_BUTTON_X}, + {Joystick::GAMEPAD_BUTTON_Y, SDL_CONTROLLER_BUTTON_Y}, + {Joystick::GAMEPAD_BUTTON_BACK, SDL_CONTROLLER_BUTTON_BACK}, + {Joystick::GAMEPAD_BUTTON_GUIDE, SDL_CONTROLLER_BUTTON_GUIDE}, + {Joystick::GAMEPAD_BUTTON_START, SDL_CONTROLLER_BUTTON_START}, + {Joystick::GAMEPAD_BUTTON_LEFTSTICK, SDL_CONTROLLER_BUTTON_LEFTSTICK}, + {Joystick::GAMEPAD_BUTTON_RIGHTSTICK, SDL_CONTROLLER_BUTTON_RIGHTSTICK}, + {Joystick::GAMEPAD_BUTTON_LEFTSHOULDER, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, + {Joystick::GAMEPAD_BUTTON_RIGHTSHOULDER, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, + {Joystick::GAMEPAD_BUTTON_DPAD_UP, SDL_CONTROLLER_BUTTON_DPAD_UP}, + {Joystick::GAMEPAD_BUTTON_DPAD_DOWN, SDL_CONTROLLER_BUTTON_DPAD_DOWN}, + {Joystick::GAMEPAD_BUTTON_DPAD_LEFT, SDL_CONTROLLER_BUTTON_DPAD_LEFT}, + {Joystick::GAMEPAD_BUTTON_DPAD_RIGHT, SDL_CONTROLLER_BUTTON_DPAD_RIGHT}, +}; + +EnumMap Joystick::gpButtons(Joystick::gpButtonEntries, sizeof(Joystick::gpButtonEntries)); + } // sdl } // joystick } // love diff --git a/src/modules/joystick/sdl/Joystick.h b/src/modules/joystick/sdl/Joystick.h index 599920384..a933b48aa 100644 --- a/src/modules/joystick/sdl/Joystick.h +++ b/src/modules/joystick/sdl/Joystick.h @@ -26,7 +26,8 @@ #include "common/EnumMap.h" // SDL -#include +#include +#include namespace love { @@ -37,38 +38,74 @@ namespace sdl class Joystick : public love::joystick::Joystick { -private: - SDL_Joystick **joysticks; public: - Joystick(); + + Joystick(int id); + Joystick(int id, int joyindex); + virtual ~Joystick(); - // Implements Module. + bool open(int deviceindex); + void close(); + + bool isConnected() const; + const char *getName() const; - void reload(); - bool checkIndex(int index); - int getJoystickCount(); - const char *getName(int index); - bool open(int index); - bool isOpen(int index); - bool verifyJoystick(int index); - int getAxisCount(int index); - int getButtonCount(int index); - int getHatCount(int index); - float clampval(float x); - float getAxis(int index, int axis); - int getAxes(lua_State *L); - bool isDown(int index, int *buttonlist); - Hat getHat(int index, int hat); - void close(int index); + int getAxisCount() const; + int getButtonCount() const; + int getHatCount() const; + + float getAxis(int axisindex) const; + std::vector getAxes() const; + Hat getHat(int hatindex) const; + + bool isDown(const std::vector &buttonlist) const; + + bool openGamepad(int deviceindex); + bool isGamepad() const; + + float getGamepadAxis(GamepadAxis axis) const; + bool isGamepadDown(const std::vector &blist) const; + + void *getHandle() const; + + std::string getGUID() const; + int getInstanceID() const; + int getID() const; + + static bool getConstant(Hat in, Uint8 &out); + static bool getConstant(Uint8 in, Hat &out); + + static bool getConstant(SDL_GameControllerAxis in, GamepadAxis &out); + static bool getConstant(GamepadAxis in, SDL_GameControllerAxis &out); + + static bool getConstant(SDL_GameControllerButton in, GamepadButton &out); + static bool getConstant(GamepadButton in, SDL_GameControllerButton &out); private: + Joystick() {} + + SDL_Joystick *joyhandle; + SDL_GameController *controller; + + SDL_JoystickID instanceid; + std::string guid; + int id; + + std::string name; + static EnumMap::Entry hatEntries[]; static EnumMap hats; -}; // Joystick + static EnumMap::Entry gpAxisEntries[]; + static EnumMap gpAxes; + + static EnumMap::Entry gpButtonEntries[]; + static EnumMap gpButtons; + +}; } // sdl } // joystick diff --git a/src/modules/joystick/sdl/JoystickModule.cpp b/src/modules/joystick/sdl/JoystickModule.cpp new file mode 100644 index 000000000..3c1a75054 --- /dev/null +++ b/src/modules/joystick/sdl/JoystickModule.cpp @@ -0,0 +1,450 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#include "common/config.h" +#include "JoystickModule.h" +#include "Joystick.h" + +// SDL +#include + +// C++ +#include +#include + +// C +#include + +namespace love +{ +namespace joystick +{ +namespace sdl +{ + +JoystickModule::JoystickModule() +{ + // Init the SDL Joystick and Game Controller systems. + if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) + throw love::Exception("%s", SDL_GetError()); + + // Start joystick event watching. Joysticks are automatically added and + // removed via love.event. + SDL_JoystickEventState(SDL_ENABLE); + SDL_GameControllerEventState(SDL_ENABLE); +} + +JoystickModule::~JoystickModule() +{ + // Close any open Joysticks. + for (size_t i = 0; i < joysticks.size(); i++) + { + joysticks[i]->close(); + joysticks[i]->release(); + } + + SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER); +} + +const char *JoystickModule::getName() const +{ + return "love.joystick.sdl"; +} + +love::joystick::Joystick *JoystickModule::getJoystick(int joyindex) +{ + if (joyindex < 0 || (size_t) joyindex >= activeSticks.size()) + return 0; + + return activeSticks[joyindex]; +} + +int JoystickModule::getIndex(const love::joystick::Joystick *joystick) +{ + for (size_t i = 0; i < activeSticks.size(); i++) + { + if (activeSticks[i] == joystick) + return i; + } + + // Joystick is not connected. + return -1; +} + +int JoystickModule::getJoystickCount() const +{ + return (int) activeSticks.size(); +} + +bool JoystickModule::isGamepad(int joyindex) const +{ + if (joyindex < 0 || (size_t) joyindex >= activeSticks.size()) + return false; + + return activeSticks[joyindex]->isGamepad(); +} + +love::joystick::Joystick *JoystickModule::getJoystickFromID(int instanceid) +{ + for (size_t i = 0; i < activeSticks.size(); i++) + { + if (instanceid == activeSticks[i]->getInstanceID()) + return activeSticks[i]; + } + + return 0; +} + +love::joystick::Joystick *JoystickModule::addJoystick(int deviceindex) +{ + if (deviceindex < 0 || deviceindex >= SDL_NumJoysticks()) + return 0; + + std::string guidstr = getDeviceGUID(deviceindex); + + joystick::Joystick *joystick = 0; + + for (size_t i = 0; i < joysticks.size(); i++) + { + // Try to re-use a disconnected Joystick with the same GUID. + if (!joysticks[i]->isConnected() && joysticks[i]->getGUID() == guidstr) + { + joystick = joysticks[i]; + joystick->open(deviceindex); + break; + } + } + + if (!joystick) + { + // Make a new Joystick and add it to the persistent list, if we can't + // re-use one. + joystick = new Joystick(joysticks.size(), deviceindex); + joysticks.push_back(joystick); + } + + // Add the Joystick to the connected list, if it's not there already. + if (std::find(activeSticks.begin(), activeSticks.end(), joystick) == activeSticks.end()) + activeSticks.push_back(joystick); + + return joystick; +} + +void JoystickModule::removeJoystick(love::joystick::Joystick *joystick) +{ + if (!joystick) + return; + + // Close the Joystick and remove it from the active joystick list. + std::vector::iterator it = std::find(activeSticks.begin(), activeSticks.end(), joystick); + if (it != activeSticks.end()) + { + (*it)->close(); + activeSticks.erase(it); + } +} + +bool JoystickModule::setGamepadMapping(const std::string &guid, Joystick::GamepadInput gpinput, Joystick::JoystickInput joyinput) +{ + // All SDL joystick GUID strings are 32 characters. + if (guid.length() != 32) + throw love::Exception("Invalid joystick GUID: %s", guid.c_str()); + + SDL_JoystickGUID sdlguid = SDL_JoystickGetGUIDFromString(guid.c_str()); + std::string mapstr; + + char *sdlmapstr = SDL_GameControllerMappingForGUID(sdlguid); + if (sdlmapstr) + { + mapstr = sdlmapstr; + SDL_free(sdlmapstr); + } + else + { + // Use a generic name if we have to create a new mapping string. + mapstr = guid + ",Controller,"; + } + + std::stringstream joyinputstream; + Uint8 sdlhat; + + // We can't have negative int values in the bind string. + switch (joyinput.type) + { + case Joystick::INPUT_TYPE_AXIS: + if (joyinput.axis >= 0) + joyinputstream << "a" << joyinput.axis; + break; + case Joystick::INPUT_TYPE_BUTTON: + if (joyinput.button >= 0) + joyinputstream << "b" << joyinput.button; + break; + case Joystick::INPUT_TYPE_HAT: + if (joyinput.hat.value >= 0 && Joystick::getConstant(joyinput.hat.value, sdlhat)) + joyinputstream << "h" << joyinput.hat.value << "." << int(sdlhat); + break; + default: + break; + } + + std::string joyinputstr = joyinputstream.str(); + + if (joyinputstr.length() == 0) + throw love::Exception("Invalid joystick input value."); + + // SDL's name for the gamepad input value, e.g. "guide". + std::string gpinputname = stringFromGamepadInput(gpinput); + + // We should remove any existing joystick bind for this gamepad buttton/axis + // so SDL's parser doesn't get mixed up. + removeBindFromMapString(mapstr, joyinputstr); + + // The string we'll be adding to the mapping string, e.g. "guide:b10," + std::string insertstr = gpinputname + ":" + joyinputstr + ","; + + // We should replace any existing gamepad bind. + size_t findpos = mapstr.find(gpinputname + ":"); + if (findpos != std::string::npos) + { + // The bind string ends at the next comma, or the end of the string. + size_t endpos = mapstr.find_first_of(',', findpos); + if (endpos == std::string::npos) + endpos = mapstr.length() - 1; + + mapstr.replace(findpos, endpos - findpos + 1, insertstr); + } + else + { + // Just append to the end if we don't need to replace anything. + mapstr += insertstr; + } + + // 1 == added, 0 == updated, -1 == error. + int status = SDL_GameControllerAddMapping(mapstr.c_str()); + + // FIXME: massive hack until missing APIs are added to SDL 2: + // https://bugzilla.libsdl.org/show_bug.cgi?id=1975 + if (status == 1) + checkGamepads(guid); + + return status >= 0; +} + +Joystick::JoystickInput JoystickModule::getGamepadMapping(const std::string &guid, Joystick::GamepadInput gpinput) +{ + // All SDL joystick GUID strings are 32 characters. + if (guid.length() != 32) + throw love::Exception("Invalid joystick GUID: %s", guid.c_str()); + + Joystick::JoystickInput jinput; + jinput.type = Joystick::INPUT_TYPE_MAX_ENUM; + + SDL_JoystickGUID sdlguid = SDL_JoystickGetGUIDFromString(guid.c_str()); + + std::string mapstr; + + char *sdlmapstr = SDL_GameControllerMappingForGUID(sdlguid); + if (!sdlmapstr) + return jinput; + + mapstr = sdlmapstr; + SDL_free(sdlmapstr); + + std::string gpbindname = stringFromGamepadInput(gpinput); + + size_t findpos = mapstr.find(std::string(",") + gpbindname + ":"); + if (findpos == std::string::npos) + return jinput; + + size_t endpos = mapstr.find_first_of(',', findpos); + if (endpos == std::string::npos) + { + // Assume end-of-string if we can't find the next comma. + endpos = mapstr.length() - 1; + } + + if (endpos >= mapstr.length()) + return jinput; // Something went wrong. + + // Strip out the trailing comma from our search position, if it exists. + if (mapstr[endpos] == ',') + endpos--; + + // New start position: comma + gamepadinputlength + ":". + findpos += 1 + gpbindname.length() + 1; + std::string jbindstr = mapstr.substr(findpos, endpos - findpos + 1); + + jinput = JoystickInputFromString(jbindstr); + return jinput; +} + +std::string JoystickModule::stringFromGamepadInput(Joystick::GamepadInput gpinput) const +{ + SDL_GameControllerAxis sdlaxis; + SDL_GameControllerButton sdlbutton; + + const char *gpinputname = 0; + + switch (gpinput.type) + { + case Joystick::INPUT_TYPE_AXIS: + if (Joystick::getConstant(gpinput.axis, sdlaxis)) + gpinputname = SDL_GameControllerGetStringForAxis(sdlaxis); + break; + case Joystick::INPUT_TYPE_BUTTON: + if (Joystick::getConstant(gpinput.button, sdlbutton)) + gpinputname = SDL_GameControllerGetStringForButton(sdlbutton); + break; + default: + break; + } + + if (!gpinputname) + throw love::Exception("Invalid gamepad axis/button."); + + return std::string(gpinputname); +} + +Joystick::JoystickInput JoystickModule::JoystickInputFromString(const std::string &str) const +{ + Joystick::JoystickInput jinput; + jinput.type = Joystick::INPUT_TYPE_MAX_ENUM; + + // Return an invalid value rather than throwing an exception. + if (str.length() < 2) + return jinput; + + // The input type will always be the first character in the string. + char inputtype = str[0]; + std::string bindvalues = str.substr(1); + + Uint8 sdlhat; + switch (inputtype) + { + case 'a': + jinput.type = Joystick::INPUT_TYPE_AXIS; + jinput.axis = atoi(bindvalues.c_str()); + break; + case 'b': + jinput.type = Joystick::INPUT_TYPE_BUTTON; + jinput.button = atoi(bindvalues.c_str()); + break; + case 'h': + // Hat string syntax is "index.value". + if (bindvalues.length() < 3) + break; + jinput.type = Joystick::INPUT_TYPE_HAT; + jinput.hat.index = atoi(bindvalues.substr(0, 1).c_str()); + sdlhat = (Uint8) atoi(bindvalues.substr(2, 1).c_str()); + if (!Joystick::getConstant(sdlhat, jinput.hat.value)) + { + // Return an invalid value if we can't find the hat constant. + jinput.type = Joystick::INPUT_TYPE_MAX_ENUM; + return jinput; + } + break; + default: + break; + } + + return jinput; +} + +void JoystickModule::removeBindFromMapString(std::string &mapstr, const std::string &joybindstr) const +{ + // Find the joystick part of the bind in the string. + size_t joybindpos = mapstr.find(joybindstr + ","); + if (joybindpos == std::string::npos) + { + joybindpos = mapstr.rfind(joybindstr); + if (joybindpos != mapstr.length() - joybindstr.length()) + return; + } + + if (joybindpos == std::string::npos) + return; + + // Find the start of the entire bind. + size_t bindstart = mapstr.rfind(',', joybindpos); + if (bindstart != std::string::npos && bindstart < mapstr.length() - 1) + { + size_t bindend = mapstr.find(',', bindstart + 1); + if (bindend == std::string::npos) + bindend = mapstr.length() - 1; + + // Replace it with an empty string (remove it.) + mapstr.replace(bindstart, bindend - bindstart + 1, ""); + } +} + +void JoystickModule::checkGamepads(const std::string &guid) const +{ + // FIXME: massive hack until missing APIs are added to SDL 2: + // https://bugzilla.libsdl.org/show_bug.cgi?id=1975 + + // Make sure all connected joysticks of a certain guid that are + // gamepad-capable are opened as such. + for (int d_index = 0; d_index < SDL_NumJoysticks(); d_index++) + { + if (!SDL_IsGameController(d_index)) + continue; + + if (guid.compare(getDeviceGUID(d_index)) != 0) + continue; + + std::vector::const_iterator it; + for (it = activeSticks.begin(); it != activeSticks.end(); ++it) + { + if ((*it)->isGamepad() || guid.compare((*it)->getGUID()) != 0) + continue; + + // Big hack time: open the index as a game controller and compare + // the underlying joystick handle to the active stick's. + SDL_GameController *ctrl = SDL_GameControllerOpen(d_index); + if (ctrl == NULL) + continue; + + SDL_Joystick *stick = SDL_GameControllerGetJoystick(ctrl); + if (stick == (SDL_Joystick *) (*it)->getHandle()) + (*it)->openGamepad(d_index); + + SDL_GameControllerClose(ctrl); + } + } +} + +std::string JoystickModule::getDeviceGUID(int deviceindex) const +{ + if (deviceindex < 0 || deviceindex >= SDL_NumJoysticks()) + return std::string(""); + + // SDL_JoystickGetGUIDString uses 32 bytes plus the null terminator. + char guidstr[33] = {'\0'}; + + // SDL2's GUIDs identify *classes* of devices, instead of unique devices. + SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(deviceindex); + SDL_JoystickGetGUIDString(guid, guidstr, sizeof(guidstr)); + + return std::string(guidstr); +} + +} // sdl +} // joystick +} // love diff --git a/src/modules/joystick/sdl/JoystickModule.h b/src/modules/joystick/sdl/JoystickModule.h new file mode 100644 index 000000000..1c06f6026 --- /dev/null +++ b/src/modules/joystick/sdl/JoystickModule.h @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#ifndef LOVE_JOYSTICK_SDL_JOYSTICK_MODULE_H +#define LOVE_JOYSTICK_SDL_JOYSTICK_MODULE_H + +// LOVE +#include "joystick/JoystickModule.h" + +// STL +#include +#include + +namespace love +{ +namespace joystick +{ +namespace sdl +{ + +class JoystickModule : public love::joystick::JoystickModule +{ +public: + + JoystickModule(); + virtual ~JoystickModule(); + + // Implements Module. + const char *getName() const; + + // Implements JoystickModule. + love::joystick::Joystick *addJoystick(int deviceindex); + void removeJoystick(love::joystick::Joystick *joystick); + love::joystick::Joystick *getJoystickFromID(int instanceid); + love::joystick::Joystick *getJoystick(int joyindex); + int getIndex(const love::joystick::Joystick *joystick); + int getJoystickCount() const; + bool isGamepad(int joyindex) const; + bool setGamepadMapping(const std::string &guid, Joystick::GamepadInput gpinput, Joystick::JoystickInput joyinput); + Joystick::JoystickInput getGamepadMapping(const std::string &guid, Joystick::GamepadInput gpinput); + +private: + + std::string stringFromGamepadInput(Joystick::GamepadInput gpinput) const; + Joystick::JoystickInput JoystickInputFromString(const std::string &str) const; + void removeBindFromMapString(std::string &mapstr, const std::string &joybindstr) const; + void checkGamepads(const std::string &guid) const; + + // SDL2's GUIDs identify *classes* of devices, instead of unique devices. + std::string getDeviceGUID(int deviceindex) const; + + // Lists of currently connected Joysticks. + std::vector activeSticks; + + // Persistent list of all Joysticks which have been connected at some point. + std::vector joysticks; + +}; // JoystickModule + +} // sdl +} // joystick +} // love + +#endif // LOVE_JOYSTICK_SDL_JOYSTICK_MODULE_H diff --git a/src/modules/joystick/sdl/wrap_Joystick.cpp b/src/modules/joystick/sdl/wrap_Joystick.cpp index 1545e6624..4aa547c85 100644 --- a/src/modules/joystick/sdl/wrap_Joystick.cpp +++ b/src/modules/joystick/sdl/wrap_Joystick.cpp @@ -18,7 +18,11 @@ * 3. This notice may not be removed or altered from any source distribution. **/ +// LOVE #include "wrap_Joystick.h" +#include "wrap_JoystickModule.h" + +#include namespace love { @@ -27,141 +31,179 @@ namespace joystick namespace sdl { -static Joystick *instance = 0; - -int w_reload(lua_State *L) +Joystick *luax_checkjoystick(lua_State *L, int idx) { - try - { - instance->reload(); - } - catch(love::Exception &e) - { - return luaL_error(L, "%s", e.what()); - } - return 0; + return luax_checktype(L, idx, "Joystick", JOYSTICK_JOYSTICK_T); } -int w_getJoystickCount(lua_State *L) +int w_Joystick_isConnected(lua_State *L) { - lua_pushinteger(L, instance->getJoystickCount()); + Joystick *j = luax_checkjoystick(L, 1); + luax_pushboolean(L, j->isConnected()); return 1; } -int w_getName(lua_State *L) +int w_Joystick_getName(lua_State *L) { - int index = luaL_checkint(L, 1) - 1; - lua_pushstring(L, instance->getName(index)); + Joystick *j = luax_checkjoystick(L, 1); + lua_pushstring(L, j->getName()); return 1; } -int w_getAxisCount(lua_State *L) +int w_Joystick_getID(lua_State *L) { - int index = luaL_checkint(L, 1) - 1; - lua_pushinteger(L, instance->getAxisCount(index)); + Joystick *j = luax_checkjoystick(L, 1); + lua_pushinteger(L, j->getID()); return 1; } -int w_getButtonCount(lua_State *L) +int w_Joystick_getGUID(lua_State *L) { - int index = luaL_checkint(L, 1) - 1; - lua_pushinteger(L, instance->getButtonCount(index)); + Joystick *j = luax_checkjoystick(L, 1); + luax_pushstring(L, j->getGUID()); return 1; } -int w_getHatCount(lua_State *L) +int w_Joystick_getAxisCount(lua_State *L) { - int index = luaL_checkint(L, 1) - 1; - lua_pushinteger(L, instance->getHatCount(index)); + Joystick *j = luax_checkjoystick(L, 1); + lua_pushinteger(L, j->getAxisCount()); return 1; } -int w_getAxis(lua_State *L) +int w_Joystick_getButtonCount(lua_State *L) { - int index = luaL_checkint(L, 1) - 1; - int axis = luaL_checkint(L, 2) - 1; - lua_pushnumber(L, instance->getAxis(index, axis)); + Joystick *j = luax_checkjoystick(L, 1); + lua_pushinteger(L, j->getButtonCount()); return 1; } -int w_getAxes(lua_State *L) +int w_Joystick_getHatCount(lua_State *L) { - return instance->getAxes(L); -} - -int w_isDown(lua_State *L) -{ - int index = luaL_checkint(L, 1) - 1; - int num = lua_gettop(L); - - int *buttonlist = new int[num]; - int counter = 0; - - for (int i = 1; i < num; i++) - buttonlist[counter++] = luaL_checkint(L, i + 1) - 1; - - buttonlist[counter] = -1; - - luax_pushboolean(L, instance->isDown(index, buttonlist)); - delete[] buttonlist; + Joystick *j = luax_checkjoystick(L, 1); + lua_pushinteger(L, j->getHatCount()); return 1; } -int w_getHat(lua_State *L) +int w_Joystick_getAxis(lua_State *L) { - int index = luaL_checkint(L, 1)-1; - int hat = luaL_checkint(L, 2)-1; + Joystick *j = luax_checkjoystick(L, 1); + int axisindex = luaL_checkint(L, 2) - 1; + lua_pushnumber(L, j->getAxis(axisindex)); + return 1; +} - Joystick::Hat h = instance->getHat(index, hat); +int w_Joystick_getAxes(lua_State *L) +{ + Joystick *j = luax_checkjoystick(L, 1); + std::vector axes = j->getAxes(); + + for (size_t i = 0; i < axes.size(); i++) + lua_pushnumber(L, axes[i]); + + return (int) axes.size(); +} + +int w_Joystick_getHat(lua_State *L) +{ + Joystick *j = luax_checkjoystick(L, 1); + int hatindex = luaL_checkint(L, 2) - 1; + + Joystick::Hat h = j->getHat(hatindex); const char *direction = ""; - Joystick::getConstant(h, direction); - lua_pushstring(L, direction); + love::joystick::Joystick::getConstant(h, direction); + lua_pushstring(L, direction); + return 1; +} + +int w_Joystick_isDown(lua_State *L) +{ + Joystick *j = luax_checkjoystick(L, 1); + + luaL_checkinteger(L, 2); + + std::vector buttons; + for (int i = 2; i <= lua_gettop(L); i++) + buttons.push_back(luaL_checkint(L, i)); + + luax_pushboolean(L, j->isDown(buttons)); + return 1; +} + +int w_Joystick_isGamepad(lua_State *L) +{ + Joystick *j = luax_checkjoystick(L, 1); + luax_pushboolean(L, j->isGamepad()); + return 1; +} + +int w_Joystick_getGamepadAxis(lua_State *L) +{ + Joystick *j = luax_checkjoystick(L, 1); + + const char *str = luaL_checkstring(L, 2); + Joystick::GamepadAxis axis; + + if (!joystick::Joystick::getConstant(str, axis)) + return luaL_error(L, "Invalid gamepad axis: %s", str); + + lua_pushnumber(L, j->getGamepadAxis(axis)); + return 1; +} + +int w_Joystick_isGamepadDown(lua_State *L) +{ + Joystick *j = luax_checkjoystick(L, 1); + + std::vector buttons; + buttons.reserve(lua_gettop(L) - 1); + + luaL_checkstring(L, 2); + + for (int i = 2; i <= lua_gettop(L); i++) + { + const char *str = luaL_checkstring(L, i); + Joystick::GamepadButton button; + + if (!joystick::Joystick::getConstant(str, button)) + return luaL_error(L, "Invalid gamepad button: %s", str); + + buttons.push_back(button); + } + + luax_pushboolean(L, j->isGamepadDown(buttons)); return 1; } // List of functions to wrap. static const luaL_Reg functions[] = { - { "reload", w_reload }, - { "getJoystickCount", w_getJoystickCount }, - { "getName", w_getName }, - { "getAxisCount", w_getAxisCount }, - { "getButtonCount", w_getButtonCount }, - { "getHatCount", w_getHatCount }, - { "getAxis", w_getAxis }, - { "getAxes", w_getAxes }, - { "isDown", w_isDown }, - { "getHat", w_getHat }, - { 0, 0 } + { "isConnected", w_Joystick_isConnected }, + { "getName", w_Joystick_getName }, + { "getID", w_Joystick_getID }, + { "getGUID", w_Joystick_getGUID }, + { "getAxisCount", w_Joystick_getAxisCount }, + { "getButtonCount", w_Joystick_getButtonCount }, + { "getHatCount", w_Joystick_getHatCount }, + { "getAxis", w_Joystick_getAxis }, + { "getAxes", w_Joystick_getAxes }, + { "getHat", w_Joystick_getHat }, + { "isDown", w_Joystick_isDown }, + { "isGamepad", w_Joystick_isGamepad }, + { "getGamepadAxis", w_Joystick_getGamepadAxis }, + { "isGamepadDown", w_Joystick_isGamepadDown }, + + // From wrap_JoystickModule. + { "getIndex", w_getIndex }, + { "getGamepadMapping", w_getGamepadMapping }, + { 0, 0 }, }; -extern "C" int luaopen_love_joystick(lua_State *L) +extern "C" int luaopen_joystick(lua_State *L) { - if (instance == 0) - { - try - { - instance = new Joystick(); - } - catch(Exception &e) - { - return luaL_error(L, e.what()); - } - } - else - instance->retain(); - - - WrappedModule w; - w.module = instance; - w.name = "joystick"; - w.flags = MODULE_T; - w.functions = functions; - w.types = 0; - - return luax_register_module(L, w); + return luax_register_type(L, "Joystick", functions); } } // sdl diff --git a/src/modules/joystick/sdl/wrap_Joystick.h b/src/modules/joystick/sdl/wrap_Joystick.h index 6b7fb962d..86f8c70b0 100644 --- a/src/modules/joystick/sdl/wrap_Joystick.h +++ b/src/modules/joystick/sdl/wrap_Joystick.h @@ -24,6 +24,7 @@ // LOVE #include "common/config.h" #include "Joystick.h" +#include "common/runtime.h" namespace love { @@ -32,17 +33,22 @@ namespace joystick namespace sdl { -int w_reload(lua_State *L); -int w_getJoystickCount(lua_State *L); -int w_getName(lua_State *L); -int w_getAxisCount(lua_State *L); -int w_getButtonCount(lua_State *L); -int w_getHatCount(lua_State *L); -int w_getAxis(lua_State *L); -int w_getAxes(lua_State *L); -int w_isDown(lua_State *L); -int w_getHat(lua_State *L); -extern "C" LOVE_EXPORT int luaopen_love_joystick(lua_State *L); +Joystick *luax_checkjoystick(lua_State *L, int idx); +int w_Joystick_isConnected(lua_State *L); +int w_Joystick_getName(lua_State *L); +int w_Joystick_getID(lua_State *L); +int w_Joystick_getGUID(lua_State *L); +int w_Joystick_getAxisCount(lua_State *L); +int w_Joystick_getButtonCount(lua_State *L); +int w_Joystick_getHatCount(lua_State *L); +int w_Joystick_getAxis(lua_State *L); +int w_Joystick_getAxes(lua_State *L); +int w_Joystick_getHat(lua_State *L); +int w_Joystick_isDown(lua_State *L); +int w_Joystick_isGamepad(lua_State *L); +int w_Joystick_getGamepadAxis(lua_State *L); +int w_Joystick_isGamepadDown(lua_State *L); +extern "C" int luaopen_joystick(lua_State *L); } // sdl } // joystick diff --git a/src/modules/joystick/sdl/wrap_JoystickModule.cpp b/src/modules/joystick/sdl/wrap_JoystickModule.cpp new file mode 100644 index 000000000..3a3769e40 --- /dev/null +++ b/src/modules/joystick/sdl/wrap_JoystickModule.cpp @@ -0,0 +1,244 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#include "wrap_JoystickModule.h" +#include "wrap_Joystick.h" + +namespace love +{ +namespace joystick +{ +namespace sdl +{ + +static JoystickModule *instance = 0; + +int w_getJoystick(lua_State *L) +{ + int index = luaL_checkint(L, 1) - 1; + love::joystick::Joystick *stick = instance->getJoystick(index); + + if (!stick) + return luaL_error(L, "Invalid joystick index"); + + stick->retain(); + luax_newtype(L, "Joystick", JOYSTICK_JOYSTICK_T, (void *) stick); + + return 1; +} + +int w_getIndex(lua_State *L) +{ + love::joystick::Joystick *j = luax_checkjoystick(L, 1); + int index = instance->getIndex(j); + if (index >= 0) + lua_pushinteger(L, index + 1); + else + lua_pushinteger(L, -1); + return 1; +} + +int w_getJoystickCount(lua_State *L) +{ + lua_pushinteger(L, instance->getJoystickCount()); + return 1; +} + +int w_isGamepad(lua_State *L) +{ + int index = luaL_checkint(L, 1) - 1; + luax_pushboolean(L, instance->isGamepad(index)); + return 1; +} + +int w_setGamepadMapping(lua_State *L) +{ + // Only accept a GUID string. We don't accept a Joystick object because + // the gamepad mapping applies to all joysticks with the same GUID (e.g. all + // Xbox 360 controllers on the system), rather than individual objects. + std::string guid = luax_checkstring(L, 1); + + const char *gpbindstr = luaL_checkstring(L, 2); + Joystick::GamepadInput gpinput; + + if (love::joystick::Joystick::getConstant(gpbindstr, gpinput.axis)) + gpinput.type = Joystick::INPUT_TYPE_AXIS; + else if (love::joystick::Joystick::getConstant(gpbindstr, gpinput.button)) + gpinput.type = Joystick::INPUT_TYPE_BUTTON; + else + return luaL_error(L, "Invalid gamepad axis/button: %s", gpbindstr); + + const char *jinputtypestr = luaL_checkstring(L, 3); + Joystick::JoystickInput jinput; + + if (!love::joystick::Joystick::getConstant(jinputtypestr, jinput.type)) + return luaL_error(L, "Invalid joystick input type: %s", jinputtypestr); + + const char *hatstr; + switch (jinput.type) + { + case Joystick::INPUT_TYPE_AXIS: + jinput.axis = luaL_checkint(L, 4) - 1; + break; + case Joystick::INPUT_TYPE_BUTTON: + jinput.button = luaL_checkint(L, 4) - 1; + break; + case Joystick::INPUT_TYPE_HAT: + // Hats need both a hat index and a hat value. + jinput.hat.index = luaL_checkint(L, 4) - 1; + hatstr = luaL_checkstring(L, 5); + if (!love::joystick::Joystick::getConstant(hatstr, jinput.hat.value)) + return luaL_error(L, "Invalid joystick hat: %s", hatstr); + break; + default: + return luaL_error(L, "Invalid joystick input type: %s", jinputtypestr); + } + + bool success = false; + try + { + success = instance->setGamepadMapping(guid, gpinput, jinput); + } + catch (love::Exception &e) + { + return luaL_error(L, "%s", e.what()); + } + luax_pushboolean(L, success); + return 1; +} + +int w_getGamepadMapping(lua_State *L) +{ + std::string guid; + + // Accept either a GUID string or a Joystick object. This way we can re-use + // the function for Joystick:getGamepadMapping. + if (lua_type(L, 1) == LUA_TSTRING) + guid = luax_checkstring(L, 1); + else + { + love::joystick::Joystick *stick = luax_checkjoystick(L, 1); + guid = stick->getGUID(); + } + + const char *gpbindstr = luaL_checkstring(L, 2); + Joystick::GamepadInput gpinput; + + if (love::joystick::Joystick::getConstant(gpbindstr, gpinput.axis)) + gpinput.type = Joystick::INPUT_TYPE_AXIS; + else if (love::joystick::Joystick::getConstant(gpbindstr, gpinput.button)) + gpinput.type = Joystick::INPUT_TYPE_BUTTON; + else + return luaL_error(L, "Invalid gamepad axis/button: %s", gpbindstr); + + Joystick::JoystickInput jinput; + jinput.type = Joystick::INPUT_TYPE_MAX_ENUM; + + try + { + jinput = instance->getGamepadMapping(guid, gpinput); + } + catch (love::Exception &e) + { + return luaL_error(L, "%s", e.what()); + } + + if (jinput.type == Joystick::INPUT_TYPE_MAX_ENUM) + return 0; + + const char *inputtypestr; + if (!love::joystick::Joystick::getConstant(jinput.type, inputtypestr)) + return luaL_error(L, "Unknown joystick input type."); + + lua_pushstring(L, inputtypestr); + + const char *hatstr; + switch (jinput.type) + { + case Joystick::INPUT_TYPE_AXIS: + lua_pushinteger(L, jinput.axis + 1); + return 2; + case Joystick::INPUT_TYPE_BUTTON: + lua_pushinteger(L, jinput.button + 1); + return 2; + case Joystick::INPUT_TYPE_HAT: + lua_pushinteger(L, jinput.hat.index + 1); + if (love::joystick::Joystick::getConstant(jinput.hat.value, hatstr)) + { + lua_pushstring(L, hatstr); + return 3; + } + else + return luaL_error(L, "Unknown joystick hat."); + default: + break; // ? + } + + return 1; +} + +// List of functions to wrap. +static const luaL_Reg functions[] = +{ + { "getJoystick", w_getJoystick }, + { "getIndex", w_getIndex }, + { "getJoystickCount", w_getJoystickCount }, + { "isGamepad", w_isGamepad }, + { "setGamepadMapping", w_setGamepadMapping }, + { "getGamepadMapping", w_getGamepadMapping }, + { 0, 0 } +}; + +static const lua_CFunction types[] = +{ + luaopen_joystick, + 0, +}; + +extern "C" int luaopen_love_joystick(lua_State *L) +{ + if (instance == 0) + { + try + { + instance = new JoystickModule(); + } + catch (Exception &e) + { + return luaL_error(L, e.what()); + } + } + else + instance->retain(); + + + WrappedModule w; + w.module = instance; + w.name = "joystick"; + w.flags = MODULE_T; + w.functions = functions; + w.types = types; + + return luax_register_module(L, w); +} + +} // sdl +} // joystick +} // love diff --git a/src/modules/joystick/sdl/wrap_JoystickModule.h b/src/modules/joystick/sdl/wrap_JoystickModule.h new file mode 100644 index 000000000..533a77a08 --- /dev/null +++ b/src/modules/joystick/sdl/wrap_JoystickModule.h @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#ifndef LOVE_JOYSTICK_SDL_WRAP_JOYSTICK_MODULE_H +#define LOVE_JOYSTICK_SDL_WRAP_JOYSTICK_MODULE_H + +// LOVE +#include "common/config.h" +#include "JoystickModule.h" + +namespace love +{ +namespace joystick +{ +namespace sdl +{ + +int w_getJoystick(lua_State *L); +int w_getIndex(lua_State *L); +int w_getJoystickCount(lua_State *L); +int w_isGamepad(lua_State *L); +int w_setGamepadMapping(lua_State *L); +int w_getGamepadMapping(lua_State *L); +extern "C" LOVE_EXPORT int luaopen_love_joystick(lua_State *L); + +} // sdl +} // joystick +} // love + +#endif // LOVE_JOYSTICK_SDL_WRAP_JOYSTICK_MODULE_H diff --git a/src/modules/keyboard/Keyboard.cpp b/src/modules/keyboard/Keyboard.cpp index f3c8aa4ac..f16172c33 100644 --- a/src/modules/keyboard/Keyboard.cpp +++ b/src/modules/keyboard/Keyboard.cpp @@ -39,12 +39,10 @@ bool Keyboard::getConstant(Keyboard::Key in, const char *&out) StringMap::Entry Keyboard::keyEntries[] = { + {"return", Keyboard::KEY_RETURN}, + {"escape", Keyboard::KEY_ESCAPE}, {"backspace", Keyboard::KEY_BACKSPACE}, {"tab", Keyboard::KEY_TAB}, - {"clear", Keyboard::KEY_CLEAR}, - {"return", Keyboard::KEY_RETURN}, - {"pause", Keyboard::KEY_PAUSE}, - {"escape", Keyboard::KEY_ESCAPE}, {" ", Keyboard::KEY_SPACE}, {"!", Keyboard::KEY_EXCLAIM}, {"\"", Keyboard::KEY_QUOTEDBL}, @@ -110,35 +108,8 @@ StringMap::Entry Keyboard::keyEntries[] = {"x", Keyboard::KEY_X}, {"y", Keyboard::KEY_Y}, {"z", Keyboard::KEY_Z}, - {"delete", Keyboard::KEY_DELETE}, - {"kp0", Keyboard::KEY_KP0}, - {"kp1", Keyboard::KEY_KP1}, - {"kp2", Keyboard::KEY_KP2}, - {"kp3", Keyboard::KEY_KP3}, - {"kp4", Keyboard::KEY_KP4}, - {"kp5", Keyboard::KEY_KP5}, - {"kp6", Keyboard::KEY_KP6}, - {"kp7", Keyboard::KEY_KP7}, - {"kp8", Keyboard::KEY_KP8}, - {"kp9", Keyboard::KEY_KP9}, - {"kp.", Keyboard::KEY_KP_PERIOD}, - {"kp/", Keyboard::KEY_KP_DIVIDE}, - {"kp*", Keyboard::KEY_KP_MULTIPLY}, - {"kp-", Keyboard::KEY_KP_MINUS}, - {"kp+", Keyboard::KEY_KP_PLUS}, - {"kpenter", Keyboard::KEY_KP_ENTER}, - {"kp=", Keyboard::KEY_KP_EQUALS}, - - {"up", Keyboard::KEY_UP}, - {"down", Keyboard::KEY_DOWN}, - {"right", Keyboard::KEY_RIGHT}, - {"left", Keyboard::KEY_LEFT}, - {"insert", Keyboard::KEY_INSERT}, - {"home", Keyboard::KEY_HOME}, - {"end", Keyboard::KEY_END}, - {"pageup", Keyboard::KEY_PAGEUP}, - {"pagedown", Keyboard::KEY_PAGEDOWN}, + {"capslock", Keyboard::KEY_CAPSLOCK}, {"f1", Keyboard::KEY_F1}, {"f2", Keyboard::KEY_F2}, @@ -152,34 +123,112 @@ StringMap::Entry Keyboard::keyEntries[] = {"f10", Keyboard::KEY_F10}, {"f11", Keyboard::KEY_F11}, {"f12", Keyboard::KEY_F12}, + + {"printscreen", Keyboard::KEY_PRINTSCREEN}, + {"scrolllock", Keyboard::KEY_SCROLLLOCK}, + {"pause", Keyboard::KEY_PAUSE}, + {"insert", Keyboard::KEY_INSERT}, + {"home", Keyboard::KEY_HOME}, + {"pageup", Keyboard::KEY_PAGEUP}, + {"delete", Keyboard::KEY_DELETE}, + {"end", Keyboard::KEY_END}, + {"pagedown", Keyboard::KEY_PAGEDOWN}, + {"right", Keyboard::KEY_RIGHT}, + {"left", Keyboard::KEY_LEFT}, + {"down", Keyboard::KEY_DOWN}, + {"up", Keyboard::KEY_UP}, + + {"numlock", Keyboard::KEY_NUMLOCKCLEAR}, + {"kp/", Keyboard::KEY_KP_DIVIDE}, + {"kp*", Keyboard::KEY_KP_MULTIPLY}, + {"kp-", Keyboard::KEY_KP_MINUS}, + {"kp+", Keyboard::KEY_KP_PLUS}, + {"kpenter", Keyboard::KEY_KP_ENTER}, + {"kp0", Keyboard::KEY_KP_0}, + {"kp1", Keyboard::KEY_KP_1}, + {"kp2", Keyboard::KEY_KP_2}, + {"kp3", Keyboard::KEY_KP_3}, + {"kp4", Keyboard::KEY_KP_4}, + {"kp5", Keyboard::KEY_KP_5}, + {"kp6", Keyboard::KEY_KP_6}, + {"kp7", Keyboard::KEY_KP_7}, + {"kp8", Keyboard::KEY_KP_8}, + {"kp9", Keyboard::KEY_KP_9}, + {"kp.", Keyboard::KEY_KP_PERIOD}, + {"kp,", Keyboard::KEY_KP_COMMA}, + {"kp=", Keyboard::KEY_KP_EQUALS}, + + {"application", Keyboard::KEY_APPLICATION}, + {"power", Keyboard::KEY_POWER}, {"f13", Keyboard::KEY_F13}, {"f14", Keyboard::KEY_F14}, {"f15", Keyboard::KEY_F15}, - - {"numlock", Keyboard::KEY_NUMLOCK}, - {"capslock", Keyboard::KEY_CAPSLOCK}, - {"scrollock", Keyboard::KEY_SCROLLOCK}, - {"rshift", Keyboard::KEY_RSHIFT}, - {"lshift", Keyboard::KEY_LSHIFT}, - {"rctrl", Keyboard::KEY_RCTRL}, - {"lctrl", Keyboard::KEY_LCTRL}, - {"ralt", Keyboard::KEY_RALT}, - {"lalt", Keyboard::KEY_LALT}, - {"rmeta", Keyboard::KEY_RMETA}, - {"lmeta", Keyboard::KEY_LMETA}, - {"lsuper", Keyboard::KEY_LSUPER}, - {"rsuper", Keyboard::KEY_RSUPER}, - {"mode", Keyboard::KEY_MODE}, - {"compose", Keyboard::KEY_COMPOSE}, - + {"f16", Keyboard::KEY_F16}, + {"f17", Keyboard::KEY_F17}, + {"f18", Keyboard::KEY_F18}, + {"f19", Keyboard::KEY_F19}, + {"f20", Keyboard::KEY_F20}, + {"f21", Keyboard::KEY_F21}, + {"f22", Keyboard::KEY_F22}, + {"f23", Keyboard::KEY_F23}, + {"f24", Keyboard::KEY_F24}, + {"execute", Keyboard::KEY_EXECUTE}, {"help", Keyboard::KEY_HELP}, - {"print", Keyboard::KEY_PRINT}, - {"sysreq", Keyboard::KEY_SYSREQ}, - {"break", Keyboard::KEY_BREAK}, {"menu", Keyboard::KEY_MENU}, - {"power", Keyboard::KEY_POWER}, - {"euro", Keyboard::KEY_EURO}, + {"select", Keyboard::KEY_SELECT}, + {"stop", Keyboard::KEY_STOP}, + {"again", Keyboard::KEY_AGAIN}, {"undo", Keyboard::KEY_UNDO}, + {"cut", Keyboard::KEY_CUT}, + {"copy", Keyboard::KEY_COPY}, + {"paste", Keyboard::KEY_PASTE}, + {"find", Keyboard::KEY_FIND}, + {"mute", Keyboard::KEY_MUTE}, + {"volumeup", Keyboard::KEY_VOLUMEUP}, + {"volumedown", Keyboard::KEY_VOLUMEDOWN}, + + {"alterase", Keyboard::KEY_ALTERASE}, + {"sysreq", Keyboard::KEY_SYSREQ}, + {"cancel", Keyboard::KEY_CANCEL}, + {"clear", Keyboard::KEY_CLEAR}, + {"prior", Keyboard::KEY_PRIOR}, + {"return2", Keyboard::KEY_RETURN2}, + {"separator", Keyboard::KEY_SEPARATOR}, + {"out", Keyboard::KEY_OUT}, + {"oper", Keyboard::KEY_OPER}, + {"clearagain", Keyboard::KEY_CLEARAGAIN}, + + {"thsousandsseparator", Keyboard::KEY_THOUSANDSSEPARATOR}, + {"decimalseparator", Keyboard::KEY_DECIMALSEPARATOR}, + {"currencyunit", Keyboard::KEY_CURRENCYUNIT}, + {"currencysubunit", Keyboard::KEY_CURRENCYSUBUNIT}, + + {"lctrl", Keyboard::KEY_LCTRL}, + {"lshift", Keyboard::KEY_LSHIFT}, + {"lalt", Keyboard::KEY_LALT}, + {"lgui", Keyboard::KEY_LGUI}, + {"rctrl", Keyboard::KEY_RCTRL}, + {"rshift", Keyboard::KEY_RSHIFT}, + {"ralt", Keyboard::KEY_RALT}, + {"rgui", Keyboard::KEY_RGUI}, + + {"mode", Keyboard::KEY_MODE}, + + {"audionext", Keyboard::KEY_AUDIONEXT}, + {"audioprev", Keyboard::KEY_AUDIOPREV}, + {"audiostop", Keyboard::KEY_AUDIOSTOP}, + {"audioplay", Keyboard::KEY_AUDIOPLAY}, + {"audiomute", Keyboard::KEY_AUDIOMUTE}, + {"mediaselect", Keyboard::KEY_MEDIASELECT}, + + {"brightnessdown", Keyboard::KEY_BRIGHTNESSDOWN}, + {"brightnessup", Keyboard::KEY_BRIGHTNESSUP}, + {"displayswitch", Keyboard::KEY_DISPLAYSWITCH}, + {"kbdillumtoggle", Keyboard::KEY_KBDILLUMTOGGLE}, + {"kbdillumdown", Keyboard::KEY_KBDILLUMDOWN}, + {"kbdillumup", Keyboard::KEY_KBDILLUMUP}, + {"eject", Keyboard::KEY_EJECT}, + {"sleep", Keyboard::KEY_SLEEP}, }; StringMap Keyboard::keys(Keyboard::keyEntries, sizeof(Keyboard::keyEntries)); diff --git a/src/modules/keyboard/Keyboard.h b/src/modules/keyboard/Keyboard.h index a4e53def2..ace45422b 100644 --- a/src/modules/keyboard/Keyboard.h +++ b/src/modules/keyboard/Keyboard.h @@ -37,16 +37,16 @@ public: enum Key { KEY_UNKNOWN, + + KEY_RETURN, + KEY_ESCAPE, KEY_BACKSPACE, KEY_TAB, - KEY_CLEAR, - KEY_RETURN, - KEY_PAUSE, - KEY_ESCAPE, KEY_SPACE, KEY_EXCLAIM, KEY_QUOTEDBL, KEY_HASH, + KEY_PERCENT, KEY_DOLLAR, KEY_AMPERSAND, KEY_QUOTE, @@ -108,35 +108,8 @@ public: KEY_X, KEY_Y, KEY_Z, - KEY_DELETE, - KEY_KP0, - KEY_KP1, - KEY_KP2, - KEY_KP3, - KEY_KP4, - KEY_KP5, - KEY_KP6, - KEY_KP7, - KEY_KP8, - KEY_KP9, - KEY_KP_PERIOD, - KEY_KP_DIVIDE, - KEY_KP_MULTIPLY, - KEY_KP_MINUS, - KEY_KP_PLUS, - KEY_KP_ENTER, - KEY_KP_EQUALS, - - KEY_UP, - KEY_DOWN, - KEY_RIGHT, - KEY_LEFT, - KEY_INSERT, - KEY_HOME, - KEY_END, - KEY_PAGEUP, - KEY_PAGEDOWN, + KEY_CAPSLOCK, KEY_F1, KEY_F2, @@ -150,39 +123,116 @@ public: KEY_F10, KEY_F11, KEY_F12, + + KEY_PRINTSCREEN, + KEY_SCROLLLOCK, + KEY_PAUSE, + KEY_INSERT, + KEY_HOME, + KEY_PAGEUP, + KEY_DELETE, + KEY_END, + KEY_PAGEDOWN, + KEY_RIGHT, + KEY_LEFT, + KEY_DOWN, + KEY_UP, + + KEY_NUMLOCKCLEAR, + KEY_KP_DIVIDE, + KEY_KP_MULTIPLY, + KEY_KP_MINUS, + KEY_KP_PLUS, + KEY_KP_ENTER, + KEY_KP_1, + KEY_KP_2, + KEY_KP_3, + KEY_KP_4, + KEY_KP_5, + KEY_KP_6, + KEY_KP_7, + KEY_KP_8, + KEY_KP_9, + KEY_KP_0, + KEY_KP_PERIOD, + KEY_KP_COMMA, + KEY_KP_EQUALS, + + KEY_APPLICATION, + KEY_POWER, KEY_F13, KEY_F14, KEY_F15, - - KEY_NUMLOCK, - KEY_CAPSLOCK, - KEY_SCROLLOCK, - KEY_RSHIFT, - KEY_LSHIFT, - KEY_RCTRL, - KEY_LCTRL, - KEY_RALT, - KEY_LALT, - KEY_RMETA, - KEY_LMETA, - KEY_LSUPER, - KEY_RSUPER, - KEY_MODE, - KEY_COMPOSE, - + KEY_F16, + KEY_F17, + KEY_F18, + KEY_F19, + KEY_F20, + KEY_F21, + KEY_F22, + KEY_F23, + KEY_F24, + KEY_EXECUTE, KEY_HELP, - KEY_PRINT, - KEY_SYSREQ, - KEY_BREAK, KEY_MENU, - KEY_POWER, - KEY_EURO, + KEY_SELECT, + KEY_STOP, + KEY_AGAIN, KEY_UNDO, + KEY_CUT, + KEY_COPY, + KEY_PASTE, + KEY_FIND, + KEY_MUTE, + KEY_VOLUMEUP, + KEY_VOLUMEDOWN, + + KEY_ALTERASE, + KEY_SYSREQ, + KEY_CANCEL, + KEY_CLEAR, + KEY_PRIOR, + KEY_RETURN2, + KEY_SEPARATOR, + KEY_OUT, + KEY_OPER, + KEY_CLEARAGAIN, + + KEY_THOUSANDSSEPARATOR, + KEY_DECIMALSEPARATOR, + KEY_CURRENCYUNIT, + KEY_CURRENCYSUBUNIT, + + KEY_LCTRL, + KEY_LSHIFT, + KEY_LALT, + KEY_LGUI, + KEY_RCTRL, + KEY_RSHIFT, + KEY_RALT, + KEY_RGUI, + + KEY_MODE, + + KEY_AUDIONEXT, + KEY_AUDIOPREV, + KEY_AUDIOSTOP, + KEY_AUDIOPLAY, + KEY_AUDIOMUTE, + KEY_MEDIASELECT, + + KEY_BRIGHTNESSDOWN, + KEY_BRIGHTNESSUP, + KEY_DISPLAYSWITCH, + KEY_KBDILLUMTOGGLE, + KEY_KBDILLUMDOWN, + KEY_KBDILLUMUP, + KEY_EJECT, + KEY_SLEEP, + KEY_MAX_ENUM = 512 }; - static const int DEFAULT = -1; - virtual ~Keyboard() {} /** @@ -192,25 +242,6 @@ public: **/ virtual bool isDown(Key *keylist) const = 0; - /** - * Enables key repeating. - * @param delay The amount of delay before repeating the key (in milliseconds) - * @param interval Specifies the amount of time between repeats (in milliseconds) - **/ - virtual void setKeyRepeat(int delay, int interval) const = 0; - - /** - * Gets the specified delay for the key repeat. - * @return int - **/ - virtual int getKeyRepeatDelay() const = 0; - - /** - * Gets the specified interval for the key repeat. - * @return int - **/ - virtual int getKeyRepeatInterval() const = 0; - static bool getConstant(const char *in, Key &out); static bool getConstant(Key in, const char *&out); diff --git a/src/modules/keyboard/sdl/Keyboard.cpp b/src/modules/keyboard/sdl/Keyboard.cpp index 551df5247..c1a52f3f9 100644 --- a/src/modules/keyboard/sdl/Keyboard.cpp +++ b/src/modules/keyboard/sdl/Keyboard.cpp @@ -36,187 +36,220 @@ const char *Keyboard::getName() const bool Keyboard::isDown(Key *keylist) const { - SDLKey k; - Uint8 *keystate = SDL_GetKeyState(0); + const Uint8 *keystate = SDL_GetKeyboardState(0); + std::map::const_iterator it; for (Key key = *keylist; key != KEY_MAX_ENUM; key = *(++keylist)) { - if (keys.find(key, k) && keystate[(unsigned)k] == 1) + it = keys.find(key); + if (it != keys.end() && keystate[SDL_GetScancodeFromKey(it->second)]) return true; } return false; } -void Keyboard::setKeyRepeat(int delay, int interval) const +std::map Keyboard::createKeyMap() { - delay = (delay == DEFAULT) ? SDL_DEFAULT_REPEAT_DELAY : delay; - interval = (interval == DEFAULT) ? SDL_DEFAULT_REPEAT_INTERVAL : interval; + std::map k; - SDL_EnableKeyRepeat(delay, interval); + k[Keyboard::KEY_UNKNOWN] = SDLK_UNKNOWN; + + k[Keyboard::KEY_RETURN] = SDLK_RETURN; + k[Keyboard::KEY_ESCAPE] = SDLK_ESCAPE; + k[Keyboard::KEY_BACKSPACE] = SDLK_BACKSPACE; + k[Keyboard::KEY_TAB] = SDLK_TAB; + k[Keyboard::KEY_SPACE] = SDLK_SPACE; + k[Keyboard::KEY_EXCLAIM] = SDLK_EXCLAIM; + k[Keyboard::KEY_QUOTEDBL] = SDLK_QUOTEDBL; + k[Keyboard::KEY_HASH] = SDLK_HASH; + k[Keyboard::KEY_DOLLAR] = SDLK_DOLLAR; + k[Keyboard::KEY_AMPERSAND] = SDLK_AMPERSAND; + k[Keyboard::KEY_QUOTE] = SDLK_QUOTE; + k[Keyboard::KEY_LEFTPAREN] = SDLK_LEFTPAREN; + k[Keyboard::KEY_RIGHTPAREN] = SDLK_RIGHTPAREN; + k[Keyboard::KEY_ASTERISK] = SDLK_ASTERISK; + k[Keyboard::KEY_PLUS] = SDLK_PLUS; + k[Keyboard::KEY_COMMA] = SDLK_COMMA; + k[Keyboard::KEY_MINUS] = SDLK_MINUS; + k[Keyboard::KEY_PERIOD] = SDLK_PERIOD; + k[Keyboard::KEY_SLASH] = SDLK_SLASH; + k[Keyboard::KEY_0] = SDLK_0; + k[Keyboard::KEY_1] = SDLK_1; + k[Keyboard::KEY_2] = SDLK_2; + k[Keyboard::KEY_3] = SDLK_3; + k[Keyboard::KEY_4] = SDLK_4; + k[Keyboard::KEY_5] = SDLK_5; + k[Keyboard::KEY_6] = SDLK_6; + k[Keyboard::KEY_7] = SDLK_7; + k[Keyboard::KEY_8] = SDLK_8; + k[Keyboard::KEY_9] = SDLK_9; + k[Keyboard::KEY_COLON] = SDLK_COLON; + k[Keyboard::KEY_SEMICOLON] = SDLK_SEMICOLON; + k[Keyboard::KEY_LESS] = SDLK_LESS; + k[Keyboard::KEY_EQUALS] = SDLK_EQUALS; + k[Keyboard::KEY_GREATER] = SDLK_GREATER; + k[Keyboard::KEY_QUESTION] = SDLK_QUESTION; + k[Keyboard::KEY_AT] = SDLK_AT; + + k[Keyboard::KEY_LEFTBRACKET] = SDLK_LEFTBRACKET; + k[Keyboard::KEY_BACKSLASH] = SDLK_BACKSLASH; + k[Keyboard::KEY_RIGHTBRACKET] = SDLK_RIGHTBRACKET; + k[Keyboard::KEY_CARET] = SDLK_CARET; + k[Keyboard::KEY_UNDERSCORE] = SDLK_UNDERSCORE; + k[Keyboard::KEY_BACKQUOTE] = SDLK_BACKQUOTE; + k[Keyboard::KEY_A] = SDLK_a; + k[Keyboard::KEY_B] = SDLK_b; + k[Keyboard::KEY_C] = SDLK_c; + k[Keyboard::KEY_D] = SDLK_d; + k[Keyboard::KEY_E] = SDLK_e; + k[Keyboard::KEY_F] = SDLK_f; + k[Keyboard::KEY_G] = SDLK_g; + k[Keyboard::KEY_H] = SDLK_h; + k[Keyboard::KEY_I] = SDLK_i; + k[Keyboard::KEY_J] = SDLK_j; + k[Keyboard::KEY_K] = SDLK_k; + k[Keyboard::KEY_L] = SDLK_l; + k[Keyboard::KEY_M] = SDLK_m; + k[Keyboard::KEY_N] = SDLK_n; + k[Keyboard::KEY_O] = SDLK_o; + k[Keyboard::KEY_P] = SDLK_p; + k[Keyboard::KEY_Q] = SDLK_q; + k[Keyboard::KEY_R] = SDLK_r; + k[Keyboard::KEY_S] = SDLK_s; + k[Keyboard::KEY_T] = SDLK_t; + k[Keyboard::KEY_U] = SDLK_u; + k[Keyboard::KEY_V] = SDLK_v; + k[Keyboard::KEY_W] = SDLK_w; + k[Keyboard::KEY_X] = SDLK_x; + k[Keyboard::KEY_Y] = SDLK_y; + k[Keyboard::KEY_Z] = SDLK_z; + + k[Keyboard::KEY_CAPSLOCK] = SDLK_CAPSLOCK; + + k[Keyboard::KEY_F1] = SDLK_F1; + k[Keyboard::KEY_F2] = SDLK_F2; + k[Keyboard::KEY_F3] = SDLK_F3; + k[Keyboard::KEY_F4] = SDLK_F4; + k[Keyboard::KEY_F5] = SDLK_F5; + k[Keyboard::KEY_F6] = SDLK_F6; + k[Keyboard::KEY_F7] = SDLK_F7; + k[Keyboard::KEY_F8] = SDLK_F8; + k[Keyboard::KEY_F9] = SDLK_F9; + k[Keyboard::KEY_F10] = SDLK_F10; + k[Keyboard::KEY_F11] = SDLK_F11; + k[Keyboard::KEY_F12] = SDLK_F12; + + k[Keyboard::KEY_PRINTSCREEN] = SDLK_PRINTSCREEN; + k[Keyboard::KEY_SCROLLLOCK] = SDLK_SCROLLLOCK; + k[Keyboard::KEY_PAUSE] = SDLK_PAUSE; + k[Keyboard::KEY_INSERT] = SDLK_INSERT; + k[Keyboard::KEY_HOME] = SDLK_HOME; + k[Keyboard::KEY_PAGEUP] = SDLK_PAGEUP; + k[Keyboard::KEY_DELETE] = SDLK_DELETE; + k[Keyboard::KEY_END] = SDLK_END; + k[Keyboard::KEY_PAGEDOWN] = SDLK_PAGEDOWN; + k[Keyboard::KEY_RIGHT] = SDLK_RIGHT; + k[Keyboard::KEY_LEFT] = SDLK_LEFT; + k[Keyboard::KEY_DOWN] = SDLK_DOWN; + k[Keyboard::KEY_UP] = SDLK_UP; + + k[Keyboard::KEY_NUMLOCKCLEAR] = SDLK_NUMLOCKCLEAR; + k[Keyboard::KEY_KP_DIVIDE] = SDLK_KP_DIVIDE; + k[Keyboard::KEY_KP_MULTIPLY] = SDLK_KP_MULTIPLY; + k[Keyboard::KEY_KP_MINUS] = SDLK_KP_MINUS; + k[Keyboard::KEY_KP_PLUS] = SDLK_KP_PLUS; + k[Keyboard::KEY_KP_ENTER] = SDLK_KP_ENTER; + k[Keyboard::KEY_KP_0] = SDLK_KP_0; + k[Keyboard::KEY_KP_1] = SDLK_KP_1; + k[Keyboard::KEY_KP_2] = SDLK_KP_2; + k[Keyboard::KEY_KP_3] = SDLK_KP_3; + k[Keyboard::KEY_KP_4] = SDLK_KP_4; + k[Keyboard::KEY_KP_5] = SDLK_KP_5; + k[Keyboard::KEY_KP_6] = SDLK_KP_6; + k[Keyboard::KEY_KP_7] = SDLK_KP_7; + k[Keyboard::KEY_KP_8] = SDLK_KP_8; + k[Keyboard::KEY_KP_9] = SDLK_KP_9; + k[Keyboard::KEY_KP_PERIOD] = SDLK_KP_PERIOD; + k[Keyboard::KEY_KP_COMMA] = SDLK_KP_COMMA; + k[Keyboard::KEY_KP_EQUALS] = SDLK_KP_EQUALS; + + k[Keyboard::KEY_APPLICATION] = SDLK_APPLICATION; + k[Keyboard::KEY_POWER] = SDLK_POWER; + k[Keyboard::KEY_F13] = SDLK_F13; + k[Keyboard::KEY_F14] = SDLK_F14; + k[Keyboard::KEY_F15] = SDLK_F15; + k[Keyboard::KEY_F16] = SDLK_F16; + k[Keyboard::KEY_F17] = SDLK_F17; + k[Keyboard::KEY_F18] = SDLK_F18; + k[Keyboard::KEY_F19] = SDLK_F19; + k[Keyboard::KEY_F20] = SDLK_F20; + k[Keyboard::KEY_F21] = SDLK_F21; + k[Keyboard::KEY_F22] = SDLK_F22; + k[Keyboard::KEY_F23] = SDLK_F23; + k[Keyboard::KEY_F24] = SDLK_F24; + k[Keyboard::KEY_EXECUTE] = SDLK_EXECUTE; + k[Keyboard::KEY_HELP] = SDLK_HELP; + k[Keyboard::KEY_MENU] = SDLK_MENU; + k[Keyboard::KEY_SELECT] = SDLK_SELECT; + k[Keyboard::KEY_STOP] = SDLK_STOP; + k[Keyboard::KEY_AGAIN] = SDLK_AGAIN; + k[Keyboard::KEY_UNDO] = SDLK_UNDO; + k[Keyboard::KEY_CUT] = SDLK_CUT; + k[Keyboard::KEY_COPY] = SDLK_COPY; + k[Keyboard::KEY_PASTE] = SDLK_PASTE; + k[Keyboard::KEY_FIND] = SDLK_FIND; + k[Keyboard::KEY_MUTE] = SDLK_MUTE; + k[Keyboard::KEY_VOLUMEUP] = SDLK_VOLUMEUP; + k[Keyboard::KEY_VOLUMEDOWN] = SDLK_VOLUMEDOWN; + + k[Keyboard::KEY_ALTERASE] = SDLK_ALTERASE; + k[Keyboard::KEY_SYSREQ] = SDLK_SYSREQ; + k[Keyboard::KEY_CANCEL] = SDLK_CANCEL; + k[Keyboard::KEY_CLEAR] = SDLK_CLEAR; + k[Keyboard::KEY_PRIOR] = SDLK_PRIOR; + k[Keyboard::KEY_RETURN2] = SDLK_RETURN2; + k[Keyboard::KEY_SEPARATOR] = SDLK_SEPARATOR; + k[Keyboard::KEY_OUT] = SDLK_OUT; + k[Keyboard::KEY_OPER] = SDLK_OPER; + k[Keyboard::KEY_CLEARAGAIN] = SDLK_CLEARAGAIN; + + k[Keyboard::KEY_THOUSANDSSEPARATOR] = SDLK_THOUSANDSSEPARATOR; + k[Keyboard::KEY_DECIMALSEPARATOR] = SDLK_DECIMALSEPARATOR; + k[Keyboard::KEY_CURRENCYUNIT] = SDLK_CURRENCYUNIT; + k[Keyboard::KEY_CURRENCYSUBUNIT] = SDLK_CURRENCYSUBUNIT; + + k[Keyboard::KEY_LCTRL] = SDLK_LCTRL; + k[Keyboard::KEY_LSHIFT] = SDLK_LSHIFT; + k[Keyboard::KEY_LALT] = SDLK_LALT; + k[Keyboard::KEY_LGUI] = SDLK_LGUI; + k[Keyboard::KEY_RCTRL] = SDLK_RCTRL; + k[Keyboard::KEY_RSHIFT] = SDLK_RSHIFT; + k[Keyboard::KEY_RALT] = SDLK_RALT; + k[Keyboard::KEY_RGUI] = SDLK_RGUI; + + k[Keyboard::KEY_MODE] = SDLK_MODE; + + k[Keyboard::KEY_AUDIONEXT] = SDLK_AUDIONEXT; + k[Keyboard::KEY_AUDIOPREV] = SDLK_AUDIOPREV; + k[Keyboard::KEY_AUDIOSTOP] = SDLK_AUDIOSTOP; + k[Keyboard::KEY_AUDIOPLAY] = SDLK_AUDIOPLAY; + k[Keyboard::KEY_AUDIOMUTE] = SDLK_AUDIOMUTE; + k[Keyboard::KEY_MEDIASELECT] = SDLK_MEDIASELECT; + + k[Keyboard::KEY_BRIGHTNESSDOWN] = SDLK_BRIGHTNESSDOWN; + k[Keyboard::KEY_BRIGHTNESSUP] = SDLK_BRIGHTNESSUP; + k[Keyboard::KEY_DISPLAYSWITCH] = SDLK_DISPLAYSWITCH; + k[Keyboard::KEY_KBDILLUMTOGGLE] = SDLK_KBDILLUMTOGGLE; + k[Keyboard::KEY_KBDILLUMDOWN] = SDLK_KBDILLUMDOWN; + k[Keyboard::KEY_KBDILLUMUP] = SDLK_KBDILLUMUP; + k[Keyboard::KEY_EJECT] = SDLK_EJECT; + k[Keyboard::KEY_SLEEP] = SDLK_SLEEP; + + return k; } -int Keyboard::getKeyRepeatDelay() const -{ - int delay, interval; - SDL_GetKeyRepeat(&delay, &interval); - return delay; -} - -int Keyboard::getKeyRepeatInterval() const -{ - int delay, interval; - SDL_GetKeyRepeat(&delay, &interval); - return interval; -} - -EnumMap::Entry Keyboard::keyEntries[] = -{ - { Keyboard::KEY_BACKSPACE, SDLK_BACKSPACE}, - { Keyboard::KEY_TAB, SDLK_TAB}, - { Keyboard::KEY_CLEAR, SDLK_CLEAR}, - { Keyboard::KEY_RETURN, SDLK_RETURN}, - { Keyboard::KEY_PAUSE, SDLK_PAUSE}, - { Keyboard::KEY_ESCAPE, SDLK_ESCAPE }, - { Keyboard::KEY_SPACE, SDLK_SPACE }, - { Keyboard::KEY_EXCLAIM, SDLK_EXCLAIM }, - { Keyboard::KEY_QUOTEDBL, SDLK_QUOTEDBL }, - { Keyboard::KEY_HASH, SDLK_HASH }, - { Keyboard::KEY_DOLLAR, SDLK_DOLLAR }, - { Keyboard::KEY_AMPERSAND, SDLK_AMPERSAND }, - { Keyboard::KEY_QUOTE, SDLK_QUOTE }, - { Keyboard::KEY_LEFTPAREN, SDLK_LEFTPAREN }, - { Keyboard::KEY_RIGHTPAREN, SDLK_RIGHTPAREN }, - { Keyboard::KEY_ASTERISK, SDLK_ASTERISK }, - { Keyboard::KEY_PLUS, SDLK_PLUS }, - { Keyboard::KEY_COMMA, SDLK_COMMA }, - { Keyboard::KEY_MINUS, SDLK_MINUS }, - { Keyboard::KEY_PERIOD, SDLK_PERIOD }, - { Keyboard::KEY_SLASH, SDLK_SLASH }, - { Keyboard::KEY_0, SDLK_0 }, - { Keyboard::KEY_1, SDLK_1 }, - { Keyboard::KEY_2, SDLK_2 }, - { Keyboard::KEY_3, SDLK_3 }, - { Keyboard::KEY_4, SDLK_4 }, - { Keyboard::KEY_5, SDLK_5 }, - { Keyboard::KEY_6, SDLK_6 }, - { Keyboard::KEY_7, SDLK_7 }, - { Keyboard::KEY_8, SDLK_8 }, - { Keyboard::KEY_9, SDLK_9 }, - { Keyboard::KEY_COLON, SDLK_COLON }, - { Keyboard::KEY_SEMICOLON, SDLK_SEMICOLON }, - { Keyboard::KEY_LESS, SDLK_LESS }, - { Keyboard::KEY_EQUALS, SDLK_EQUALS }, - { Keyboard::KEY_GREATER, SDLK_GREATER }, - { Keyboard::KEY_QUESTION, SDLK_QUESTION }, - { Keyboard::KEY_AT, SDLK_AT }, - - { Keyboard::KEY_LEFTBRACKET, SDLK_LEFTBRACKET }, - { Keyboard::KEY_BACKSLASH, SDLK_BACKSLASH }, - { Keyboard::KEY_RIGHTBRACKET, SDLK_RIGHTBRACKET }, - { Keyboard::KEY_CARET, SDLK_CARET }, - { Keyboard::KEY_UNDERSCORE, SDLK_UNDERSCORE }, - { Keyboard::KEY_BACKQUOTE, SDLK_BACKQUOTE }, - { Keyboard::KEY_A, SDLK_a }, - { Keyboard::KEY_B, SDLK_b }, - { Keyboard::KEY_C, SDLK_c }, - { Keyboard::KEY_D, SDLK_d }, - { Keyboard::KEY_E, SDLK_e }, - { Keyboard::KEY_F, SDLK_f }, - { Keyboard::KEY_G, SDLK_g }, - { Keyboard::KEY_H, SDLK_h }, - { Keyboard::KEY_I, SDLK_i }, - { Keyboard::KEY_J, SDLK_j }, - { Keyboard::KEY_K, SDLK_k }, - { Keyboard::KEY_L, SDLK_l }, - { Keyboard::KEY_M, SDLK_m }, - { Keyboard::KEY_N, SDLK_n }, - { Keyboard::KEY_O, SDLK_o }, - { Keyboard::KEY_P, SDLK_p }, - { Keyboard::KEY_Q, SDLK_q }, - { Keyboard::KEY_R, SDLK_r }, - { Keyboard::KEY_S, SDLK_s }, - { Keyboard::KEY_T, SDLK_t }, - { Keyboard::KEY_U, SDLK_u }, - { Keyboard::KEY_V, SDLK_v }, - { Keyboard::KEY_W, SDLK_w }, - { Keyboard::KEY_X, SDLK_x }, - { Keyboard::KEY_Y, SDLK_y }, - { Keyboard::KEY_Z, SDLK_z }, - { Keyboard::KEY_DELETE, SDLK_DELETE }, - - { Keyboard::KEY_KP0, SDLK_KP0 }, - { Keyboard::KEY_KP1, SDLK_KP1 }, - { Keyboard::KEY_KP2, SDLK_KP2 }, - { Keyboard::KEY_KP3, SDLK_KP3 }, - { Keyboard::KEY_KP4, SDLK_KP4 }, - { Keyboard::KEY_KP5, SDLK_KP5 }, - { Keyboard::KEY_KP6, SDLK_KP6 }, - { Keyboard::KEY_KP7, SDLK_KP7 }, - { Keyboard::KEY_KP8, SDLK_KP8 }, - { Keyboard::KEY_KP9, SDLK_KP9 }, - { Keyboard::KEY_KP_PERIOD, SDLK_KP_PERIOD }, - { Keyboard::KEY_KP_DIVIDE, SDLK_KP_DIVIDE }, - { Keyboard::KEY_KP_MULTIPLY, SDLK_KP_MULTIPLY}, - { Keyboard::KEY_KP_MINUS, SDLK_KP_MINUS }, - { Keyboard::KEY_KP_PLUS, SDLK_KP_PLUS }, - { Keyboard::KEY_KP_ENTER, SDLK_KP_ENTER }, - { Keyboard::KEY_KP_EQUALS, SDLK_KP_EQUALS }, - - { Keyboard::KEY_UP, SDLK_UP }, - { Keyboard::KEY_DOWN, SDLK_DOWN }, - { Keyboard::KEY_RIGHT, SDLK_RIGHT }, - { Keyboard::KEY_LEFT, SDLK_LEFT }, - { Keyboard::KEY_INSERT, SDLK_INSERT }, - { Keyboard::KEY_HOME, SDLK_HOME }, - { Keyboard::KEY_END, SDLK_END }, - { Keyboard::KEY_PAGEUP, SDLK_PAGEUP }, - { Keyboard::KEY_PAGEDOWN, SDLK_PAGEDOWN }, - - { Keyboard::KEY_F1, SDLK_F1 }, - { Keyboard::KEY_F2, SDLK_F2 }, - { Keyboard::KEY_F3, SDLK_F3 }, - { Keyboard::KEY_F4, SDLK_F4 }, - { Keyboard::KEY_F5, SDLK_F5 }, - { Keyboard::KEY_F6, SDLK_F6 }, - { Keyboard::KEY_F7, SDLK_F7 }, - { Keyboard::KEY_F8, SDLK_F8 }, - { Keyboard::KEY_F9, SDLK_F9 }, - { Keyboard::KEY_F10, SDLK_F10 }, - { Keyboard::KEY_F11, SDLK_F11 }, - { Keyboard::KEY_F12, SDLK_F12 }, - { Keyboard::KEY_F13, SDLK_F13 }, - { Keyboard::KEY_F14, SDLK_F14 }, - { Keyboard::KEY_F15, SDLK_F15 }, - - { Keyboard::KEY_NUMLOCK, SDLK_NUMLOCK }, - { Keyboard::KEY_CAPSLOCK, SDLK_CAPSLOCK }, - { Keyboard::KEY_SCROLLOCK, SDLK_SCROLLOCK }, - { Keyboard::KEY_RSHIFT, SDLK_RSHIFT }, - { Keyboard::KEY_LSHIFT, SDLK_LSHIFT }, - { Keyboard::KEY_RCTRL, SDLK_RCTRL }, - { Keyboard::KEY_LCTRL, SDLK_LCTRL }, - { Keyboard::KEY_RALT, SDLK_RALT }, - { Keyboard::KEY_LALT, SDLK_LALT }, - { Keyboard::KEY_RMETA, SDLK_RMETA }, - { Keyboard::KEY_LMETA, SDLK_LMETA }, - { Keyboard::KEY_LSUPER, SDLK_LSUPER }, - { Keyboard::KEY_RSUPER, SDLK_RSUPER }, - { Keyboard::KEY_MODE, SDLK_MODE }, - { Keyboard::KEY_COMPOSE, SDLK_COMPOSE }, - - { Keyboard::KEY_HELP, SDLK_HELP }, - { Keyboard::KEY_PRINT, SDLK_PRINT }, - { Keyboard::KEY_SYSREQ, SDLK_SYSREQ }, - { Keyboard::KEY_BREAK, SDLK_BREAK }, - { Keyboard::KEY_MENU, SDLK_MENU }, - { Keyboard::KEY_POWER, SDLK_POWER }, - { Keyboard::KEY_EURO, SDLK_EURO }, - { Keyboard::KEY_UNDO, SDLK_UNDO }, -}; - -EnumMap Keyboard::keys(Keyboard::keyEntries, sizeof(Keyboard::keyEntries)); - +std::map Keyboard::keys = Keyboard::createKeyMap(); } // sdl } // keyboard diff --git a/src/modules/keyboard/sdl/Keyboard.h b/src/modules/keyboard/sdl/Keyboard.h index 4033e23dc..002fbb0d2 100644 --- a/src/modules/keyboard/sdl/Keyboard.h +++ b/src/modules/keyboard/sdl/Keyboard.h @@ -28,6 +28,9 @@ // SDL #include +// STL +#include + namespace love { namespace keyboard @@ -42,14 +45,11 @@ public: // Implements Module. const char *getName() const; bool isDown(Key *keylist) const; - void setKeyRepeat(int delay, int interval) const; - int getKeyRepeatDelay() const; - int getKeyRepeatInterval() const; private: - static EnumMap::Entry keyEntries[]; - static EnumMap keys; + static std::map createKeyMap(); + static std::map keys; }; // Keyboard diff --git a/src/modules/keyboard/wrap_Keyboard.cpp b/src/modules/keyboard/wrap_Keyboard.cpp index 5c378337a..4faf29e77 100644 --- a/src/modules/keyboard/wrap_Keyboard.cpp +++ b/src/modules/keyboard/wrap_Keyboard.cpp @@ -50,34 +50,10 @@ int w_isDown(lua_State *L) return 1; } -int w_setKeyRepeat(lua_State *L) -{ - if (lua_gettop(L) == 0) - { - // Disables key repeat. - instance->setKeyRepeat(0, 0); - return 0; - } - - int delay = lua_isnumber(L, 1) ? (int)(lua_tonumber(L, 1) * 1000 + 0.5) : Keyboard::DEFAULT; - int interval = lua_isnumber(L, 2) ? (int)(lua_tonumber(L, 2) * 1000 + 0.5) : Keyboard::DEFAULT; - instance->setKeyRepeat(delay, interval); - return 0; -} - -int w_getKeyRepeat(lua_State *L) -{ - lua_pushnumber(L, (lua_Number) instance->getKeyRepeatDelay() * 0.001); - lua_pushnumber(L, (lua_Number) instance->getKeyRepeatInterval() * 0.001); - return 2; -} - // List of functions to wrap. static const luaL_Reg functions[] = { { "isDown", w_isDown }, - { "setKeyRepeat", w_setKeyRepeat }, - { "getKeyRepeat", w_getKeyRepeat }, { 0, 0 } }; diff --git a/src/modules/keyboard/wrap_Keyboard.h b/src/modules/keyboard/wrap_Keyboard.h index 6fa841b9d..a052e93f1 100644 --- a/src/modules/keyboard/wrap_Keyboard.h +++ b/src/modules/keyboard/wrap_Keyboard.h @@ -30,8 +30,6 @@ namespace keyboard { int w_isDown(lua_State *L); -int w_setKeyRepeat(lua_State *L); -int w_getKeyRepeat(lua_State *L); extern "C" LOVE_EXPORT int luaopen_love_keyboard(lua_State *L); } // keyboard diff --git a/src/modules/love/love.cpp b/src/modules/love/love.cpp index 7dfd7892d..6b959024c 100644 --- a/src/modules/love/love.cpp +++ b/src/modules/love/love.cpp @@ -103,6 +103,7 @@ extern "C" extern int luaopen_love_mouse(lua_State*); extern int luaopen_love_physics(lua_State*); extern int luaopen_love_sound(lua_State*); + extern int luaopen_love_system(lua_State*); extern int luaopen_love_timer(lua_State*); extern int luaopen_love_thread(lua_State*); extern int luaopen_love_window(lua_State*); @@ -122,6 +123,7 @@ static const luaL_Reg modules[] = { { "love.mouse", luaopen_love_mouse }, { "love.physics", luaopen_love_physics }, { "love.sound", luaopen_love_sound }, + { "love.system", luaopen_love_system }, { "love.timer", luaopen_love_timer }, { "love.thread", luaopen_love_thread }, { "love.window", luaopen_love_window }, diff --git a/src/modules/mouse/Cursor.cpp b/src/modules/mouse/Cursor.cpp new file mode 100644 index 000000000..8b7632ed6 --- /dev/null +++ b/src/modules/mouse/Cursor.cpp @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#include "Cursor.h" + +namespace love +{ +namespace mouse +{ + +Cursor::~Cursor() +{ +} + +bool Cursor::getConstant(const char *in, SystemCursor &out) +{ + return systemCursors.find(in, out); +} + +bool Cursor::getConstant(SystemCursor in, const char *&out) +{ + return systemCursors.find(in, out); +} + +bool Cursor::getConstant(const char *in, CursorType &out) +{ + return types.find(in, out); +} + +bool Cursor::getConstant(CursorType in, const char *&out) +{ + return types.find(in, out); +} + +StringMap::Entry Cursor::systemCursorEntries[] = +{ + {"arrow", Cursor::CURSOR_ARROW}, + {"ibeam", Cursor::CURSOR_IBEAM}, + {"wait", Cursor::CURSOR_WAIT}, + {"crosshair", Cursor::CURSOR_CROSSHAIR}, + {"waitarrow", Cursor::CURSOR_WAITARROW}, + {"sizenwse", Cursor::CURSOR_SIZENWSE}, + {"sizenesw", Cursor::CURSOR_SIZENESW}, + {"sizewe", Cursor::CURSOR_SIZEWE}, + {"sizens", Cursor::CURSOR_SIZENS}, + {"sizeall", Cursor::CURSOR_SIZEALL}, + {"no", Cursor::CURSOR_NO}, + {"hand", Cursor::CURSOR_HAND}, +}; + +StringMap Cursor::systemCursors(Cursor::systemCursorEntries, sizeof(Cursor::systemCursorEntries)); + +StringMap::Entry Cursor::typeEntries[] = +{ + {"system", Cursor::CURSORTYPE_SYSTEM}, + {"image", Cursor::CURSORTYPE_IMAGE}, +}; + +StringMap Cursor::types(Cursor::typeEntries, sizeof(Cursor::typeEntries)); + +} // mouse +} // love diff --git a/src/modules/mouse/Cursor.h b/src/modules/mouse/Cursor.h new file mode 100644 index 000000000..9bbdcdfce --- /dev/null +++ b/src/modules/mouse/Cursor.h @@ -0,0 +1,100 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#ifndef LOVE_MOUSE_CURSOR_H +#define LOVE_MOUSE_CURSOR_H + +// LOVE +#include "image/ImageData.h" +#include "common/Object.h" +#include "common/StringMap.h" + +namespace love +{ +namespace mouse +{ + +class Cursor : public Object +{ +public: + + // Types of system cursors. + enum SystemCursor + { + CURSOR_ARROW, + CURSOR_IBEAM, + CURSOR_WAIT, + CURSOR_CROSSHAIR, + CURSOR_WAITARROW, + CURSOR_SIZENWSE, + CURSOR_SIZENESW, + CURSOR_SIZEWE, + CURSOR_SIZENS, + CURSOR_SIZEALL, + CURSOR_NO, + CURSOR_HAND, + CURSOR_MAX_ENUM + }; + + enum CursorType + { + CURSORTYPE_SYSTEM, + CURSORTYPE_IMAGE, + CURSORTYPE_MAX_ENUM + }; + + virtual ~Cursor(); + + /** + * Returns a pointer to the implementation-dependent handle of this Cursor. + **/ + virtual void *getHandle() const = 0; + + /** + * Returns whether this Cursor is system-defined or a custom image. + **/ + virtual CursorType getType() const = 0; + + /** + * Returns the type type of system cursor used, if this Cursor is using a + * system-defined image. + **/ + virtual SystemCursor getSystemType() const = 0; + + static bool getConstant(const char *in, SystemCursor &out); + static bool getConstant(SystemCursor in, const char *&out); + + static bool getConstant(const char *in, CursorType &out); + static bool getConstant(CursorType in, const char *&out); + +private: + + static StringMap::Entry systemCursorEntries[]; + static StringMap systemCursors; + + static StringMap::Entry typeEntries[]; + static StringMap types; + +}; + +} // mouse +} // love + +#endif // LOVE_MOUSE_CURSOR_H diff --git a/src/modules/mouse/Mouse.h b/src/modules/mouse/Mouse.h index 7a7aef99d..f11492fda 100644 --- a/src/modules/mouse/Mouse.h +++ b/src/modules/mouse/Mouse.h @@ -22,8 +22,10 @@ #define LOVE_MOUSE_MOUSE_H // LOVE +#include "Cursor.h" #include "common/Module.h" #include "common/StringMap.h" +#include "image/ImageData.h" namespace love { @@ -49,6 +51,14 @@ public: virtual ~Mouse() {}; + virtual Cursor *newCursor(love::image::ImageData *data, int hotx, int hoty) = 0; + virtual Cursor *newCursor(Cursor::SystemCursor cursortype) = 0; + + virtual void setCursor(Cursor *cursor) = 0; + virtual void setCursor() = 0; + + virtual Cursor *getCursor() const = 0; + virtual int getX() const = 0; virtual int getY() const = 0; virtual void getPosition(int &x, int &y) const = 0; diff --git a/src/modules/mouse/sdl/Cursor.cpp b/src/modules/mouse/sdl/Cursor.cpp new file mode 100644 index 000000000..53f20afe0 --- /dev/null +++ b/src/modules/mouse/sdl/Cursor.cpp @@ -0,0 +1,122 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +// LOVE +#include "Cursor.h" +#include "common/config.h" + +namespace love +{ +namespace mouse +{ +namespace sdl +{ + +Cursor::Cursor(image::ImageData *data, int hotx, int hoty) + : cursor(0) + , type(CURSORTYPE_IMAGE) + , systemType(CURSOR_MAX_ENUM) +{ + Uint32 rmask, gmask, bmask, amask; +#ifdef LOVE_BIG_ENDIAN + rmask = 0xFF000000; + gmask = 0x00FF0000; + bmask = 0x0000FF00; + amask = 0x000000FF; +#else + rmask = 0x000000FF; + gmask = 0x0000FF00; + bmask = 0x00FF0000; + amask = 0xFF000000; +#endif + + int w = data->getWidth(); + int h = data->getHeight(); + int pitch = w * 4; + + SDL_Surface *surface = SDL_CreateRGBSurfaceFrom(data->getData(), w, h, 32, pitch, rmask, gmask, bmask, amask); + if (!surface) + throw love::Exception("Cannot create cursor: out of memory!"); + + cursor = SDL_CreateColorCursor(surface, hotx, hoty); + SDL_FreeSurface(surface); + + if (!cursor) + throw love::Exception("Cannot create cursor: %s", SDL_GetError()); +} + +Cursor::Cursor(mouse::Cursor::SystemCursor cursortype) + : cursor(0) + , type(CURSORTYPE_SYSTEM) + , systemType(cursortype) +{ + SDL_SystemCursor sdlcursortype; + + if (systemCursors.find(cursortype, sdlcursortype)) + cursor = SDL_CreateSystemCursor(sdlcursortype); + else + throw love::Exception("Cannot create system cursor: invalid type."); + + if (!cursor) + throw love::Exception("Cannot create system cursor: %s", SDL_GetError()); +} + +Cursor::~Cursor() +{ + if (cursor) + SDL_FreeCursor(cursor); +} + +void *Cursor::getHandle() const +{ + return cursor; +} + +Cursor::CursorType Cursor::getType() const +{ + return type; +} + +Cursor::SystemCursor Cursor::getSystemType() const +{ + return systemType; +} + +EnumMap::Entry Cursor::systemCursorEntries[] = +{ + {Cursor::CURSOR_ARROW, SDL_SYSTEM_CURSOR_ARROW}, + {Cursor::CURSOR_IBEAM, SDL_SYSTEM_CURSOR_IBEAM}, + {Cursor::CURSOR_WAIT, SDL_SYSTEM_CURSOR_WAIT}, + {Cursor::CURSOR_CROSSHAIR, SDL_SYSTEM_CURSOR_CROSSHAIR}, + {Cursor::CURSOR_WAITARROW, SDL_SYSTEM_CURSOR_WAITARROW}, + {Cursor::CURSOR_SIZENWSE, SDL_SYSTEM_CURSOR_SIZENWSE}, + {Cursor::CURSOR_SIZENESW, SDL_SYSTEM_CURSOR_SIZENESW}, + {Cursor::CURSOR_SIZEWE, SDL_SYSTEM_CURSOR_SIZEWE}, + {Cursor::CURSOR_SIZENS, SDL_SYSTEM_CURSOR_SIZENS}, + {Cursor::CURSOR_SIZEALL, SDL_SYSTEM_CURSOR_SIZEALL}, + {Cursor::CURSOR_NO, SDL_SYSTEM_CURSOR_NO}, + {Cursor::CURSOR_HAND, SDL_SYSTEM_CURSOR_HAND}, +}; + +EnumMap Cursor::systemCursors(Cursor::systemCursorEntries, sizeof(Cursor::systemCursorEntries)); + +} // sdl +} // mouse +} // love diff --git a/src/modules/mouse/sdl/Cursor.h b/src/modules/mouse/sdl/Cursor.h new file mode 100644 index 000000000..f2ef1822e --- /dev/null +++ b/src/modules/mouse/sdl/Cursor.h @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#ifndef LOVE_MOUSE_SDL_CURSOR_H +#define LOVE_MOUSE_SDL_CURSOR_H + +// LOVE +#include "mouse/Cursor.h" +#include "common/EnumMap.h" + +// SDL +#include + +namespace love +{ +namespace mouse +{ +namespace sdl +{ + +class Cursor : public love::mouse::Cursor +{ +public: + + Cursor(image::ImageData *imageData, int hotx, int hoty); + Cursor(SystemCursor cursortype); + ~Cursor(); + + void *getHandle() const; + CursorType getType() const; + SystemCursor getSystemType() const; + +private: + + SDL_Cursor *cursor; + CursorType type; + SystemCursor systemType; + + static EnumMap::Entry systemCursorEntries[]; + static EnumMap systemCursors; +}; + +} // sdl +} // mouse +} // love + +#endif // LOVE_MOUSE_SDL_CURSOR_H diff --git a/src/modules/mouse/sdl/Mouse.cpp b/src/modules/mouse/sdl/Mouse.cpp index 5ea238804..9dceed70b 100644 --- a/src/modules/mouse/sdl/Mouse.cpp +++ b/src/modules/mouse/sdl/Mouse.cpp @@ -18,10 +18,12 @@ * 3. This notice may not be removed or altered from any source distribution. **/ +// LOVE #include "Mouse.h" +#include "window/sdl/Window.h" // SDL -#include +#include namespace love { @@ -35,6 +37,50 @@ const char *Mouse::getName() const return "love.mouse.sdl"; } +Mouse::Mouse() + : curCursor(0) +{ +} + +Mouse::~Mouse() +{ + if (curCursor) + setCursor(); +} + +love::mouse::Cursor *Mouse::newCursor(love::image::ImageData *data, int hotx, int hoty) +{ + return new Cursor(data, hotx, hoty); +} + +love::mouse::Cursor *Mouse::newCursor(love::mouse::Cursor::SystemCursor cursortype) +{ + return new Cursor(cursortype); +} + +void Mouse::setCursor(love::mouse::Cursor *cursor) +{ + Object::AutoRelease cursorrelease(curCursor); + + curCursor = cursor; + curCursor->retain(); + + SDL_SetCursor((SDL_Cursor *) cursor->getHandle()); +} + +void Mouse::setCursor() +{ + Object::AutoRelease cursorrelease(curCursor); + curCursor = NULL; + + SDL_SetCursor(SDL_GetDefaultCursor()); +} + +love::mouse::Cursor *Mouse::getCursor() const +{ + return curCursor; +} + int Mouse::getX() const { int x; @@ -56,7 +102,13 @@ void Mouse::getPosition(int &x, int &y) const void Mouse::setPosition(int x, int y) { - SDL_WarpMouse(x, y); + love::window::Window *window = love::window::sdl::Window::getSingleton(); + + SDL_Window *handle = NULL; + if (window) + handle = (SDL_Window *) window->getHandle(); + + SDL_WarpMouseInWindow(handle, x, y); } void Mouse::setX(int x) @@ -91,17 +143,23 @@ bool Mouse::isDown(Button *buttonlist) const bool Mouse::isVisible() const { - return (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE) ? true : false; + return SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE; } void Mouse::setGrab(bool grab) { - SDL_WM_GrabInput(grab ? SDL_GRAB_ON : SDL_GRAB_OFF); + love::window::Window *window = love::window::sdl::Window::getSingleton(); + if (window) + window->setMouseGrab(grab); } bool Mouse::isGrabbed() const { - return (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON ? true : false); + love::window::Window *window = love::window::sdl::Window::getSingleton(); + if (window) + return window->isMouseGrabbed(); + else + return false; } } // sdl diff --git a/src/modules/mouse/sdl/Mouse.h b/src/modules/mouse/sdl/Mouse.h index 8d23937d9..78d826c87 100644 --- a/src/modules/mouse/sdl/Mouse.h +++ b/src/modules/mouse/sdl/Mouse.h @@ -23,6 +23,7 @@ // LOVE #include "mouse/Mouse.h" +#include "Cursor.h" namespace love { @@ -38,6 +39,17 @@ public: // Implements Module. const char *getName() const; + Mouse(); + ~Mouse(); + + love::mouse::Cursor *newCursor(love::image::ImageData *data, int hotx, int hoty); + love::mouse::Cursor *newCursor(love::mouse::Cursor::SystemCursor cursortype); + + void setCursor(love::mouse::Cursor *cursor); + void setCursor(); + + love::mouse::Cursor *getCursor() const; + int getX() const; int getY() const; void getPosition(int &x, int &y) const; @@ -49,6 +61,11 @@ public: bool isVisible() const; void setGrab(bool grab); bool isGrabbed() const; + +private: + + love::mouse::Cursor *curCursor; + }; // Mouse } // sdl diff --git a/src/modules/mouse/wrap_Cursor.cpp b/src/modules/mouse/wrap_Cursor.cpp new file mode 100644 index 000000000..520a32e0b --- /dev/null +++ b/src/modules/mouse/wrap_Cursor.cpp @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +// LOVE +#include "wrap_Cursor.h" +#include "Cursor.h" + +namespace love +{ +namespace mouse +{ + +int w_getType(lua_State *L) +{ + mouse::Cursor *cursor = luax_checktype(L, 1, "Cursor", MOUSE_CURSOR_T); + + Cursor::CursorType ctype = cursor->getType(); + const char *ctypestr; + + if (!mouse::Cursor::getConstant(ctype, ctypestr)) + return luaL_error(L, "Unknown cursor type."); + + lua_pushstring(L, ctypestr); + + Cursor::SystemCursor systype = cursor->getSystemType(); + const char *systypestr; + + if (mouse::Cursor::getConstant(systype, systypestr)) + { + lua_pushstring(L, systypestr); + return 2; + } + + return 1; +}; + +static const luaL_Reg functions[] = +{ + { "getType", w_getType }, + { 0, 0 }, +}; + +extern "C" int luaopen_cursor(lua_State *L) +{ + return luax_register_type(L, "Cursor", functions); +} + +} // mouse +} // love \ No newline at end of file diff --git a/src/modules/mouse/wrap_Cursor.h b/src/modules/mouse/wrap_Cursor.h new file mode 100644 index 000000000..586e674b1 --- /dev/null +++ b/src/modules/mouse/wrap_Cursor.h @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#ifndef LOVE_MOUSE_WRAP_CURSOR_H +#define LOVE_MOUSE_WRAP_CURSOR_H + +// LOVE +#include "common/runtime.h" + +namespace love +{ +namespace mouse +{ + +int w_getType(lua_State *L); +extern "C" int luaopen_cursor(lua_State *L); + +} // mouse +} // love + + +#endif // LOVE_MOUSE_WRAP_CURSOR_H diff --git a/src/modules/mouse/wrap_Mouse.cpp b/src/modules/mouse/wrap_Mouse.cpp index 3967d5551..f4470c3c1 100644 --- a/src/modules/mouse/wrap_Mouse.cpp +++ b/src/modules/mouse/wrap_Mouse.cpp @@ -18,12 +18,13 @@ * 3. This notice may not be removed or altered from any source distribution. **/ +// LOVE +#include "wrap_Mouse.h" +#include "wrap_Cursor.h" #include "common/config.h" #include "sdl/Mouse.h" -#include "wrap_Mouse.h" - namespace love { namespace mouse @@ -31,6 +32,78 @@ namespace mouse static Mouse *instance = 0; +int w_newCursor(lua_State *L) +{ + Cursor *cursor = 0; + + if (lua_isstring(L, 1)) + { + // System cursor type. + const char *str = luaL_checkstring(L, 1); + Cursor::SystemCursor systemCursor; + + if (!Cursor::getConstant(str, systemCursor)) + return luaL_error(L, "Invalid cursor type %s", str); + + try + { + cursor = instance->newCursor(systemCursor); + } + catch (love::Exception &e) + { + return luaL_error(L, "%s", e.what()); + } + } + else + { + // Custom image. + love::image::ImageData *data = luax_checktype(L, 1, "ImageData", IMAGE_IMAGE_DATA_T); + int hotx = luaL_optint(L, 2, 0); + int hoty = luaL_optint(L, 3, 0); + + try + { + cursor = instance->newCursor(data, hotx, hoty); + } + catch (love::Exception &e) + { + return luaL_error(L, "%s", e.what()); + } + } + + luax_newtype(L, "Cursor", MOUSE_CURSOR_T, (void *) cursor); + return 1; +} + +int w_setCursor(lua_State *L) +{ + // Revert to the default system cursor if no argument is given. + if (lua_isnoneornil(L, 1)) + { + instance->setCursor(); + return 0; + } + + Cursor *cursor = luax_checktype(L, 1, "Cursor", MOUSE_CURSOR_T); + instance->setCursor(cursor); + return 0; +} + +int w_getCursor(lua_State *L) +{ + Cursor *cursor = instance->getCursor(); + + if (cursor) + { + cursor->retain(); + luax_newtype(L, "Cursor", MOUSE_CURSOR_T, (void *) cursor); + } + else + lua_pushnil(L); + + return 1; +} + int w_getX(lua_State *L) { lua_pushnumber(L, instance->getX()); @@ -122,6 +195,9 @@ int w_isGrabbed(lua_State *L) // List of functions to wrap. static const luaL_Reg functions[] = { + { "newCursor", w_newCursor }, + { "setCursor", w_setCursor }, + { "getCursor", w_getCursor }, { "getX", w_getX }, { "getY", w_getY }, { "setX", w_setX }, @@ -136,6 +212,13 @@ static const luaL_Reg functions[] = { 0, 0 } }; +// Types for this module. +static const lua_CFunction types[] = +{ + luaopen_cursor, + 0, +}; + extern "C" int luaopen_love_mouse(lua_State *L) { if (instance == 0) @@ -157,7 +240,7 @@ extern "C" int luaopen_love_mouse(lua_State *L) w.name = "mouse"; w.flags = MODULE_T; w.functions = functions; - w.types = 0; + w.types = types; return luax_register_module(L, w); } diff --git a/src/modules/mouse/wrap_Mouse.h b/src/modules/mouse/wrap_Mouse.h index 7310e4b8b..5e580c2a8 100644 --- a/src/modules/mouse/wrap_Mouse.h +++ b/src/modules/mouse/wrap_Mouse.h @@ -22,13 +22,17 @@ #define LOVE_MOUSE_WRAP_MOUSE_H // LOVE -#include "Mouse.h" +#include "common/runtime.h" +#include "common/config.h" namespace love { namespace mouse { +int w_newCursor(lua_State *L); +int w_setCursor(lua_State *L); +int w_getCursor(lua_State *L); int w_getX(lua_State *L); int w_getY(lua_State *L); int w_getPosition(lua_State *L); diff --git a/src/modules/system/System.cpp b/src/modules/system/System.cpp new file mode 100644 index 000000000..7760f996d --- /dev/null +++ b/src/modules/system/System.cpp @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#include "System.h" + +namespace love +{ +namespace system +{ + +std::string System::getOS() const +{ +#ifdef LOVE_MACOSX + return "OS X"; +#elif LOVE_WINDOWS + return "Windows"; +#elif LOVE_LINUX + return "Linux"; +#else + return "Unknown"; +#endif +} + +bool System::getConstant(const char *in, System::PowerState &out) +{ + return powerStates.find(in, out); +} + +bool System::getConstant(System::PowerState in, const char *&out) +{ + return powerStates.find(in, out); +} + +StringMap::Entry System::powerEntries[] = +{ + {"unknown", System::POWER_UNKNOWN}, + {"battery", System::POWER_BATTERY}, + {"nobattery", System::POWER_NO_BATTERY}, + {"charging", System::POWER_CHARGING}, + {"charged", System::POWER_CHARGED}, +}; + +StringMap System::powerStates(System::powerEntries, sizeof(System::powerEntries)); + +} // system +} // love diff --git a/src/modules/system/System.h b/src/modules/system/System.h new file mode 100644 index 000000000..b394a914f --- /dev/null +++ b/src/modules/system/System.h @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#ifndef LOVE_SYSTEM_H +#define LOVE_SYSTEM_H + +// LOVE +#include "common/config.h" +#include "common/Module.h" +#include "common/StringMap.h" + +// stdlib +#include + +namespace love +{ +namespace system +{ + +class System : public Module +{ +public: + + enum PowerState + { + POWER_UNKNOWN, + POWER_BATTERY, + POWER_NO_BATTERY, + POWER_CHARGING, + POWER_CHARGED, + POWER_MAX_ENUM + }; + + virtual ~System() {} + + /** + * Gets the current operating system. + **/ + std::string getOS() const; + + /** + * Gets the number of reported CPU cores on the current system. + * Does not account for technologies such as Hyperthreading: a 4-core + * Hyperthreading-enabled Intel CPU will report 8, instead of 4. + **/ + virtual int getProcessorCount() const = 0; + + /** + * Replaces the contents of the system's text clipboard with a string. + * @param text The clipboard text to set. + **/ + virtual void setClipboardText(const std::string &text) const = 0; + + /** + * Gets the contents of the system's text clipboard. + **/ + virtual std::string getClipboardText() const = 0; + + /** + * Gets information about the system's power supply. + * + * @param[out] seconds Time in seconds of battery life left. + * -1 if a value can't be determined. + * @param[out] percent The percentage of battery life left (0-100.) + * -1 if a value can't be determined. + * + * @return The current state of the battery. + **/ + virtual PowerState getPowerInfo(int &seconds, int &percent) const = 0; + + static bool getConstant(const char *in, PowerState &out); + static bool getConstant(PowerState in, const char *&out); + +private: + + static StringMap::Entry powerEntries[]; + static StringMap powerStates; + +}; // System + +} // system +} // love + +#endif // LOVE_SYSTEM_H diff --git a/src/modules/system/sdl/System.cpp b/src/modules/system/sdl/System.cpp new file mode 100644 index 000000000..39b180968 --- /dev/null +++ b/src/modules/system/sdl/System.cpp @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +// LOVE +#include "System.h" + +// SDL +#include +#include + +namespace love +{ +namespace system +{ +namespace sdl +{ + +System::System() +{ +} + +const char *System::getName() const +{ + return "love.system.sdl"; +} + +int System::getProcessorCount() const +{ + return SDL_GetCPUCount(); +} + +void System::setClipboardText(const std::string &text) const +{ + SDL_SetClipboardText(text.c_str()); +} + +std::string System::getClipboardText() const +{ + std::string text(""); + + char *ctext = SDL_GetClipboardText(); + if (ctext) + { + text = std::string(ctext); + SDL_free(ctext); + } + + return text; +} + +love::system::System::PowerState System::getPowerInfo(int &seconds, int &percent) const +{ + SDL_PowerState sdlstate = SDL_GetPowerInfo(&seconds, &percent); + + PowerState state = POWER_UNKNOWN; + powerStates.find(sdlstate, state); + + return state; +} + +EnumMap::Entry System::powerEntries[] = +{ + {System::POWER_UNKNOWN, SDL_POWERSTATE_UNKNOWN}, + {System::POWER_BATTERY, SDL_POWERSTATE_ON_BATTERY}, + {System::POWER_NO_BATTERY, SDL_POWERSTATE_NO_BATTERY}, + {System::POWER_CHARGING, SDL_POWERSTATE_CHARGING}, + {System::POWER_CHARGED, SDL_POWERSTATE_CHARGED}, +}; + +EnumMap System::powerStates(System::powerEntries, sizeof(System::powerEntries)); + +} // sdl +} // system +} // love diff --git a/src/modules/system/sdl/System.h b/src/modules/system/sdl/System.h new file mode 100644 index 000000000..5d2b35569 --- /dev/null +++ b/src/modules/system/sdl/System.h @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#ifndef LOVE_SYSTEM_SDL_SYSTEM_H +#define LOVE_SYSTEM_SDL_SYSTEM_H + +// LOVE +#include "system/System.h" +#include "common/EnumMap.h" + +// SDL +#include + +namespace love +{ +namespace system +{ +namespace sdl +{ + +class System : public love::system::System +{ +public: + + System(); + virtual ~System() {} + + // Implements Module. + const char *getName() const; + + int getProcessorCount() const; + + void setClipboardText(const std::string &text) const; + std::string getClipboardText() const; + + PowerState getPowerInfo(int &seconds, int &percent) const; + +private: + + static EnumMap::Entry powerEntries[]; + static EnumMap powerStates; + +}; // System + +} // sdl +} // system +} // love + +#endif // LOVE_SYSTEM_SDL_SYSTEM_H diff --git a/src/modules/system/wrap_System.cpp b/src/modules/system/wrap_System.cpp new file mode 100644 index 000000000..3048a94dc --- /dev/null +++ b/src/modules/system/wrap_System.cpp @@ -0,0 +1,112 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +// LOVE +#include "wrap_System.h" +#include "sdl/System.h" + +namespace love +{ +namespace system +{ + +static System *instance = 0; + +int w_getOS(lua_State *L) +{ + luax_pushstring(L, instance->getOS()); + return 1; +} + +int w_getProcessorCount(lua_State *L) +{ + lua_pushinteger(L, instance->getProcessorCount()); + return 1; +} + +int w_setClipboardText(lua_State *L) +{ + const char *text = luaL_checkstring(L, 1); + instance->setClipboardText(text); + return 0; +} + +int w_getClipboardText(lua_State *L) +{ + luax_pushstring(L, instance->getClipboardText()); + return 1; +} + +int w_getPowerInfo(lua_State *L) +{ + int seconds = -1, percent = -1; + const char *str; + + System::PowerState state = instance->getPowerInfo(seconds, percent); + + if (!System::getConstant(state, str)) + str = "unknown"; + + lua_pushstring(L, str); + + if (percent >= 0) + lua_pushinteger(L, percent); + else + lua_pushnil(L); + + if (seconds >= 0) + lua_pushinteger(L, seconds); + else + lua_pushnil(L); + + return 3; +} + +static const luaL_Reg functions[] = +{ + { "getOS", w_getOS }, + { "getProcessorCount", w_getProcessorCount }, + { "setClipboardText", w_setClipboardText }, + { "getClipboardText", w_getClipboardText }, + { "getPowerInfo", w_getPowerInfo }, + { 0, 0 } +}; + +extern "C" int luaopen_love_system(lua_State *L) +{ + if (instance == 0) + { + instance = new love::system::sdl::System(); + } + else + instance->retain(); + + WrappedModule w; + w.module = instance; + w.name = "system"; + w.flags = MODULE_T; + w.functions = functions; + w.types = 0; + + return luax_register_module(L, w); +} + +} // system +} // love \ No newline at end of file diff --git a/src/modules/system/wrap_System.h b/src/modules/system/wrap_System.h new file mode 100644 index 000000000..1bf7dc868 --- /dev/null +++ b/src/modules/system/wrap_System.h @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#ifndef LOVE_WRAP_SYSTEM_H +#define LOVE_WRAP_SYSTEM_H + +// LOVE +#include "System.h" +#include "common/runtime.h" + +namespace love +{ +namespace system +{ + +int w_getOS(lua_State *L); +int w_getProcessorCount(lua_State *L); +int w_setClipboardText(lua_State *L); +int w_getClipboardText(lua_State *L); +int w_getPowerInfo(lua_State *L); +extern "C" LOVE_EXPORT int luaopen_love_system(lua_State *L); + +} // system +} // love + +#endif // LOVE_WRAP_SYSTEM_H diff --git a/src/modules/thread/ThreadModule.cpp b/src/modules/thread/ThreadModule.cpp index 412c5bfa5..b70c931bb 100644 --- a/src/modules/thread/ThreadModule.cpp +++ b/src/modules/thread/ThreadModule.cpp @@ -24,10 +24,6 @@ namespace love { namespace thread { -const char *ThreadModule::getName() const -{ - return "love.thread.sdl"; -} LuaThread *ThreadModule::newThread(const std::string &name, love::Data *data) { @@ -44,5 +40,11 @@ Channel *ThreadModule::getChannel(const std::string &name) { return Channel::getChannel(name); } + +const char *ThreadModule::getName() const +{ + return "love.thread.sdl"; +} + } // thread } // love diff --git a/src/modules/thread/ThreadModule.h b/src/modules/thread/ThreadModule.h index 937774b7a..a004af96e 100644 --- a/src/modules/thread/ThreadModule.h +++ b/src/modules/thread/ThreadModule.h @@ -25,12 +25,14 @@ #include // LOVE -#include -#include -#include -#include -#include -#include +#include "common/Data.h" +#include "common/Module.h" +#include "common/StringMap.h" + +#include "Thread.h" +#include "Channel.h" +#include "LuaThread.h" +#include "threads.h" namespace love { @@ -39,13 +41,17 @@ namespace thread class ThreadModule : public love::Module { public: - virtual ~ThreadModule() {} - LuaThread *newThread(const std::string &name, love::Data *data); - Channel *newChannel(); - Channel *getChannel(const std::string &name); - const char *getName() const; + virtual ~ThreadModule() {} + virtual LuaThread *newThread(const std::string &name, love::Data *data); + virtual Channel *newChannel(); + virtual Channel *getChannel(const std::string &name); + + // Implements Module. + virtual const char *getName() const; + }; // ThreadModule + } // thread } // love diff --git a/src/modules/thread/sdl/Thread.cpp b/src/modules/thread/sdl/Thread.cpp index 2438ab8c6..f5e4c5339 100644 --- a/src/modules/thread/sdl/Thread.cpp +++ b/src/modules/thread/sdl/Thread.cpp @@ -51,7 +51,7 @@ bool Thread::start() return false; if (thread) // Clean old handle up SDL_WaitThread(thread, 0); - thread = SDL_CreateThread(thread_runner, this); + thread = SDL_CreateThread(thread_runner, NULL, this); running = (thread != 0); return running; } diff --git a/src/modules/thread/sdl/threads.cpp b/src/modules/thread/sdl/threads.cpp index e5881f5a9..068347e09 100644 --- a/src/modules/thread/sdl/threads.cpp +++ b/src/modules/thread/sdl/threads.cpp @@ -39,12 +39,12 @@ Mutex::~Mutex() void Mutex::lock() { - SDL_mutexP(mutex); + SDL_LockMutex(mutex); } void Mutex::unlock() { - SDL_mutexV(mutex); + SDL_UnlockMutex(mutex); } Conditional::Conditional() diff --git a/src/modules/thread/wrap_ThreadModule.cpp b/src/modules/thread/wrap_ThreadModule.cpp index 4e6173ba6..9d6d6306b 100644 --- a/src/modules/thread/wrap_ThreadModule.cpp +++ b/src/modules/thread/wrap_ThreadModule.cpp @@ -18,16 +18,20 @@ * 3. This notice may not be removed or altered from any source distribution. **/ +// LOVE #include "wrap_ThreadModule.h" #include "wrap_LuaThread.h" #include "wrap_Channel.h" -#include -#include +#include "ThreadModule.h" + +#include "filesystem/File.h" +#include "filesystem/FileData.h" namespace love { namespace thread { + static ThreadModule *instance = 0; int w_newThread(lua_State *L) @@ -89,7 +93,7 @@ extern "C" int luaopen_love_thread(lua_State *L) { try { - instance = new ThreadModule(); + instance = new love::thread::ThreadModule(); } catch (Exception & e) { @@ -108,5 +112,6 @@ extern "C" int luaopen_love_thread(lua_State *L) return luax_register_module(L, w); } -} -} + +} // thread +} // love diff --git a/src/modules/thread/wrap_ThreadModule.h b/src/modules/thread/wrap_ThreadModule.h index 056015659..0b9fa2a09 100644 --- a/src/modules/thread/wrap_ThreadModule.h +++ b/src/modules/thread/wrap_ThreadModule.h @@ -22,7 +22,8 @@ #define LOVE_THREAD_WRAP_THREADMODULE_H // LOVE -#include "ThreadModule.h" +#include "common/config.h" +#include "common/runtime.h" namespace love { diff --git a/src/modules/window/Window.cpp b/src/modules/window/Window.cpp index aa6c8c609..0afe8bee2 100644 --- a/src/modules/window/Window.cpp +++ b/src/modules/window/Window.cpp @@ -40,13 +40,35 @@ void Window::swapBuffers() WindowFlags::WindowFlags() : fullscreen(false) + , fstype(Window::FULLSCREEN_TYPE_NORMAL) , vsync(true) , fsaa(0) , resizable(false) + , minwidth(100) + , minheight(100) , borderless(false) , centered(true) + , display(0) { } +bool Window::getConstant(const char *in, Window::FullscreenType &out) +{ + return fullscreenTypes.find(in, out); +} + +bool Window::getConstant(Window::FullscreenType in, const char *&out) +{ + return fullscreenTypes.find(in, out); +} + +StringMap::Entry Window::fullscreenTypeEntries[] = +{ + {"normal", Window::FULLSCREEN_TYPE_NORMAL}, + {"desktop", Window::FULLSCREEN_TYPE_DESKTOP}, +}; + +StringMap Window::fullscreenTypes(Window::fullscreenTypeEntries, sizeof(Window::fullscreenTypeEntries)); + } // window } // love diff --git a/src/modules/window/Window.h b/src/modules/window/Window.h index 8148aeb72..5f575687e 100644 --- a/src/modules/window/Window.h +++ b/src/modules/window/Window.h @@ -21,32 +21,35 @@ #ifndef LOVE_WINDOW_WINDOW_H #define LOVE_WINDOW_WINDOW_H -// STL -#include - // LOVE #include "common/Module.h" +#include "common/StringMap.h" #include "image/ImageData.h" +// C++ +#include +#include + namespace love { namespace window { -struct WindowFlags -{ - WindowFlags(); - bool fullscreen; // = false - bool vsync; // = true - int fsaa; // = 0 - bool resizable; // = false - bool borderless; // = false - bool centered; // = true -}; // WindowFlags +// Forward-declared so it can be used in the class methods. We can't define the +// whole thing here because it uses the Window::Type enum. +struct WindowFlags; class Window : public Module { public: + + enum FullscreenType + { + FULLSCREEN_TYPE_NORMAL, + FULLSCREEN_TYPE_DESKTOP, + FULLSCREEN_TYPE_MAX_ENUM + }; + struct WindowSize { int width; @@ -56,18 +59,27 @@ public: virtual ~Window(); virtual bool setWindow(int width = 800, int height = 600, WindowFlags *flags = 0) = 0; - virtual void getWindow(int &width, int &height, WindowFlags &flags) const = 0; + virtual void getWindow(int &width, int &height, WindowFlags &flags) = 0; - virtual bool checkWindowSize(int width, int height, bool fullscreen) const = 0; - virtual WindowSize *getFullscreenSizes(int &n) const = 0; + virtual bool setFullscreen(bool fullscreen, FullscreenType fstype) = 0; + virtual bool setFullscreen(bool fullscreen) = 0; + + virtual bool onWindowResize(int width, int height) = 0; + + virtual int getDisplayCount() const = 0; + + virtual bool checkWindowSize(int width, int height, bool fullscreen, int displayindex) const = 0; + virtual std::vector getFullscreenSizes(int displayindex) const = 0; virtual int getWidth() const = 0; virtual int getHeight() const = 0; + virtual void getDesktopDimensions(int displayindex, int &width, int &height) const = 0; + virtual bool isCreated() const = 0; virtual void setWindowTitle(const std::string &title) = 0; - virtual std::string getWindowTitle() const = 0; + virtual const std::string &getWindowTitle() const = 0; virtual bool setIcon(love::image::ImageData *imgd) = 0; virtual love::image::ImageData *getIcon() = 0; @@ -83,13 +95,44 @@ public: virtual void setMouseVisible(bool visible) = 0; virtual bool getMouseVisible() const = 0; + virtual void setMouseGrab(bool grab) = 0; + virtual bool isMouseGrabbed() const = 0; + + virtual const void *getHandle() const = 0; + + //virtual static Window *createSingleton() = 0; //virtual static Window *getSingleton() = 0; - // No virtual statics, of course, but you are supposed to implement this static. + // No virtual statics, of course, but you are supposed to implement these statics. + + static bool getConstant(const char *in, FullscreenType &out); + static bool getConstant(FullscreenType in, const char *&out); protected: + static Window *singleton; +private: + + static StringMap::Entry fullscreenTypeEntries[]; + static StringMap fullscreenTypes; + }; // Window + +struct WindowFlags +{ + WindowFlags(); + bool fullscreen; // = false + Window::FullscreenType fstype; // = FULLSCREEN_TYPE_NORMAL + bool vsync; // = true + int fsaa; // = 0 + bool resizable; // = false + int minwidth; // = 100 + int minheight; // = 100 + bool borderless; // = false + bool centered; // = true + int display; // = 0 +}; // WindowFlags + } // window } // love diff --git a/src/modules/window/sdl/Window.cpp b/src/modules/window/sdl/Window.cpp index 99189bf45..f8f94d160 100644 --- a/src/modules/window/sdl/Window.cpp +++ b/src/modules/window/sdl/Window.cpp @@ -23,11 +23,10 @@ #include "graphics/Graphics.h" #include "Window.h" -// SDL -#include - -// STL +// C++ #include +#include +#include namespace love { @@ -39,15 +38,30 @@ namespace sdl Window::Window() : windowTitle("") , created(false) + , mouseGrabbed(false) + , window(0) + , context(0) { +#ifdef LOVE_MACOSX + // SDL 2 minimizes the window at weird times on OSX if this isn't disabled. + // TODO: do Linux and/or Windows need this as well (multi-monitor)? + SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); +#endif + if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) - throw love::Exception(SDL_GetError()); + throw love::Exception("%s", SDL_GetError()); } Window::~Window() { - if (currentMode.icon) - currentMode.icon->release(); + if (curMode.icon) + curMode.icon->release(); + + if (window) + SDL_DestroyWindow(window); + + if (context) + SDL_GL_DeleteContext(context); SDL_QuitSubSystem(SDL_INIT_VIDEO); } @@ -66,109 +80,181 @@ bool Window::setWindow(int width, int height, WindowFlags *flags) if (gfx) gfx->unSetMode(); - bool fullscreen = false; - bool vsync = true; - int fsaa = 0; - bool resizable = false; - bool borderless = false; - bool centered = true; + WindowFlags f; if (flags) + f = *flags; + + f.minwidth = std::max(f.minwidth, 0); + f.minheight = std::max(f.minheight, 0); + + f.display = std::min(std::max(f.display, 0), getDisplayCount()); + + // Use the desktop resolution if a width or height of 0 is specified. + if (width == 0 || height == 0) { - fullscreen = flags->fullscreen; - vsync = flags->vsync; - fsaa = flags->fsaa; - resizable = flags->resizable; - borderless = flags->borderless; - centered = flags->centered; + SDL_DisplayMode mode = {}; + SDL_GetDesktopDisplayMode(f.display, &mode); + width = mode.w; + height = mode.h; } - bool mouseVisible = getMouseVisible(); - int keyrepeatDelay, keyrepeatInterval; - SDL_GetKeyRepeat(&keyrepeatDelay, &keyrepeatInterval); + Uint32 sdlflags = SDL_WINDOW_OPENGL; - // We need to restart the subsystem for two reasons: - // 1) Special case for fullscreen -> windowed. Windows XP did not - // work well with "normal" display mode change in this case. - // The application window does leave fullscreen, but the desktop - // resolution does not revert to the correct one. Restarting the - // SDL video subsystem does the trick, though. - // 2) Restart the event system (for whatever reason the event system - // started and stopped with SDL_INIT_VIDEO, see: - // http://sdl.beuc.net/sdl.wiki/Introduction_to_Events) - // because the mouse position will not be able to exceed - // the previous' video mode window size (i.e. alway - // love.mouse.getX() < 800 when switching from 800x600 to a - // higher resolution) - SDL_QuitSubSystem(SDL_INIT_VIDEO); - - if (centered) // Window should be centered. - SDL_putenv(const_cast("SDL_VIDEO_CENTERED=center")); - else - SDL_putenv(const_cast("SDL_VIDEO_CENTERED=")); - - if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) + if (f.fullscreen) { - std::cout << "Could not init SDL_VIDEO: " << SDL_GetError() << std::endl; + switch (f.fstype) + { + case FULLSCREEN_TYPE_NORMAL: + default: + sdlflags |= SDL_WINDOW_FULLSCREEN; + break; + case FULLSCREEN_TYPE_DESKTOP: + sdlflags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + break; + } + } + + if (f.resizable) + sdlflags |= SDL_WINDOW_RESIZABLE; + + if (f.borderless) + sdlflags |= SDL_WINDOW_BORDERLESS; + + // Destroy and recreate the window if the dimensions or flags have changed. + if (window) + { + int curdisplay = SDL_GetWindowDisplayIndex(window); + Uint32 wflags = SDL_GetWindowFlags(window); + wflags &= (SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_RESIZABLE | SDL_WINDOW_BORDERLESS); + + if (sdlflags != wflags || width != curMode.width || height != curMode.height + || f.display != curdisplay || f.fsaa != curMode.flags.fsaa) + { + SDL_DestroyWindow(window); + window = 0; + + // The old window may have generated pending events which are no + // longer relevant. Destroy them all! + SDL_FlushEvent(SDL_WINDOWEVENT); + } + } + + int centeredpos = SDL_WINDOWPOS_CENTERED_DISPLAY(f.display); + int uncenteredpos = SDL_WINDOWPOS_UNDEFINED_DISPLAY(f.display); + + if (!window) + { + // In Windows and Linux, some GL attributes are set on window creation. + setWindowGLAttributes(f.fsaa); + + const char *title = windowTitle.c_str(); + int pos = f.centered ? centeredpos : uncenteredpos; + + window = SDL_CreateWindow(title, pos, pos, width, height, sdlflags); + + if (!window && f.fsaa > 0) + { + // FSAA might have caused the failure, disable it and try again. + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); + + window = SDL_CreateWindow(title, pos, pos, width, height, sdlflags); + f.fsaa = 0; + } + + // Make sure the window keeps any previously set icon. + if (window && curMode.icon) + setIcon(curMode.icon); + } + + if (!window) + { + std::cerr << "Could not set video mode: " << SDL_GetError() << std::endl; return false; } - // Set caption. - setWindowTitle(windowTitle); - setMouseVisible(mouseVisible); - setIcon(currentMode.icon); - SDL_EnableKeyRepeat(keyrepeatDelay, keyrepeatInterval); + // Enforce minimum window dimensions. + SDL_SetWindowMinimumSize(window, f.minwidth, f.minheight); - // Set GL attributes - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, (vsync ? 1 : 0)); - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1); + if (f.centered && !f.fullscreen) + SDL_SetWindowPosition(window, centeredpos, centeredpos); - // FSAA - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (fsaa > 0) ? 1 : 0); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (fsaa > 0) ? fsaa : 0); + SDL_RaiseWindow(window); - Uint32 sdlflags = SDL_OPENGL; - // Flags - if (fullscreen) - sdlflags |= SDL_FULLSCREEN; - if (resizable) - sdlflags |= SDL_RESIZABLE; - if (borderless) - sdlflags |= SDL_NOFRAME; - - // Have SDL set the video mode. - SDL_Surface *surface; - if ((surface = SDL_SetVideoMode(width, height, 32, sdlflags)) == 0) - { - bool failed = true; - if (fsaa > 0) - { - // FSAA might have caused the failure, disable it and try again - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); - failed = (surface = SDL_SetVideoMode(width, height, 32, sdlflags)) == 0; - } - if (failed) - { - std::cerr << "Could not set video mode: " << SDL_GetError() << std::endl; - return false; - } - } + if (!setContext(f.fsaa, f.vsync)) + return false; created = true; - const SDL_VideoInfo *videoinfo = SDL_GetVideoInfo(); - width = videoinfo->current_w; - height = videoinfo->current_h; + updateWindowFlags(f); + if (gfx) + gfx->setMode(curMode.width, curMode.height); + + // Make sure the mouse keeps its previous grab setting. + setMouseGrab(mouseGrabbed); + + return true; +} + +bool Window::onWindowResize(int width, int height) +{ + if (!window) + return false; + + curMode.width = width; + curMode.height = height; + + return true; +} + +bool Window::setContext(int fsaa, bool vsync) +{ + // We need to recreate the context if FSAA changes, + // or if the existing context has been invalidated. + if (context && (fsaa != curMode.flags.fsaa || SDL_GL_MakeCurrent(window, context) < 0)) + { + SDL_GL_DeleteContext(context); + context = 0; + } + + // Create a new OpenGL context. + if (!context) + { + setWindowGLAttributes(fsaa); + + context = SDL_GL_CreateContext(window); + + if (!context && fsaa > 0) + { + // FSAA might have caused the failure, disable it and try again. + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); + context = SDL_GL_CreateContext(window); + } + } + + if (!context) + { + std::cerr << "Could not set video mode: " << SDL_GetError() << std::endl; + return false; + } + + // Set vertical synchronization. + if (vsync) + { + // Prefer EXT_swap_control_tear (late swaps happen immediately), + // otherwise fall back to regular vsync. + if (SDL_GL_SetSwapInterval(-1) < 0 || SDL_GL_GetSwapInterval() != -1) + SDL_GL_SetSwapInterval(1); + } + else + SDL_GL_SetSwapInterval(0); + + // Verify FSAA setting. int buffers; int samples; - SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &buffers); SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &samples); @@ -179,65 +265,173 @@ bool Window::setWindow(int width, int height, WindowFlags *flags) fsaa = (buffers > 0) ? samples : 0; } - // Get the actual vsync status - int real_vsync; - SDL_GL_GetAttribute(SDL_GL_SWAP_CONTROL, &real_vsync); - - // Set the new display mode as the current display mode. - currentMode.width = width; - currentMode.height = height; - currentMode.flags.fsaa = fsaa; - currentMode.flags.fullscreen = fullscreen; - currentMode.flags.vsync = (real_vsync != 0); - currentMode.flags.resizable = ((surface->flags & SDL_RESIZABLE) != 0); - currentMode.flags.borderless = ((surface->flags & SDL_NOFRAME) != 0); - currentMode.flags.centered = centered; - - if (gfx) - gfx->setMode(width, height); + curMode.flags.fsaa = fsaa; + curMode.flags.vsync = SDL_GL_GetSwapInterval() != 0; return true; } -void Window::getWindow(int &width, int &height, WindowFlags &flags) const +void Window::setWindowGLAttributes(int fsaa) const { - width = currentMode.width; - height = currentMode.height; - flags = currentMode.flags; + // Set GL window attributes. + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1); + + // FSAA. + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (fsaa > 0) ? 1 : 0); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (fsaa > 0) ? fsaa : 0); } -bool Window::checkWindowSize(int width, int height, bool fullscreen) const +void Window::updateWindowFlags(const WindowFlags &newflags) { - Uint32 sdlflags = fullscreen ? (SDL_OPENGL | SDL_FULLSCREEN) : SDL_OPENGL; + Uint32 wflags = SDL_GetWindowFlags(window); - // Check if mode is supported - int bpp = SDL_VideoModeOK(width, height, 32, sdlflags); + // Set the new display mode as the current display mode. + SDL_GetWindowSize(window, &curMode.width, &curMode.height); - return (bpp >= 16); + if ((wflags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) + { + curMode.flags.fullscreen = true; + curMode.flags.fstype = FULLSCREEN_TYPE_DESKTOP; + } + else if ((wflags & SDL_WINDOW_FULLSCREEN) == SDL_WINDOW_FULLSCREEN) + { + curMode.flags.fullscreen = true; + curMode.flags.fstype = FULLSCREEN_TYPE_NORMAL; + } + else + { + curMode.flags.fullscreen = false; + curMode.flags.fstype = newflags.fstype; + } + + // The min width/height is set to 0 internally in SDL when in fullscreen. + if (curMode.flags.fullscreen) + { + curMode.flags.minwidth = newflags.minwidth; + curMode.flags.minheight = newflags.minheight; + } + else + SDL_GetWindowMinimumSize(window, &curMode.flags.minwidth, &curMode.flags.minheight); + + curMode.flags.resizable = (wflags & SDL_WINDOW_RESIZABLE) != 0; + curMode.flags.borderless = (wflags & SDL_WINDOW_BORDERLESS) != 0; + curMode.flags.centered = newflags.centered; + curMode.flags.display = std::max(SDL_GetWindowDisplayIndex(window), 0); +} + +void Window::getWindow(int &width, int &height, WindowFlags &flags) +{ + // Window position may be different from creation - update display index. + if (window) + curMode.flags.display = std::max(SDL_GetWindowDisplayIndex(window), 0); + + width = curMode.width; + height = curMode.height; + flags = curMode.flags; +} + +bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype) +{ + if (!window) + return false; + + WindowFlags newflags = curMode.flags; + newflags.fullscreen = fullscreen; + newflags.fstype = fstype; + + Uint32 sdlflags = 0; + + if (fullscreen) + { + if (fstype == FULLSCREEN_TYPE_DESKTOP) + sdlflags = SDL_WINDOW_FULLSCREEN_DESKTOP; + else + { + sdlflags = SDL_WINDOW_FULLSCREEN; + + SDL_DisplayMode mode = {}; + mode.w = curMode.width; + mode.h = curMode.height; + + SDL_GetClosestDisplayMode(SDL_GetWindowDisplayIndex(window), &mode, &mode); + SDL_SetWindowDisplayMode(window, &mode); + } + } + + if (SDL_SetWindowFullscreen(window, sdlflags) == 0) + { + SDL_GL_MakeCurrent(window, context); + updateWindowFlags(newflags); + return true; + } + + return false; +} + +bool Window::setFullscreen(bool fullscreen) +{ + return setFullscreen(fullscreen, curMode.flags.fstype); +} + +int Window::getDisplayCount() const +{ + return SDL_GetNumVideoDisplays(); +} + +bool Window::checkWindowSize(int width, int height, bool fullscreen, int displayindex) const +{ + if (fullscreen) + { + SDL_DisplayMode mode = {}, closest = {}; + mode.w = width; + mode.h = height; + SDL_GetClosestDisplayMode(displayindex, &mode, &closest); + + return (mode.w == closest.w && mode.h == closest.h); + } + else + { + SDL_DisplayMode mode = {}; + SDL_GetDesktopDisplayMode(displayindex, &mode); + + return (width <= mode.w && height <= mode.h); + } } typedef Window::WindowSize WindowSize; -WindowSize *Window::getFullscreenSizes(int &n) const +std::vector Window::getFullscreenSizes(int displayindex) const { - SDL_Rect **modes = SDL_ListModes(0, SDL_OPENGL | SDL_FULLSCREEN); + std::vector sizes; - if (modes == (SDL_Rect **)0 || modes == (SDL_Rect **)-1) + SDL_DisplayMode mode = {}; + std::vector::const_iterator it; + for (int i = 0; i < SDL_GetNumDisplayModes(displayindex); i++) { - n = 0; - return NULL; - } + SDL_GetDisplayMode(displayindex, i, &mode); - n = 0; - for (int i = 0; modes[i]; i++) - n++; + // SDL2's display mode list has multiple entries for modes of the same + // size with different bits per pixel, so we need to filter those out. + bool alreadyhassize = false; + for (it = sizes.begin(); it != sizes.end(); ++it) + { + if (it->width == mode.w && it->height == mode.h) + { + alreadyhassize = true; + break; + } + } - WindowSize *sizes = new WindowSize[n]; - - for (int i = 0; i < n; i++) - { - WindowSize w = {modes[i]->w, modes[i]->h}; - sizes[i] = w; + if (!alreadyhassize) + { + WindowSize w = {mode.w, mode.h}; + sizes.push_back(w); + } } return sizes; @@ -245,12 +439,28 @@ WindowSize *Window::getFullscreenSizes(int &n) const int Window::getWidth() const { - return currentMode.width; + return curMode.width; } int Window::getHeight() const { - return currentMode.height; + return curMode.height; +} + +void Window::getDesktopDimensions(int displayindex, int &width, int &height) const +{ + if (displayindex >= 0 && displayindex < getDisplayCount()) + { + SDL_DisplayMode mode = {}; + SDL_GetDesktopDisplayMode(displayindex, &mode); + width = mode.w; + height = mode.h; + } + else + { + width = 0; + height = 0; + } } bool Window::isCreated() const @@ -261,14 +471,13 @@ bool Window::isCreated() const void Window::setWindowTitle(const std::string &title) { windowTitle = title; - SDL_WM_SetCaption(windowTitle.c_str(), 0); + + if (window) + SDL_SetWindowTitle(window, title.c_str()); } -std::string Window::getWindowTitle() const +const std::string &Window::getWindowTitle() const { - // not a reference - // because we want this untouched - // const std::string& might be an option return windowTitle; } @@ -277,6 +486,14 @@ bool Window::setIcon(love::image::ImageData *imgd) if (!imgd) return false; + imgd->retain(); + if (curMode.icon) + curMode.icon->release(); + curMode.icon = imgd; + + if (!window) + return false; + Uint32 rmask, gmask, bmask, amask; #ifdef LOVE_BIG_ENDIAN rmask = 0xFF000000; @@ -294,51 +511,46 @@ bool Window::setIcon(love::image::ImageData *imgd) int h = imgd->getHeight(); int pitch = imgd->getWidth() * 4; - SDL_Surface *icon = 0; + SDL_Surface *sdlicon = 0; { // We don't want another thread modifying the ImageData mid-copy. love::thread::Lock lock(imgd->getMutex()); - icon = SDL_CreateRGBSurfaceFrom(imgd->getData(), w, h, 32, pitch, rmask, gmask, bmask, amask); + sdlicon = SDL_CreateRGBSurfaceFrom(imgd->getData(), w, h, 32, pitch, rmask, gmask, bmask, amask); } - if (!icon) + if (!sdlicon) return false; - SDL_WM_SetIcon(icon, NULL); - SDL_FreeSurface(icon); - - imgd->retain(); - if (currentMode.icon) - currentMode.icon->release(); - currentMode.icon = imgd; + SDL_SetWindowIcon(window, sdlicon); + SDL_FreeSurface(sdlicon); return true; } love::image::ImageData *Window::getIcon() { - return currentMode.icon; + return curMode.icon; } void Window::swapBuffers() { - SDL_GL_SwapBuffers(); + SDL_GL_SwapWindow(window); } bool Window::hasFocus() const { - return (SDL_GetAppState() & SDL_APPINPUTFOCUS) != 0; + return (window && SDL_GetKeyboardFocus() == window); } bool Window::hasMouseFocus() const { - return (SDL_GetAppState() & SDL_APPMOUSEFOCUS) != 0; + return (window && SDL_GetMouseFocus() == window); } bool Window::isVisible() const { - return (SDL_GetAppState() & SDL_APPACTIVE) != 0; + return window && (SDL_GetWindowFlags(window) & SDL_WINDOW_SHOWN) != 0; } void Window::setMouseVisible(bool visible) @@ -348,10 +560,30 @@ void Window::setMouseVisible(bool visible) bool Window::getMouseVisible() const { - return (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE) ? true : false; + return (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE); } -love::window::Window *Window::getSingleton() +void Window::setMouseGrab(bool grab) +{ + mouseGrabbed = grab; + if (window) + SDL_SetWindowGrab(window, (SDL_bool) grab); +} + +bool Window::isMouseGrabbed() const +{ + if (window) + return (bool) SDL_GetWindowGrab(window); + else + return mouseGrabbed; +} + +const void *Window::getHandle() const +{ + return window; +} + +love::window::Window *Window::createSingleton() { if (!singleton) singleton = new Window(); @@ -361,6 +593,11 @@ love::window::Window *Window::getSingleton() return singleton; } +love::window::Window *Window::getSingleton() +{ + return singleton; +} + const char *Window::getName() const { return "love.window.sdl"; diff --git a/src/modules/window/sdl/Window.h b/src/modules/window/sdl/Window.h index 8048a63ec..02a5b8ad2 100644 --- a/src/modules/window/sdl/Window.h +++ b/src/modules/window/sdl/Window.h @@ -24,6 +24,9 @@ // LOVE #include "window/Window.h" +// SDL +#include + namespace love { namespace window @@ -39,18 +42,27 @@ public: ~Window(); bool setWindow(int width = 800, int height = 600, WindowFlags *flags = 0); - void getWindow(int &width, int &height, WindowFlags &flags) const; + void getWindow(int &width, int &height, WindowFlags &flags); - bool checkWindowSize(int width, int height, bool fullscreen) const; - WindowSize *getFullscreenSizes(int &n) const; + bool setFullscreen(bool fullscreen, FullscreenType fstype); + bool setFullscreen(bool fullscreen); + + bool onWindowResize(int width, int height); + + int getDisplayCount() const; + + bool checkWindowSize(int width, int height, bool fullscreen, int displayindex) const; + std::vector getFullscreenSizes(int displayindex) const; int getWidth() const; int getHeight() const; + void getDesktopDimensions(int displayindex, int &width, int &height) const; + bool isCreated() const; void setWindowTitle(const std::string &title); - std::string getWindowTitle() const; + const std::string &getWindowTitle() const; bool setIcon(love::image::ImageData *imgd); love::image::ImageData *getIcon(); @@ -65,12 +77,24 @@ public: void setMouseVisible(bool visible); bool getMouseVisible() const; + void setMouseGrab(bool grab); + bool isMouseGrabbed() const; + + const void *getHandle() const; + + static love::window::Window *createSingleton(); static love::window::Window *getSingleton(); const char *getName() const; private: + bool setContext(int fsaa, bool vsync); + void setWindowGLAttributes(int fsaa) const; + + // Update the window flags based on the window's actual state. + void updateWindowFlags(const WindowFlags &newflags); + std::string windowTitle; struct _currentMode @@ -82,10 +106,15 @@ private: WindowFlags flags; love::image::ImageData *icon; - } currentMode; + } curMode; bool created; + bool mouseGrabbed; + + SDL_Window *window; + SDL_GLContext context; + }; // Window } // sdl diff --git a/src/modules/window/wrap_Window.cpp b/src/modules/window/wrap_Window.cpp index 70b0d6fd5..245f79a54 100644 --- a/src/modules/window/wrap_Window.cpp +++ b/src/modules/window/wrap_Window.cpp @@ -28,23 +28,37 @@ namespace window static Window *instance = 0; +int w_getDisplayCount(lua_State *L) +{ + lua_pushinteger(L, instance->getDisplayCount()); + return 1; +} + int w_checkMode(lua_State *L) { int w = luaL_checkint(L, 1); int h = luaL_checkint(L, 2); bool fs = false; + int displayindex = 0; if (lua_istable(L, 3)) { lua_getfield(L, 3, "fullscreen"); fs = luax_toboolean(L, -1); - lua_pop(L, 1); + + lua_getfield(L, 3, "display"); + displayindex = luaL_optint(L, -1, 1) - 1; + + lua_pop(L, 2); } else + { fs = luax_toboolean(L, 3); + displayindex = luaL_optint(L, 4, 1) - 1; + } - luax_pushboolean(L, instance->checkWindowSize(w, h, fs)); + luax_pushboolean(L, instance->checkWindowSize(w, h, fs, displayindex)); return 1; } @@ -63,12 +77,33 @@ int w_setMode(lua_State *L) WindowFlags flags; + lua_getfield(L, 3, "fullscreentype"); + if (!lua_isnoneornil(L, -1)) + { + const char *typestr = luaL_checkstring(L, -1); + + if (!Window::getConstant(typestr, flags.fstype)) + return luaL_error(L, "Invalid fullscreen type: %s", typestr); + } + else + { + // Default to "normal" fullscreen. + flags.fstype = Window::FULLSCREEN_TYPE_NORMAL; + } + lua_pop(L, 1); + flags.fullscreen = luax_boolflag(L, 3, "fullscreen", false); flags.vsync = luax_boolflag(L, 3, "vsync", true); flags.fsaa = luax_intflag(L, 3, "fsaa", 0); flags.resizable = luax_boolflag(L, 3, "resizable", false); + flags.minwidth = luax_intflag(L, 3, "minwidth", 100); + flags.minheight = luax_intflag(L, 3, "minheight", 100); flags.borderless = luax_boolflag(L, 3, "borderless", false); flags.centered = luax_boolflag(L, 3, "centered", true); + flags.display = luax_intflag(L, 3, "display", 1); + + // Display index is 1-based in Lua and 0-based internally. + flags.display--; try { @@ -92,38 +127,52 @@ int w_getMode(lua_State *L) lua_newtable(L); + const char *fstypestr = "normal"; + Window::getConstant(flags.fstype, fstypestr); + + lua_pushstring(L, fstypestr); + lua_setfield(L, -2, "fullscreentype"); + luax_pushboolean(L, flags.fullscreen); lua_setfield(L, -2, "fullscreen"); luax_pushboolean(L, flags.vsync); lua_setfield(L, -2, "vsync"); - lua_pushnumber(L, flags.fsaa); + lua_pushinteger(L, flags.fsaa); lua_setfield(L, -2, "fsaa"); luax_pushboolean(L, flags.resizable); lua_setfield(L, -2, "resizable"); + lua_pushinteger(L, flags.minwidth); + lua_setfield(L, -2, "minwidth"); + + lua_pushinteger(L, flags.minheight); + lua_setfield(L, -2, "minheight"); + luax_pushboolean(L, flags.borderless); lua_setfield(L, -2, "borderless"); luax_pushboolean(L, flags.centered); lua_setfield(L, -2, "centered"); - + + // Display index is 0-based internally and 1-based in Lua. + lua_pushinteger(L, flags.display + 1); + lua_setfield(L, -2, "display"); + return 3; } int w_getModes(lua_State *L) { - int n; - Window::WindowSize *modes = instance->getFullscreenSizes(n); + int displayindex = luaL_optint(L, 1, 1); - if (modes == 0) - return 0; + std::vector modes = instance->getFullscreenSizes(displayindex - 1); - lua_createtable(L, n, 0); + lua_createtable(L, modes.size(), 0); - for (int i = 0; i < n ; i++) + for (size_t i = 0; i < modes.size(); i++) { lua_pushinteger(L, i+1); lua_createtable(L, 0, 2); @@ -141,29 +190,43 @@ int w_getModes(lua_State *L) lua_settable(L, -3); } - delete[] modes; return 1; } -int w_toggleFullscreen(lua_State *L) +int w_setFullscreen(lua_State *L) { - int width, height; - WindowFlags flags; - instance->getWindow(width, height, flags); - flags.fullscreen = !flags.fullscreen; + bool fullscreen = luax_toboolean(L, 1); + Window::FullscreenType fstype = Window::FULLSCREEN_TYPE_MAX_ENUM; - try - { - luax_pushboolean(L, instance->setWindow(width, height, &flags)); - } - catch (love::Exception &e) - { - return luaL_error(L, "%s", e.what()); - } + const char *typestr = lua_isnoneornil(L, 2) ? 0 : lua_tostring(L, 2); + if (typestr && !Window::getConstant(typestr, fstype)) + return luaL_error(L, "Invalid fullscreen type: %s", typestr); + bool success = false; + if (fstype == Window::FULLSCREEN_TYPE_MAX_ENUM) + success = instance->setFullscreen(fullscreen); + else + success = instance->setFullscreen(fullscreen, fstype); + + luax_pushboolean(L, success); return 1; } +int w_isFullscreen(lua_State *L) +{ + int w, h; + WindowFlags flags; + instance->getWindow(w, h, flags); + + const char *typestr; + if (!Window::getConstant(flags.fstype, typestr)) + luaL_error(L, "Unknown fullscreen type."); + + luax_pushboolean(L, flags.fullscreen); + lua_pushstring(L, typestr); + return 2; +} + int w_isCreated(lua_State *L) { luax_pushboolean(L, instance->isCreated()); @@ -189,11 +252,21 @@ int w_getDimensions(lua_State *L) return 2; } +int w_getDesktopDimensions(lua_State *L) +{ + int width = 0, height = 0; + int displayindex = luaL_optint(L, 1, 1) - 1; + instance->getDesktopDimensions(displayindex, width, height); + lua_pushinteger(L, width); + lua_pushinteger(L, height); + return 2; +} + int w_setIcon(lua_State *L) { image::ImageData *i = luax_checktype(L, 1, "ImageData", IMAGE_IMAGE_DATA_T); - instance->setIcon(i); - return 0; + luax_pushboolean(L, instance->setIcon(i)); + return 1; } int w_getIcon(lua_State *L) @@ -242,15 +315,18 @@ int w_isVisible(lua_State *L) static const luaL_Reg functions[] = { + { "getDisplayCount", w_getDisplayCount }, { "checkMode", w_checkMode }, { "setMode", w_setMode }, { "getMode", w_getMode }, { "getModes", w_getModes }, - { "toggleFullscreen", w_toggleFullscreen }, + { "setFullscreen", w_setFullscreen }, + { "isFullscreen", w_isFullscreen }, { "isCreated", w_isCreated }, { "getWidth", w_getWidth }, { "getHeight", w_getHeight }, { "getDimensions", w_getDimensions }, + { "getDesktopDimensions", w_getDesktopDimensions }, { "setIcon", w_setIcon }, { "getIcon", w_getIcon }, { "setTitle", w_setTitle }, @@ -265,7 +341,7 @@ extern "C" int luaopen_love_window(lua_State *L) { try { - instance = sdl::Window::getSingleton(); + instance = sdl::Window::createSingleton(); } catch (love::Exception &e) { diff --git a/src/modules/window/wrap_Window.h b/src/modules/window/wrap_Window.h index ec813ac04..506185774 100644 --- a/src/modules/window/wrap_Window.h +++ b/src/modules/window/wrap_Window.h @@ -29,15 +29,18 @@ namespace love namespace window { +int w_getDisplayCount(lua_State *L); int w_checkMode(lua_State *L); int w_setMode(lua_State *L); int w_getMode(lua_State *L); int w_getModes(lua_State *L); -int w_toggleFullscreen(lua_State *L); +int w_setFullscreen(lua_State *L); +int w_isFullscreen(lua_State *L); int w_isCreated(lua_State *L); int w_getWidth(lua_State *L); int w_getHeight(lua_State *L); int w_getDimensions(lua_State *L); +int w_getDesktopDimensions(lua_State *L); int w_setIcon(lua_State *L); int w_getIcon(lua_State *L); int w_setTitle(lua_State *L); diff --git a/src/scripts/boot.lua b/src/scripts/boot.lua index c9b0453aa..43caf5fd0 100644 --- a/src/scripts/boot.lua +++ b/src/scripts/boot.lua @@ -158,6 +158,12 @@ function love.createhandlers() keyreleased = function (b) if love.keyreleased then return love.keyreleased(b) end end, + textinput = function (t) + if love.textinput then return love.textinput(t) end + end, + textedit = function (t,s,l) + if love.textedit then return love.textedit(t,s,l) end + end, mousepressed = function (x,y,b) if love.mousepressed then return love.mousepressed(x,y,b) end end, @@ -173,9 +179,24 @@ function love.createhandlers() joystickaxis = function (j,a,v) if love.joystickaxis then return love.joystickaxis(j,a,v) end end, - joystickhat = function(j,h,v) + joystickhat = function (j,h,v) if love.joystickhat then return love.joystickhat(j,h,v) end end, + gamepadpressed = function (j,b) + if love.gamepadpressed then return love.gamepadpressed(j,b) end + end, + gamepadreleased = function (j,b) + if love.gamepadreleased then return love.gamepadreleased(j,b) end + end, + gamepadaxis = function (j,a,v) + if love.gamepadaxis then return love.gamepadaxis(j,a,v) end + end, + joystickadded = function (j) + if love.joystickadded then return love.joystickadded(j) end + end, + joystickremoved = function(j) + if love.joystickremoved then return love.joystickremoved(j) end + end, focus = function (f) if love.focus then return love.focus(f) end end, @@ -192,11 +213,7 @@ function love.createhandlers() if love.threaderror then return love.threaderror(t, err) end end, resize = function(w, h) - local ow, oh, flags = love.window.getMode() - if flags.resizable then - love.window.setMode(w, h, flags) - if love.resize then return love.resize(w, h) end - end + if love.resize then return love.resize(w, h) end end, }, { __index = function(self, name) @@ -266,7 +283,11 @@ function love.init() window = { width = 800, height = 600, + minwidth = 100, + minheight = 100, fullscreen = false, + fullscreentype = "normal", + display = 1, vsync = true, fsaa = 0, borderless = false, @@ -285,6 +306,7 @@ function love.init() math = true, physics = true, sound = true, + system = true, font = true, thread = true, window = true, @@ -322,6 +344,7 @@ function love.init() "joystick", "mouse", "sound", + "system", "audio", "image", "font", @@ -347,15 +370,19 @@ function love.init() -- Setup window here. local has_window = false if c.window and c.modules.window then - if love.window.checkMode(c.window.width, c.window.height, c.window.fullscreen) or (c.window.width == 0 and c.window.height == 0) then + if love.window.checkMode(c.window.width, c.window.height, c.window.fullscreen, c.window.display) or (c.window.width == 0 and c.window.height == 0) then assert(love.window.setMode(c.window.width, c.window.height, { fullscreen = c.window.fullscreen, + fullscreentype = c.window.fullscreentype, vsync = c.window.vsync, fsaa = c.window.fsaa, resizable = c.window.resizable, + minwidth = c.window.minwidth, + minheight = c.window.minheight, borderless = c.window.borderless, centered = c.window.centered, + display = c.window.display, }), "Could not set window mode") else error("Could not set window mode") diff --git a/src/scripts/boot.lua.h b/src/scripts/boot.lua.h index f2d1558e5..2ed6b1699 100644 --- a/src/scripts/boot.lua.h +++ b/src/scripts/boot.lua.h @@ -270,6 +270,19 @@ const unsigned char boot_lua[] = 0x6f, 0x76, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x28, 0x62, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, + 0x09, 0x09, 0x74, 0x65, 0x78, 0x74, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x74, 0x29, 0x0a, + 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x69, 0x6e, 0x70, + 0x75, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, + 0x65, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x28, 0x74, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, + 0x09, 0x09, 0x74, 0x65, 0x78, 0x74, 0x65, 0x64, 0x69, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x74, 0x2c, 0x73, 0x2c, 0x6c, 0x29, 0x0a, + 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x65, 0x64, 0x69, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, + 0x2e, 0x74, 0x65, 0x78, 0x74, 0x65, 0x64, 0x69, 0x74, 0x28, 0x74, 0x2c, 0x73, 0x2c, 0x6c, 0x29, 0x20, 0x65, + 0x6e, 0x64, 0x0a, + 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x09, 0x09, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x70, 0x72, @@ -306,12 +319,47 @@ const unsigned char boot_lua[] = 0x6a, 0x2c, 0x61, 0x2c, 0x76, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x09, 0x09, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x68, 0x61, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, - 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6a, 0x2c, 0x68, 0x2c, 0x76, 0x29, 0x0a, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 0x2c, 0x68, 0x2c, 0x76, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x68, 0x61, 0x74, 0x28, 0x6a, 0x2c, 0x68, 0x2c, 0x76, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, + 0x09, 0x09, 0x67, 0x61, 0x6d, 0x65, 0x70, 0x61, 0x64, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, + 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 0x2c, 0x62, 0x29, 0x0a, + 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x70, 0x61, 0x64, + 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x70, 0x61, 0x64, 0x70, 0x72, 0x65, 0x73, + 0x73, 0x65, 0x64, 0x28, 0x6a, 0x2c, 0x62, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, + 0x09, 0x09, 0x67, 0x61, 0x6d, 0x65, 0x70, 0x61, 0x64, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, + 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 0x2c, 0x62, 0x29, 0x0a, + 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x70, 0x61, 0x64, + 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x70, 0x61, 0x64, 0x72, 0x65, 0x6c, + 0x65, 0x61, 0x73, 0x65, 0x64, 0x28, 0x6a, 0x2c, 0x62, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, + 0x09, 0x09, 0x67, 0x61, 0x6d, 0x65, 0x70, 0x61, 0x64, 0x61, 0x78, 0x69, 0x73, 0x20, 0x3d, 0x20, 0x66, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 0x2c, 0x61, 0x2c, 0x76, 0x29, 0x0a, + 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x70, 0x61, 0x64, + 0x61, 0x78, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, + 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x70, 0x61, 0x64, 0x61, 0x78, 0x69, 0x73, 0x28, 0x6a, 0x2c, + 0x61, 0x2c, 0x76, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, + 0x09, 0x09, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x3d, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 0x29, 0x0a, + 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, + 0x6b, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x61, 0x64, 0x64, 0x65, + 0x64, 0x28, 0x6a, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, + 0x09, 0x09, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, + 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6a, 0x29, 0x0a, + 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, + 0x6b, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x72, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x28, 0x6a, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x09, 0x09, 0x66, 0x6f, 0x63, 0x75, 0x73, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x66, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x6f, 0x63, 0x75, 0x73, 0x20, 0x74, @@ -344,17 +392,9 @@ const unsigned char boot_lua[] = 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x09, 0x09, 0x72, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x77, 0x2c, 0x20, 0x68, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x77, 0x2c, 0x20, 0x6f, 0x68, 0x2c, 0x20, 0x66, - 0x6c, 0x61, 0x67, 0x73, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, - 0x2e, 0x67, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x28, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x2e, 0x72, 0x65, 0x73, 0x69, 0x7a, 0x61, - 0x62, 0x6c, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x73, 0x65, - 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x28, 0x77, 0x2c, 0x20, 0x68, 0x2c, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x72, 0x65, 0x73, 0x69, 0x7a, 0x65, - 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, - 0x72, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x28, 0x77, 0x2c, 0x20, 0x68, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x72, 0x65, 0x73, 0x69, 0x7a, 0x65, 0x20, + 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x72, + 0x65, 0x73, 0x69, 0x7a, 0x65, 0x28, 0x77, 0x2c, 0x20, 0x68, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x09, 0x7d, 0x2c, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, @@ -471,8 +511,14 @@ const unsigned char boot_lua[] = 0x09, 0x09, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x09, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x38, 0x30, 0x30, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x3d, 0x20, 0x36, 0x30, 0x30, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x6d, 0x69, 0x6e, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x30, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x6d, 0x69, 0x6e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x3d, 0x20, 0x31, 0x30, 0x30, + 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x74, 0x79, 0x70, 0x65, 0x20, + 0x3d, 0x20, 0x22, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x22, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x31, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x76, 0x73, 0x79, 0x6e, 0x63, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x66, 0x73, 0x61, 0x61, 0x20, 0x3d, 0x20, 0x30, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x6c, 0x65, 0x73, 0x73, 0x20, 0x3d, 0x20, 0x66, 0x61, @@ -497,6 +543,7 @@ const unsigned char boot_lua[] = 0x09, 0x09, 0x09, 0x6d, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x73, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x73, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x66, 0x6f, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, @@ -553,6 +600,7 @@ const unsigned char boot_lua[] = 0x09, 0x09, 0x22, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x22, 0x2c, 0x0a, 0x09, 0x09, 0x22, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x22, 0x2c, 0x0a, 0x09, 0x09, 0x22, 0x73, 0x6f, 0x75, 0x6e, 0x64, 0x22, 0x2c, 0x0a, + 0x09, 0x09, 0x22, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x22, 0x2c, 0x0a, 0x09, 0x09, 0x22, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x22, 0x2c, 0x0a, 0x09, 0x09, 0x22, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x22, 0x2c, 0x0a, 0x09, 0x09, 0x22, 0x66, 0x6f, 0x6e, 0x74, 0x22, 0x2c, 0x0a, @@ -590,7 +638,8 @@ const unsigned char boot_lua[] = 0x68, 0x65, 0x63, 0x6b, 0x4d, 0x6f, 0x64, 0x65, 0x28, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x2c, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x66, 0x75, 0x6c, - 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x29, 0x20, 0x6f, 0x72, 0x20, 0x28, 0x63, 0x2e, 0x77, 0x69, 0x6e, + 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x2c, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, + 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x29, 0x20, 0x6f, 0x72, 0x20, 0x28, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x3d, 0x3d, 0x20, 0x30, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, @@ -602,17 +651,26 @@ const unsigned char boot_lua[] = 0x09, 0x09, 0x09, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x66, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x66, 0x75, 0x6c, 0x6c, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x74, 0x79, 0x70, 0x65, + 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x66, 0x75, 0x6c, 0x6c, 0x73, 0x63, + 0x72, 0x65, 0x65, 0x6e, 0x74, 0x79, 0x70, 0x65, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x76, 0x73, 0x79, 0x6e, 0x63, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x76, 0x73, 0x79, 0x6e, 0x63, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x66, 0x73, 0x61, 0x61, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x66, 0x73, 0x61, 0x61, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x72, 0x65, 0x73, 0x69, 0x7a, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x72, 0x65, 0x73, 0x69, 0x7a, 0x61, 0x62, 0x6c, 0x65, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x6d, 0x69, 0x6e, 0x77, 0x69, 0x64, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, + 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x6d, 0x69, 0x6e, 0x77, 0x69, 0x64, 0x74, 0x68, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x6d, 0x69, 0x6e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x20, 0x3d, 0x20, 0x63, 0x2e, + 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x6d, 0x69, 0x6e, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x6c, 0x65, 0x73, 0x73, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x6c, 0x65, 0x73, 0x73, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x65, 0x64, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, + 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x7d, 0x29, 0x2c, 0x20, 0x22, 0x43, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x65, 0x74, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x29, 0x0a, 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x0a,