From f08136a7f8f17778ce642177ecb6c3e80079cc33 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sat, 19 Sep 2009 13:29:40 +0000 Subject: [PATCH] Merged a cleaned up version of Jiang's code changes from Google Summer of Code 2009 --- build-scripts/showrev.sh | 3 + include/SDL_events.h | 17 ++ include/SDL_keyboard.h | 28 +++ src/SDL_compat.c | 15 +- src/events/SDL_keyboard.c | 18 ++ src/events/SDL_keyboard_c.h | 3 + src/video/SDL_sysvideo.h | 5 + src/video/SDL_video.c | 28 +++ src/video/cocoa/SDL_cocoaevents.m | 4 + src/video/cocoa/SDL_cocoakeyboard.h | 4 + src/video/cocoa/SDL_cocoakeyboard.m | 186 +++++++++++++++++-- src/video/cocoa/SDL_cocoamodes.m | 2 + src/video/cocoa/SDL_cocoavideo.h | 4 +- src/video/cocoa/SDL_cocoavideo.m | 4 + test/Makefile.in | 5 +- test/configure.in | 18 ++ test/testime.c | 275 ++++++++++++++++++++++++++++ 17 files changed, 605 insertions(+), 14 deletions(-) create mode 100644 test/testime.c diff --git a/build-scripts/showrev.sh b/build-scripts/showrev.sh index 682bf7278..a33ac7c79 100755 --- a/build-scripts/showrev.sh +++ b/build-scripts/showrev.sh @@ -9,4 +9,7 @@ if [ -d $srcdir/.svn ]; then (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 --git a/include/SDL_events.h b/include/SDL_events.h index e9e8d07d6..be199dcf9 100644 --- a/include/SDL_events.h +++ b/include/SDL_events.h @@ -60,6 +60,7 @@ typedef enum 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 @@ typedef enum 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), @@ -148,6 +150,20 @@ typedef struct SDL_KeyboardEvent SDL_keysym keysym; /**< The key that was pressed or released */ } 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 * @@ -350,6 +366,7 @@ typedef union SDL_Event 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 --git a/include/SDL_keyboard.h b/include/SDL_keyboard.h index 28737ee0e..a0b5b99d9 100644 --- a/include/SDL_keyboard.h +++ b/include/SDL_keyboard.h @@ -154,6 +154,34 @@ extern DECLSPEC const char *SDLCALL SDL_GetScancodeName(SDL_scancode */ 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 --git a/src/SDL_compat.c b/src/SDL_compat.c index fb15a89e3..6b485ef90 100644 --- a/src/SDL_compat.c +++ b/src/SDL_compat.c @@ -40,6 +40,7 @@ static SDL_GLContext *SDL_VideoContext = NULL; 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 @@ SDL_GetKeyRepeat(int *delay, int *interval) 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 --git a/src/events/SDL_keyboard.c b/src/events/SDL_keyboard.c index 8f9692151..5aaeb177d 100644 --- a/src/events/SDL_keyboard.c +++ b/src/events/SDL_keyboard.c @@ -852,6 +852,24 @@ SDL_SendKeyboardText(int index, const char *text) 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 --git a/src/events/SDL_keyboard_c.h b/src/events/SDL_keyboard_c.h index a6f44c1aa..a067494ef 100644 --- a/src/events/SDL_keyboard_c.h +++ b/src/events/SDL_keyboard_c.h @@ -81,6 +81,9 @@ extern int SDL_SendKeyboardKey(int index, Uint8 state, SDL_scancode scancode); /* 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 --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index d8c819ca3..b6bab03ea 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -277,6 +277,11 @@ struct SDL_VideoDevice /* 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 --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 604e598db..5a3a8d487 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -3233,4 +3233,32 @@ SDL_GetWindowWMInfo(SDL_WindowID windowID, struct SDL_SysWMinfo *info) 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 --git a/src/video/cocoa/SDL_cocoaevents.m b/src/video/cocoa/SDL_cocoaevents.m index 9a03cc2a2..4a74de08b 100644 --- a/src/video/cocoa/SDL_cocoaevents.m +++ b/src/video/cocoa/SDL_cocoaevents.m @@ -193,6 +193,10 @@ - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sende 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 --git a/src/video/cocoa/SDL_cocoakeyboard.h b/src/video/cocoa/SDL_cocoakeyboard.h index 665db500c..1dc53df1c 100644 --- a/src/video/cocoa/SDL_cocoakeyboard.h +++ b/src/video/cocoa/SDL_cocoakeyboard.h @@ -28,6 +28,10 @@ extern void Cocoa_InitKeyboard(_THIS); 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 --git a/src/video/cocoa/SDL_cocoakeyboard.m b/src/video/cocoa/SDL_cocoakeyboard.m index 2d981aa1c..dd6b6e672 100644 --- a/src/video/cocoa/SDL_cocoakeyboard.m +++ b/src/video/cocoa/SDL_cocoakeyboard.m @@ -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 @@ - (void) doCommandBySelector:(SEL) myselector {} { 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); @@ -497,6 +622,47 @@ - (void) doCommandBySelector:(SEL) myselector {} SDL_SetScancodeName(SDL_SCANCODE_RGUI, "Right Command"); } +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) { @@ -533,11 +699,13 @@ - (void) doCommandBySelector:(SEL) myselector {} 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 @@ - (void) doCommandBySelector:(SEL) myselector {} NSAutoreleasePool *pool; SDL_DelKeyboard(data->keyboard); - - pool = [[NSAutoreleasePool alloc] init]; - [data->fieldEdit release]; - [pool release]; } /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/cocoa/SDL_cocoamodes.m b/src/video/cocoa/SDL_cocoamodes.m index 8eae6cc7a..5afdd668d 100644 --- a/src/video/cocoa/SDL_cocoamodes.m +++ b/src/video/cocoa/SDL_cocoamodes.m @@ -250,6 +250,8 @@ - (void) setFrame:(NSRect)frame; 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 --git a/src/video/cocoa/SDL_cocoavideo.h b/src/video/cocoa/SDL_cocoavideo.h index 14d886562..13fa7d214 100644 --- a/src/video/cocoa/SDL_cocoavideo.h +++ b/src/video/cocoa/SDL_cocoavideo.h @@ -41,6 +41,8 @@ /* Private display data */ +@class SDLTranslatorResponder; + typedef struct SDL_VideoData { SInt32 osversion; @@ -48,7 +50,7 @@ typedef struct SDL_VideoData int mouse; int keyboard; void *key_layout; - NSText *fieldEdit; + SDLTranslatorResponder *fieldEdit; Uint32 screensaver_activity; } SDL_VideoData; diff --git a/src/video/cocoa/SDL_cocoavideo.m b/src/video/cocoa/SDL_cocoavideo.m index 331e6abad..b61fb29a3 100644 --- a/src/video/cocoa/SDL_cocoavideo.m +++ b/src/video/cocoa/SDL_cocoavideo.m @@ -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 --git a/test/Makefile.in b/test/Makefile.in index ad4e5c51f..27f4ab6ef 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -7,7 +7,7 @@ EXE = @EXE@ 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 @@ testmmousetablet$(EXE): $(srcdir)/testmmousetablet.c 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 --git a/test/configure.in b/test/configure.in index b84202c09..fa13dc941 100644 --- a/test/configure.in +++ b/test/configure.in @@ -128,5 +128,23 @@ fi 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 --git a/test/testime.c b/test/testime.c new file mode 100644 index 000000000..d4a980cae --- /dev/null +++ b/test/testime.c @@ -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; +}