# HG changeset patch # User Sam Lantinga # Date 1253366980 0 # Node ID 00cace2d9080698102d59af05425bcf6552b6469 # Parent fd207dce9f940a1ac8498bf718757d08de60d036 Merged a cleaned up version of Jiang's code changes from Google Summer of Code 2009 diff -r fd207dce9f94 -r 00cace2d9080 build-scripts/showrev.sh --- a/build-scripts/showrev.sh Sat Sep 19 12:48:52 2009 +0000 +++ b/build-scripts/showrev.sh Sat Sep 19 13:29:40 2009 +0000 @@ -9,4 +9,7 @@ (svnversion -c 2>/dev/null || svnversion .) | \ sed -e 's,\([0-9]*\)[A-Z]*,\1,' \ -e 's,[0-9]*:\([0-9]*\)[A-Z]*,\1,' +else + cd $srcdir + git svn info | grep Revision | awk '{ print $2 }' fi diff -r fd207dce9f94 -r 00cace2d9080 include/SDL_events.h --- a/include/SDL_events.h Sat Sep 19 12:48:52 2009 +0000 +++ b/include/SDL_events.h Sat Sep 19 13:29:40 2009 +0000 @@ -60,6 +60,7 @@ SDL_WINDOWEVENT, /**< Window state change */ SDL_KEYDOWN, /**< Keys pressed */ SDL_KEYUP, /**< Keys released */ + SDL_TEXTEDITING, /**< Keyboard text editing (composition) */ SDL_TEXTINPUT, /**< Keyboard text input */ SDL_MOUSEMOTION, /**< Mouse moved */ SDL_MOUSEBUTTONDOWN, /**< Mouse button pressed */ @@ -97,6 +98,7 @@ SDL_KEYDOWNMASK = SDL_EVENTMASK(SDL_KEYDOWN), SDL_KEYUPMASK = SDL_EVENTMASK(SDL_KEYUP), SDL_KEYEVENTMASK = SDL_EVENTMASK(SDL_KEYDOWN) | SDL_EVENTMASK(SDL_KEYUP), + SDL_TEXTEDITINGMASK = SDL_EVENTMASK(SDL_TEXTEDITING), SDL_TEXTINPUTMASK = SDL_EVENTMASK(SDL_TEXTINPUT), SDL_MOUSEMOTIONMASK = SDL_EVENTMASK(SDL_MOUSEMOTION), SDL_MOUSEBUTTONDOWNMASK = SDL_EVENTMASK(SDL_MOUSEBUTTONDOWN), @@ -149,6 +151,20 @@ } SDL_KeyboardEvent; /** + * \struct SDL_TextEditingEvent + * + * \brief Keyboard text editing event structure (event.edit.*) + */ +#define SDL_TEXTEDITINGEVENT_TEXT_SIZE (32) +typedef struct SDL_TextEditingEvent +{ + Uint8 type; /**< SDL_TEXTEDITING */ + char text[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; /**< The editing text */ + int start; /**< The start cursor of selected editing text */ + int length; /**< The length of selected editing text */ +} SDL_TextEditingEvent; + +/** * \struct SDL_TextInputEvent * * \brief Keyboard text input event structure (event.text.*) @@ -350,6 +366,7 @@ Uint8 type; /**< Event type, shared with all events */ SDL_WindowEvent window; /**< Window event data */ SDL_KeyboardEvent key; /**< Keyboard event data */ + SDL_TextEditingEvent edit; /**< Text editing event data */ SDL_TextInputEvent text; /**< Text input event data */ SDL_MouseMotionEvent motion; /**< Mouse motion event data */ SDL_MouseButtonEvent button; /**< Mouse button event data */ diff -r fd207dce9f94 -r 00cace2d9080 include/SDL_keyboard.h --- a/include/SDL_keyboard.h Sat Sep 19 12:48:52 2009 +0000 +++ b/include/SDL_keyboard.h Sat Sep 19 13:29:40 2009 +0000 @@ -154,6 +154,34 @@ */ extern DECLSPEC const char *SDLCALL SDL_GetKeyName(SDLKey key); +/** + * \fn void SDL_StartTextInput(void) + * + * \brief Start accepting Unicode text input events. + * + * \sa SDL_StopTextInput() + * \sa SDL_SetTextInputRect() + */ +extern DECLSPEC void SDLCALL SDL_StartTextInput(void); + +/** + * \fn void SDL_StopTextInput(void) + * + * \brief Stop receiving any text input events. + * + * \sa SDL_StartTextInput() + */ +extern DECLSPEC void SDLCALL SDL_StopTextInput(void); + +/** + * \fn void SDL_SetTextInputRect(SDL_Rect *rect) + * + * \brief Set the rectangle used to type Unicode text inputs. + * + * \sa SDL_StartTextInput() + */ +extern DECLSPEC void SDLCALL SDL_SetTextInputRect(SDL_Rect *rect); + /* Ends C function definitions when using C++ */ #ifdef __cplusplus diff -r fd207dce9f94 -r 00cace2d9080 src/SDL_compat.c --- a/src/SDL_compat.c Sat Sep 19 12:48:52 2009 +0000 +++ b/src/SDL_compat.c Sat Sep 19 13:29:40 2009 +0000 @@ -40,6 +40,7 @@ static Uint32 SDL_VideoFlags = 0; static char *wm_title = NULL; static SDL_Surface *SDL_VideoIcon; +static int SDL_enabled_UNICODE = 0; char * SDL_AudioDriverName(char *namebuf, int maxlen) @@ -1720,7 +1721,19 @@ int SDL_EnableUNICODE(int enable) { - return SDL_EventState(SDL_TEXTINPUT, enable); + int previous = SDL_enabled_UNICODE; + + switch (enable) { + case 1: + SDL_enabled_UNICODE = 1; + SDL_StartTextInput(); + break; + case 0: + SDL_enabled_UNICODE = 0; + SDL_StopTextInput(); + break; + } + return previous; } /* vi: set ts=4 sw=4 expandtab: */ diff -r fd207dce9f94 -r 00cace2d9080 src/events/SDL_keyboard.c --- a/src/events/SDL_keyboard.c Sat Sep 19 12:48:52 2009 +0000 +++ b/src/events/SDL_keyboard.c Sat Sep 19 13:29:40 2009 +0000 @@ -852,6 +852,24 @@ return (posted); } +int +SDL_SendEditingText(const char *text, int start, int length) +{ + int posted; + + /* Post the event, if desired */ + posted = 0; + if (SDL_ProcessEvents[SDL_TEXTEDITING] == SDL_ENABLE) { + SDL_Event event; + event.edit.type = SDL_TEXTEDITING; + event.edit.start = start; + event.edit.length = length; + SDL_strlcpy(event.edit.text, text, SDL_arraysize(event.text.text)); + posted = (SDL_PushEvent(&event) > 0); + } + return (posted); +} + void SDL_KeyboardQuit(void) { diff -r fd207dce9f94 -r 00cace2d9080 src/events/SDL_keyboard_c.h --- a/src/events/SDL_keyboard_c.h Sat Sep 19 12:48:52 2009 +0000 +++ b/src/events/SDL_keyboard_c.h Sat Sep 19 13:29:40 2009 +0000 @@ -81,6 +81,9 @@ /* Send keyboard text input for a keyboard at an index */ extern int SDL_SendKeyboardText(int index, const char *text); +/* Send editing text for selected range from start to end */ +extern int SDL_SendEditingText(const char *text, int start, int end); + /* Shutdown the keyboard subsystem */ extern void SDL_KeyboardQuit(void); diff -r fd207dce9f94 -r 00cace2d9080 src/video/SDL_sysvideo.h --- a/src/video/SDL_sysvideo.h Sat Sep 19 12:48:52 2009 +0000 +++ b/src/video/SDL_sysvideo.h Sat Sep 19 13:29:40 2009 +0000 @@ -277,6 +277,11 @@ /* Suspend the screensaver */ void (*SuspendScreenSaver) (_THIS); + /* Text input */ + void (*StartTextInput) (_THIS); + void (*StopTextInput) (_THIS); + void (*SetTextInputRect) (_THIS, SDL_Rect *rect); + /* * * */ /* Data common to all drivers */ SDL_bool suspend_screensaver; diff -r fd207dce9f94 -r 00cace2d9080 src/video/SDL_video.c --- a/src/video/SDL_video.c Sat Sep 19 12:48:52 2009 +0000 +++ b/src/video/SDL_video.c Sat Sep 19 13:29:40 2009 +0000 @@ -3233,4 +3233,32 @@ return (_this->GetWindowWMInfo(_this, window, info)); } +void +SDL_StartTextInput(void) +{ + if (_this->StartTextInput) { + _this->StartTextInput(_this); + } + SDL_EventState(SDL_TEXTINPUT, SDL_ENABLE); + SDL_EventState(SDL_TEXTEDITING, SDL_ENABLE); +} + +void +SDL_StopTextInput(void) +{ + if (_this->StopTextInput) { + _this->StopTextInput(_this); + } + SDL_EventState(SDL_TEXTINPUT, SDL_DISABLE); + SDL_EventState(SDL_TEXTEDITING, SDL_DISABLE); +} + +void +SDL_SetTextInputRect(SDL_Rect *rect) +{ + if (_this->SetTextInputRect) { + _this->SetTextInputRect(_this, rect); + } +} + /* vi: set ts=4 sw=4 expandtab: */ diff -r fd207dce9f94 -r 00cace2d9080 src/video/cocoa/SDL_cocoaevents.m --- a/src/video/cocoa/SDL_cocoaevents.m Sat Sep 19 12:48:52 2009 +0000 +++ b/src/video/cocoa/SDL_cocoaevents.m Sat Sep 19 13:29:40 2009 +0000 @@ -193,6 +193,10 @@ Cocoa_HandleKeyEvent(_this, event); /* Fall through to pass event to NSApp; er, nevermind... */ /* FIXME: Find a way to stop the beeping, using delegate */ + + /* Add to support system-wide keyboard shortcuts like CMD+Space */ + if (([event modifierFlags] & NSCommandKeyMask) || [event type] == NSFlagsChanged) + [NSApp sendEvent: event]; break; default: [NSApp sendEvent:event]; diff -r fd207dce9f94 -r 00cace2d9080 src/video/cocoa/SDL_cocoakeyboard.h --- a/src/video/cocoa/SDL_cocoakeyboard.h Sat Sep 19 12:48:52 2009 +0000 +++ b/src/video/cocoa/SDL_cocoakeyboard.h Sat Sep 19 13:29:40 2009 +0000 @@ -28,6 +28,10 @@ extern void Cocoa_HandleKeyEvent(_THIS, NSEvent * event); extern void Cocoa_QuitKeyboard(_THIS); +extern void Cocoa_StartTextInput(_THIS); +extern void Cocoa_StopTextInput(_THIS); +extern void Cocoa_SetTextInputRect(_THIS, SDL_Rect *rect); + #endif /* _SDL_cocoakeyboard_h */ /* vi: set ts=4 sw=4 expandtab: */ diff -r fd207dce9f94 -r 00cace2d9080 src/video/cocoa/SDL_cocoakeyboard.m --- a/src/video/cocoa/SDL_cocoakeyboard.m Sat Sep 19 12:48:52 2009 +0000 +++ b/src/video/cocoa/SDL_cocoakeyboard.m Sat Sep 19 13:29:40 2009 +0000 @@ -28,6 +28,8 @@ #include +//#define DEBUG_IME NSLog +#define DEBUG_IME #ifndef NX_DEVICERCTLKEYMASK #define NX_DEVICELCTLKEYMASK 0x00000001 @@ -54,14 +56,142 @@ #define NX_DEVICERCTLKEYMASK 0x00002000 #endif -@interface SDLTranslatorResponder : NSTextView +@interface SDLTranslatorResponder : NSView { + NSString *_markedText; + NSRange _markedRange; + NSRange _selectedRange; + SDL_Rect _inputRect; + int _keyboard; } - (void) doCommandBySelector:(SEL)myselector; +- (void) setInputRect:(SDL_Rect *) rect; +- (void) setKeyboard:(int) keyboard; @end @implementation SDLTranslatorResponder -- (void) doCommandBySelector:(SEL) myselector {} + +- (void) setKeyboard:(int) keyboard +{ + _keyboard = keyboard; +} + +- (void) setInputRect:(SDL_Rect *) rect +{ + _inputRect = *rect; +} + +- (void) insertText:(id) aString +{ + const char *str; + + DEBUG_IME(@"insertText: %@", aString); + + /* Could be NSString or NSAttributedString, so we have + * to test and convert it before return as SDL event */ + if ([aString isKindOfClass: [NSAttributedString class]]) + str = [[aString string] UTF8String]; + else + str = [aString UTF8String]; + + SDL_SendKeyboardText(_keyboard, str); +} + +- (void) doCommandBySelector:(SEL) myselector +{ + [super doCommandBySelector: myselector]; +} + +- (BOOL) hasMarkedText +{ + return _markedText != nil; +} + +- (NSRange) markedRange +{ + return _markedRange; +} + +- (NSRange) selectedRange +{ + return _selectedRange; +} + +- (void) setMarkedText:(id) aString + selectedRange:(NSRange) selRange +{ + if ([aString isKindOfClass: [NSAttributedString class]]) + aString = [aString string]; + + if ([aString length] == 0) + { + [self unmarkText]; + return; + } + + if (_markedText != aString) + { + [_markedText release]; + _markedText = [aString retain]; + } + + _selectedRange = selRange; + _markedRange = NSMakeRange(0, [aString length]); + + SDL_SendEditingText([aString UTF8String], selRange.location, selRange.length); + + DEBUG_IME(@"setMarkedText: %@, (%d, %d)", _markedText, + selRange.location, selRange.length); +} + +- (void) unmarkText +{ + [_markedText release]; + _markedText = nil; +} + +- (NSRect) firstRectForCharacterRange: (NSRange) theRange +{ + float windowHeight = [[self window] frame].size.height; + NSRect rect = NSMakeRect(_inputRect.x, windowHeight - _inputRect.y - _inputRect.h, + _inputRect.w, _inputRect.h); + + DEBUG_IME(@"firstRectForCharacterRange: (%d, %d): windowHeight = %g, rect = %@", + theRange.location, theRange.length, windowHeight, + NSStringFromRect(rect)); + rect.origin = [[self window] convertBaseToScreen: rect.origin]; + + return rect; +} + +- (NSAttributedString *) attributedSubstringFromRange: (NSRange) theRange +{ + DEBUG_IME(@"attributedSubstringFromRange: (%d, %d)", theRange.location, theRange.length); + return nil; +} + +- (NSInteger) conversationIdentifier +{ + return (NSInteger) self; +} + +// This method returns the index for character that is +// nearest to thePoint. thPoint is in screen coordinate system. +- (NSUInteger) characterIndexForPoint:(NSPoint) thePoint +{ + DEBUG_IME(@"characterIndexForPoint: (%g, %g)", thePoint.x, thePoint.y); + return 0; +} + +// This method is the key to attribute extension. +// We could add new attributes through this method. +// NSInputServer examines the return value of this +// method & constructs appropriate attributed string. +- (NSArray *) validAttributesForMarkedText +{ + return [NSArray array]; +} + @end /* This is the original behavior, before support was added for @@ -478,12 +608,7 @@ { SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; SDL_Keyboard keyboard; - NSAutoreleasePool *pool; - pool = [[NSAutoreleasePool alloc] init]; - data->fieldEdit = [[SDLTranslatorResponder alloc] initWithFrame:NSMakeRect(0.0, 0.0, 0.0, 0.0)]; - [pool release]; - SDL_zero(keyboard); data->keyboard = SDL_AddKeyboard(&keyboard, -1); UpdateKeymap(data); @@ -498,6 +623,47 @@ } void +Cocoa_StartTextInput(_THIS) +{ + SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSView *parentView = [[NSApp keyWindow] contentView]; + + data->fieldEdit = [[SDLTranslatorResponder alloc] initWithFrame:NSMakeRect(0.0, 0.0, 0.0, 0.0)]; + [data->fieldEdit setKeyboard: data->keyboard]; + + if (! [[data->fieldEdit superview] isEqual: parentView]) + { + // DEBUG_IME(@"add fieldEdit to window contentView"); + [data->fieldEdit removeFromSuperview]; + [parentView addSubview: data->fieldEdit]; + [[NSApp keyWindow] makeFirstResponder: data->fieldEdit]; + } + + [pool release]; +} + +void +Cocoa_StopTextInput(_THIS) +{ + SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [data->fieldEdit removeFromSuperview]; + [data->fieldEdit release]; + data->fieldEdit = nil; + [pool release]; +} + +void +Cocoa_SetTextInputRect(_THIS, SDL_Rect *rect) +{ + SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; + + [data->fieldEdit setInputRect: rect]; +} + +void Cocoa_HandleKeyEvent(_THIS, NSEvent *event) { SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; @@ -533,11 +699,13 @@ if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) { /* FIXME CW 2007-08-16: only send those events to the field editor for which we actually want text events, not e.g. esc or function keys. Arrow keys in particular seem to produce crashes sometimes. */ [data->fieldEdit interpretKeyEvents:[NSArray arrayWithObject:event]]; +#if 0 text = [[event characters] UTF8String]; if(text && *text) { SDL_SendKeyboardText(data->keyboard, text); [data->fieldEdit setString:@""]; } +#endif } break; case NSKeyUp: @@ -559,10 +727,6 @@ NSAutoreleasePool *pool; SDL_DelKeyboard(data->keyboard); - - pool = [[NSAutoreleasePool alloc] init]; - [data->fieldEdit release]; - [pool release]; } /* vi: set ts=4 sw=4 expandtab: */ diff -r fd207dce9f94 -r 00cace2d9080 src/video/cocoa/SDL_cocoamodes.m --- a/src/video/cocoa/SDL_cocoamodes.m Sat Sep 19 12:48:52 2009 +0000 +++ b/src/video/cocoa/SDL_cocoamodes.m Sat Sep 19 13:29:40 2009 +0000 @@ -250,6 +250,8 @@ CGReleaseDisplayFadeReservation(fade_token); } + [[NSApp mainWindow] makeKeyAndOrderFront: nil]; + #if MAC_OS_X_VERSION_MAX_ALLOWED < 1050 /* There is a bug in Cocoa where NSScreen doesn't synchronize diff -r fd207dce9f94 -r 00cace2d9080 src/video/cocoa/SDL_cocoavideo.h --- a/src/video/cocoa/SDL_cocoavideo.h Sat Sep 19 12:48:52 2009 +0000 +++ b/src/video/cocoa/SDL_cocoavideo.h Sat Sep 19 13:29:40 2009 +0000 @@ -41,6 +41,8 @@ /* Private display data */ +@class SDLTranslatorResponder; + typedef struct SDL_VideoData { SInt32 osversion; @@ -48,7 +50,7 @@ int mouse; int keyboard; void *key_layout; - NSText *fieldEdit; + SDLTranslatorResponder *fieldEdit; Uint32 screensaver_activity; } SDL_VideoData; diff -r fd207dce9f94 -r 00cace2d9080 src/video/cocoa/SDL_cocoavideo.m --- a/src/video/cocoa/SDL_cocoavideo.m Sat Sep 19 12:48:52 2009 +0000 +++ b/src/video/cocoa/SDL_cocoavideo.m Sat Sep 19 13:29:40 2009 +0000 @@ -102,6 +102,10 @@ device->GL_DeleteContext = Cocoa_GL_DeleteContext; #endif + device->StartTextInput = Cocoa_StartTextInput; + device->StopTextInput = Cocoa_StopTextInput; + device->SetTextInputRect = Cocoa_SetTextInputRect; + device->free = Cocoa_DeleteDevice; return device; diff -r fd207dce9f94 -r 00cace2d9080 test/Makefile.in --- a/test/Makefile.in Sat Sep 19 12:48:52 2009 +0000 +++ b/test/Makefile.in Sat Sep 19 13:29:40 2009 +0000 @@ -7,7 +7,7 @@ CFLAGS = @CFLAGS@ LIBS = @LIBS@ -TARGETS = checkkeys$(EXE) graywin$(EXE) loopwave$(EXE) testresample$(EXE) testaudioinfo$(EXE) testmultiaudio$(EXE) testpower$(EXE) testalpha$(EXE) testbitmap$(EXE) testblitspeed$(EXE) testcursor$(EXE) testintersections$(EXE) testdraw2$(EXE) testdyngl$(EXE) testdyngles$(EXE) testerror$(EXE) testfile$(EXE) testgamma$(EXE) testgl$(EXE) testgl2$(EXE) testgles$(EXE) testhread$(EXE) testiconv$(EXE) testjoystick$(EXE) testkeys$(EXE) testlock$(EXE) testoverlay2$(EXE) testoverlay$(EXE) testpalette$(EXE) testplatform$(EXE) testsem$(EXE) testsprite$(EXE) testsprite2$(EXE) testtimer$(EXE) testver$(EXE) testvidinfo$(EXE) testwin$(EXE) testwm$(EXE) testwm2$(EXE) threadwin$(EXE) torturethread$(EXE) testloadso$(EXE) testhaptic$(EXE) testmmousetablet$(EXE) testatomic$(EXE) +TARGETS = checkkeys$(EXE) graywin$(EXE) loopwave$(EXE) testresample$(EXE) testaudioinfo$(EXE) testmultiaudio$(EXE) testpower$(EXE) testalpha$(EXE) testbitmap$(EXE) testblitspeed$(EXE) testcursor$(EXE) testintersections$(EXE) testdraw2$(EXE) testdyngl$(EXE) testdyngles$(EXE) testerror$(EXE) testfile$(EXE) testgamma$(EXE) testgl$(EXE) testgl2$(EXE) testgles$(EXE) testhread$(EXE) testiconv$(EXE) testjoystick$(EXE) testkeys$(EXE) testlock$(EXE) testoverlay2$(EXE) testoverlay$(EXE) testpalette$(EXE) testplatform$(EXE) testsem$(EXE) testsprite$(EXE) testsprite2$(EXE) testtimer$(EXE) testver$(EXE) testvidinfo$(EXE) testwin$(EXE) testwm$(EXE) testwm2$(EXE) threadwin$(EXE) torturethread$(EXE) testloadso$(EXE) testhaptic$(EXE) testmmousetablet$(EXE) testatomic$(EXE) testime$(EXE) all: Makefile $(TARGETS) @@ -149,6 +149,9 @@ testatomic$(EXE): $(srcdir)/testatomic.c $(CC) -o $@ $? $(CFLAGS) $(LIBS) +testime$(EXE): $(srcdir)/testime.c + $(CC) -o $@ $? $(CFLAGS) $(LIBS) @SDL_TTF_LIB@ + clean: rm -f $(TARGETS) diff -r fd207dce9f94 -r 00cace2d9080 test/configure.in --- a/test/configure.in Sat Sep 19 12:48:52 2009 +0000 +++ b/test/configure.in Sat Sep 19 13:29:40 2009 +0000 @@ -128,5 +128,23 @@ AC_SUBST(GLLIB) +dnl Check for SDL_ttf +AC_MSG_CHECKING(for SDL_ttf) +have_SDL_ttf=no +AC_TRY_COMPILE([ + #include "SDL_ttf.h" +],[ +],[ +have_SDL_ttf=yes +]) +AC_MSG_RESULT($have_SDL_ttf) + +if test x$have_SDL_ttf = xyes; then + CFLAGS="$CFLAGS -DHAVE_SDL_TTF" + SDL_TTF_LIB="-lSDL_ttf" +fi + +AC_SUBST(SDL_TTF_LIB) + dnl Finally create all the generated files AC_OUTPUT([Makefile]) diff -r fd207dce9f94 -r 00cace2d9080 test/testime.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/testime.c Sat Sep 19 13:29:40 2009 +0000 @@ -0,0 +1,275 @@ +/* A simple program to test the Input Method support in the SDL library (1.3+) */ + +#include +#include +#include + +#include "SDL.h" +#ifdef HAVE_SDL_TTF +#include "SDL_ttf.h" +#endif + +#define DEFAULT_PTSIZE 30 +#define DEFAULT_FONT "/System/Library/Fonts/华文细黑.ttf" +#define MAX_TEXT_LENGTH 256 + +SDL_Surface *screen; + +#ifdef HAVE_SDL_TTF +TTF_Font *font; +#endif +SDL_Rect textRect, markedRect; +Uint32 lineColor, backColor; +SDL_Color textColor = { 0, 0, 0 }; +char text[MAX_TEXT_LENGTH], *markedText; + +void usage() +{ + printf("usage: testime [--font fontfile] [--fullscreen]\n"); + exit(0); +} + +void InitVideo(int argc, char *argv[]) +{ + int width = 500, height = 250; + int flags = SDL_HWSURFACE; + const char *fontname = DEFAULT_FONT; + int fullscreen = 0; + + for (argc--, argv++; argc > 0; argc--, argv++) + { + if (strcmp(argv[0], "--help") == 0) + usage(); + + else if (strcmp(argv[0], "--fullscreen") == 0) + fullscreen = 1; + + else if (strcmp(argv[0], "--font") == 0) + { + argc--; + argv++; + + if (argc > 0) + fontname = argv[0]; + else + usage(); + } + } + + SDL_putenv("SDL_VIDEO_WINDOW_POS=center"); + if (SDL_Init(SDL_INIT_VIDEO) < 0) + { + fprintf(stderr, "Unable to init SDL: %s\n", TTF_GetError()); + exit(-1); + } + +#ifdef HAVE_SDL_TTF + /* Initialize fonts */ + TTF_Init(); + + font = TTF_OpenFont(fontname, DEFAULT_PTSIZE); + if (! font) + { + fprintf(stderr, "Failed to find font: %s\n", SDL_GetError()); + exit(-1); + } +#endif + + printf("Using font: %s\n", fontname); + atexit(SDL_Quit); + + if (fullscreen) + { + SDL_DisplayMode mode; + SDL_GetDesktopDisplayMode(&mode); + + width = mode.w; + height = mode.h; + fprintf(stderr, "%dx%d\n", width, height); + flags |= SDL_FULLSCREEN; + } + + /* Create window */ + screen = SDL_SetVideoMode(width, height, 32, flags); + if (screen == NULL) + { + fprintf(stderr, "Unable to set %dx%d video: %s\n", + width, height, SDL_GetError()); + exit(-1); + } +} + +void CleanupVideo() +{ + SDL_StopTextInput(); +#ifdef HAVE_SDL_TTF + TTF_CloseFont(font); + TTF_Quit(); +#endif +} + +void InitInput() +{ + backColor = SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF); + lineColor = SDL_MapRGB(screen->format, 0x0, 0x0, 0x0); + + /* Prepare a rect for text input */ + textRect.x = textRect.y = 100; + textRect.w = screen->w - 2 * textRect.x; + textRect.h = 50; + + text[0] = 0; + markedRect = textRect; + markedText = NULL; + + SDL_StartTextInput(); +} + +#ifdef HAVE_SDL_TTF +static void RenderText(SDL_Surface *sur, + TTF_Font *font, + const char *text, + int x, int y, + SDL_Color color) +{ + SDL_Surface *textSur = TTF_RenderUTF8_Blended(font, text, color); + SDL_Rect dest = { x, y, textSur->w, textSur->h }; + + SDL_BlitSurface(textSur, NULL, sur, &dest); + SDL_FreeSurface(textSur); +} +#endif + +void Redraw() +{ + int w = 0, h = textRect.h; + SDL_Rect cursorRect, underlineRect; + + SDL_FillRect(screen, &textRect, backColor); + +#ifdef HAVE_SDL_TTF + if (strlen(text)) + { + RenderText(screen, font, text, textRect.x, textRect.y, textColor); + TTF_SizeUTF8(font, text, &w, &h); + } +#endif + + markedRect.x = textRect.x + w; + markedRect.w = textRect.w - w; + if (markedRect.w < 0) + { + SDL_Flip(screen); + // Stop text input because we cannot hold any more characters + SDL_StopTextInput(); + return; + } + + cursorRect = markedRect; + cursorRect.w = 2; + cursorRect.h = h; + + SDL_FillRect(screen, &markedRect, backColor); + if (markedText) + { +#ifdef HAVE_SDL_TTF + RenderText(screen, font, markedText, markedRect.x, markedRect.y, textColor); + TTF_SizeUTF8(font, markedText, &w, &h); +#endif + + underlineRect = markedRect; + underlineRect.y += (h - 2); + underlineRect.h = 2; + underlineRect.w = w; + + cursorRect.x += w + 1; + + SDL_FillRect(screen, &underlineRect, lineColor); + } + + SDL_FillRect(screen, &cursorRect, lineColor); + + SDL_Flip(screen); + + SDL_SetTextInputRect(&markedRect); +} + +void +HotKey_ToggleFullScreen(void) +{ + SDL_Surface *screen; + + screen = SDL_GetVideoSurface(); + if (SDL_WM_ToggleFullScreen(screen)) { + printf("Toggled fullscreen mode - now %s\n", + (screen->flags & SDL_FULLSCREEN) ? "fullscreen" : "windowed"); + } else { + printf("Unable to toggle fullscreen mode\n"); + } +} + +int main(int argc, char *argv[]) +{ + InitVideo(argc, argv); + InitInput(); + Redraw(); + + SDL_Event event; + int done = 0; + + while (! done && SDL_WaitEvent(&event)) + { + switch (event.type) + { + case SDL_KEYDOWN: + if (event.key.keysym.sym == SDLK_ESCAPE) { + done = 1; + break; + } + + fprintf(stderr, + "Keyboard %d: scancode 0x%08X = %s, keycode 0x%08X = %s\n", + event.key.which, event.key.keysym.scancode, + SDL_GetScancodeName(event.key.keysym.scancode), + event.key.keysym.sym, SDL_GetKeyName(event.key.keysym.sym)); + break; + + case SDL_TEXTINPUT: + if (strlen(event.text.text) == 0 || event.text.text[0] == '\n' || + markedRect.w < 0) + break; + + fprintf(stderr, "Keyboard %d: text input \"%s\"\n", + event.text.which, event.text.text); + + if (strlen(text) + strlen(event.text.text) < sizeof(text)) + strcpy(text + strlen(text), event.text.text); + + fprintf(stderr, "text inputed: %s\n", text); + + // After text inputed, we can clear up markedText because it + // is committed + markedText = NULL; + Redraw(); + break; + + case SDL_TEXTEDITING: + fprintf(stderr, "text editing \"%s\", selected range (%d, %d)\n", + event.edit.text, event.edit.start, event.edit.length); + + markedText = event.edit.text; + Redraw(); + break; + + case SDL_QUIT: + done = 1; + break; + + default: + break; + } + } + + CleanupVideo(); + return 0; +}