GameChatKeyboardHanlder.m 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /*
  2. * GameChatKeyboardHanlder.m, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #import "GameChatKeyboardHanlder.h"
  11. #include <SDL_events.h>
  12. static int watchReturnKey(void * userdata, SDL_Event * event);
  13. static void sendKeyEvent(SDL_KeyCode keyCode)
  14. {
  15. SDL_Event keyEvent;
  16. keyEvent.key = (SDL_KeyboardEvent){
  17. .type = SDL_KEYDOWN,
  18. .keysym.sym = keyCode,
  19. };
  20. SDL_PushEvent(&keyEvent);
  21. }
  22. static CGRect keyboardFrame(NSNotification * n, NSString * userInfoKey)
  23. {
  24. return [n.userInfo[userInfoKey] CGRectValue];
  25. }
  26. static CGRect keyboardFrameBegin(NSNotification * n) { return keyboardFrame(n, UIKeyboardFrameBeginUserInfoKey); }
  27. static CGRect keyboardFrameEnd (NSNotification * n) { return keyboardFrame(n, UIKeyboardFrameEndUserInfoKey); }
  28. @interface GameChatKeyboardHanlder ()
  29. @property (nonatomic) BOOL wasChatMessageSent;
  30. @end
  31. @implementation GameChatKeyboardHanlder
  32. - (void)triggerInput {
  33. __auto_type notificationCenter = NSNotificationCenter.defaultCenter;
  34. [notificationCenter addObserver:self selector:@selector(textDidBeginEditing:) name:UITextFieldTextDidBeginEditingNotification object:nil];
  35. [notificationCenter addObserver:self selector:@selector(textDidEndEditing:) name:UITextFieldTextDidEndEditingNotification object:nil];
  36. [notificationCenter addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
  37. [notificationCenter addObserver:self selector:@selector(keyboardDidChangeFrame:) name:UIKeyboardDidChangeFrameNotification object:nil];
  38. self.wasChatMessageSent = NO;
  39. sendKeyEvent(SDLK_TAB);
  40. }
  41. - (void)positionTextFieldAboveKeyboardRect:(CGRect)kbFrame {
  42. __auto_type r = kbFrame;
  43. r.size.height = CGRectGetHeight(self.textFieldSDL.frame);
  44. r.origin.y -= r.size.height;
  45. self.textFieldSDL.frame = r;
  46. }
  47. #pragma mark - Notifications
  48. - (void)textDidBeginEditing:(NSNotification *)n {
  49. self.textFieldSDL.hidden = NO;
  50. self.textFieldSDL.text = nil;
  51. // watch for pressing Return to ignore sending Escape key after keyboard is closed
  52. SDL_AddEventWatch(watchReturnKey, (__bridge void *)self);
  53. }
  54. - (void)textDidEndEditing:(NSNotification *)n {
  55. [NSNotificationCenter.defaultCenter removeObserver:self];
  56. self.textFieldSDL.hidden = YES;
  57. // discard chat message
  58. if(!self.wasChatMessageSent)
  59. sendKeyEvent(SDLK_ESCAPE);
  60. }
  61. - (void)keyboardWillChangeFrame:(NSNotification *)n {
  62. // animate textfield together with keyboard
  63. [UIView performWithoutAnimation:^{
  64. [self positionTextFieldAboveKeyboardRect:keyboardFrameBegin(n)];
  65. }];
  66. NSTimeInterval kbAnimationDuration = [n.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
  67. NSUInteger kbAnimationCurve = [n.userInfo[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue];
  68. [UIView animateWithDuration:kbAnimationDuration delay:0 options:(kbAnimationCurve << 16) animations:^{
  69. [self positionTextFieldAboveKeyboardRect:keyboardFrameEnd(n)];
  70. } completion:nil];
  71. }
  72. - (void)keyboardDidChangeFrame:(NSNotification *)n {
  73. [self positionTextFieldAboveKeyboardRect:keyboardFrameEnd(n)];
  74. }
  75. @end
  76. static int watchReturnKey(void * userdata, SDL_Event * event)
  77. {
  78. if(event->type == SDL_KEYDOWN && event->key.keysym.scancode == SDL_SCANCODE_RETURN)
  79. {
  80. __auto_type self = (__bridge GameChatKeyboardHanlder *)userdata;
  81. self.wasChatMessageSent = YES;
  82. SDL_DelEventWatch(watchReturnKey, userdata);
  83. }
  84. return 1;
  85. }