mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
show SDL's textfield above the keyboard for game chat, extract handling to separate class
kambala-decapitator/vcmi#4 kambala-decapitator/vcmi#31
This commit is contained in:
parent
217c83a7e7
commit
f97ff108a7
@ -147,11 +147,13 @@ set(client_HEADERS
|
||||
|
||||
if(APPLE_IOS)
|
||||
set(client_SRCS ${client_SRCS}
|
||||
SDL_uikit_main.mm
|
||||
CFocusableHelper.cpp
|
||||
ios/GameChatKeyboardHanlder.m
|
||||
ios/SDL_uikit_main.mm
|
||||
)
|
||||
set(client_HEADERS ${client_HEADERS}
|
||||
CFocusableHelper.h
|
||||
ios/GameChatKeyboardHanlder.h
|
||||
)
|
||||
endif()
|
||||
|
||||
|
23
client/ios/GameChatKeyboardHanlder.h
Normal file
23
client/ios/GameChatKeyboardHanlder.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* GameChatKeyboardHanlder.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface GameChatKeyboardHanlder : NSObject
|
||||
|
||||
@property (nonatomic, weak) UITextField * textFieldSDL;
|
||||
|
||||
- (void)triggerInput;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
107
client/ios/GameChatKeyboardHanlder.m
Normal file
107
client/ios/GameChatKeyboardHanlder.m
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* GameChatKeyboardHanlder.m, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#import "GameChatKeyboardHanlder.h"
|
||||
|
||||
#include <SDL_events.h>
|
||||
|
||||
static int watchReturnKey(void * userdata, SDL_Event * event);
|
||||
|
||||
static void sendKeyEvent(SDL_KeyCode keyCode)
|
||||
{
|
||||
SDL_Event keyEvent;
|
||||
keyEvent.key = (SDL_KeyboardEvent){
|
||||
.type = SDL_KEYDOWN,
|
||||
.keysym.sym = keyCode,
|
||||
};
|
||||
SDL_PushEvent(&keyEvent);
|
||||
}
|
||||
|
||||
static CGRect keyboardFrame(NSNotification * n, NSString * userInfoKey)
|
||||
{
|
||||
return [n.userInfo[userInfoKey] CGRectValue];
|
||||
}
|
||||
static CGRect keyboardFrameBegin(NSNotification * n) { return keyboardFrame(n, UIKeyboardFrameBeginUserInfoKey); }
|
||||
static CGRect keyboardFrameEnd (NSNotification * n) { return keyboardFrame(n, UIKeyboardFrameEndUserInfoKey); }
|
||||
|
||||
|
||||
@interface GameChatKeyboardHanlder ()
|
||||
@property (nonatomic) BOOL wasChatMessageSent;
|
||||
@end
|
||||
|
||||
@implementation GameChatKeyboardHanlder
|
||||
|
||||
- (void)triggerInput {
|
||||
__auto_type notificationCenter = NSNotificationCenter.defaultCenter;
|
||||
[notificationCenter addObserver:self selector:@selector(textDidBeginEditing:) name:UITextFieldTextDidBeginEditingNotification object:nil];
|
||||
[notificationCenter addObserver:self selector:@selector(textDidEndEditing:) name:UITextFieldTextDidEndEditingNotification object:nil];
|
||||
[notificationCenter addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil];
|
||||
[notificationCenter addObserver:self selector:@selector(keyboardDidChangeFrame:) name:UIKeyboardDidChangeFrameNotification object:nil];
|
||||
|
||||
self.wasChatMessageSent = NO;
|
||||
sendKeyEvent(SDLK_TAB);
|
||||
}
|
||||
|
||||
- (void)positionTextFieldAboveKeyboardRect:(CGRect)kbFrame {
|
||||
__auto_type r = kbFrame;
|
||||
r.size.height = CGRectGetHeight(self.textFieldSDL.frame);
|
||||
r.origin.y -= r.size.height;
|
||||
self.textFieldSDL.frame = r;
|
||||
}
|
||||
|
||||
#pragma mark - Notifications
|
||||
|
||||
- (void)textDidBeginEditing:(NSNotification *)n {
|
||||
self.textFieldSDL.hidden = NO;
|
||||
self.textFieldSDL.text = nil;
|
||||
|
||||
// watch for pressing Return to ignore sending Escape key after keyboard is closed
|
||||
SDL_AddEventWatch(watchReturnKey, (__bridge void *)self);
|
||||
}
|
||||
|
||||
- (void)textDidEndEditing:(NSNotification *)n {
|
||||
[NSNotificationCenter.defaultCenter removeObserver:self];
|
||||
self.textFieldSDL.hidden = YES;
|
||||
|
||||
// discard chat message
|
||||
if(!self.wasChatMessageSent)
|
||||
sendKeyEvent(SDLK_ESCAPE);
|
||||
}
|
||||
|
||||
- (void)keyboardWillChangeFrame:(NSNotification *)n {
|
||||
// animate textfield together with keyboard
|
||||
[UIView performWithoutAnimation:^{
|
||||
[self positionTextFieldAboveKeyboardRect:keyboardFrameBegin(n)];
|
||||
}];
|
||||
|
||||
NSTimeInterval kbAnimationDuration = [n.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
|
||||
NSUInteger kbAnimationCurve = [n.userInfo[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue];
|
||||
[UIView animateWithDuration:kbAnimationDuration delay:0 options:(kbAnimationCurve << 16) animations:^{
|
||||
[self positionTextFieldAboveKeyboardRect:keyboardFrameEnd(n)];
|
||||
} completion:nil];
|
||||
}
|
||||
|
||||
- (void)keyboardDidChangeFrame:(NSNotification *)n {
|
||||
[self positionTextFieldAboveKeyboardRect:keyboardFrameEnd(n)];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
static int watchReturnKey(void * userdata, SDL_Event * event)
|
||||
{
|
||||
if(event->type == SDL_KEYDOWN && event->key.keysym.scancode == SDL_SCANCODE_RETURN)
|
||||
{
|
||||
__auto_type self = (__bridge GameChatKeyboardHanlder *)userdata;
|
||||
self.wasChatMessageSent = YES;
|
||||
SDL_DelEventWatch(watchReturnKey, userdata);
|
||||
}
|
||||
return 1;
|
||||
}
|
@ -13,35 +13,38 @@
|
||||
#include "CServerHandler.h"
|
||||
#include "CFocusableHelper.h"
|
||||
|
||||
#import "GameChatKeyboardHanlder.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
double ios_screenScale() { return UIScreen.mainScreen.nativeScale; }
|
||||
|
||||
|
||||
static int watchReturnKey(void * userdata, SDL_Event * event);
|
||||
|
||||
static void sendKeyEvent(SDL_KeyCode keyCode)
|
||||
{
|
||||
SDL_Event keyEvent;
|
||||
keyEvent.key = (SDL_KeyboardEvent){
|
||||
.type = SDL_KEYDOWN,
|
||||
.keysym.sym = keyCode,
|
||||
};
|
||||
SDL_PushEvent(&keyEvent);
|
||||
}
|
||||
|
||||
|
||||
@interface SDLViewObserver : NSObject <UIGestureRecognizerDelegate>
|
||||
@property (nonatomic) bool wasChatMessageSent;
|
||||
@property (nonatomic, strong) GameChatKeyboardHanlder * gameChatHandler;
|
||||
@end
|
||||
|
||||
@implementation SDLViewObserver
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
|
||||
UIView * view = [object valueForKey:keyPath];
|
||||
UIView * view = [object valueForKeyPath:keyPath];
|
||||
|
||||
UITextField * textField;
|
||||
for (UIView * v in view.subviews) {
|
||||
if ([v isKindOfClass:[UITextField class]]) {
|
||||
textField = (UITextField *)v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto r = textField.frame;
|
||||
r.size.height = 40;
|
||||
textField.frame = r;
|
||||
textField.backgroundColor = UIColor.whiteColor;
|
||||
self.gameChatHandler.textFieldSDL = textField;
|
||||
|
||||
auto longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
|
||||
longPress.minimumPressDuration = 0.1;
|
||||
longPress.minimumPressDuration = 0.2;
|
||||
[view addGestureRecognizer:longPress];
|
||||
|
||||
auto pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)];
|
||||
@ -102,29 +105,7 @@ static void sendKeyEvent(SDL_KeyCode keyCode)
|
||||
- (void)handlePinch:(UIGestureRecognizer *)gesture {
|
||||
if(gesture.state != UIGestureRecognizerStateBegan || CSH->state != EClientState::GAMEPLAY)
|
||||
return;
|
||||
|
||||
// Tab triggers chat message input
|
||||
self.wasChatMessageSent = false;
|
||||
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(handleKeyboardDidShowForGameChat:) name:UIKeyboardDidShowNotification object:nil];
|
||||
sendKeyEvent(SDLK_TAB);
|
||||
}
|
||||
|
||||
#pragma mark - Notifications
|
||||
|
||||
- (void)handleKeyboardDidShowForGameChat:(NSNotification *)n {
|
||||
[NSNotificationCenter.defaultCenter removeObserver:self name:n.name object:nil];
|
||||
|
||||
// watch for pressing Return to ignore sending Escape key after keyboard is closed
|
||||
SDL_AddEventWatch(watchReturnKey, (__bridge void *)self);
|
||||
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(handleKeyboardDidHideForGameChat:) name:UIKeyboardDidHideNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)handleKeyboardDidHideForGameChat:(NSNotification *)n {
|
||||
[NSNotificationCenter.defaultCenter removeObserver:self name:n.name object:nil];
|
||||
|
||||
// discard chat message
|
||||
if(!self.wasChatMessageSent)
|
||||
sendKeyEvent(SDLK_ESCAPE);
|
||||
[self.gameChatHandler triggerInput];
|
||||
}
|
||||
|
||||
#pragma mark - UIGestureRecognizerDelegate
|
||||
@ -146,6 +127,7 @@ main(int argc, char *argv[])
|
||||
@autoreleasepool
|
||||
{
|
||||
auto observer = [SDLViewObserver new];
|
||||
observer.gameChatHandler = [GameChatKeyboardHanlder new];
|
||||
[NSNotificationCenter.defaultCenter addObserverForName:UIWindowDidBecomeKeyNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
|
||||
[UIApplication.sharedApplication.keyWindow.rootViewController addObserver:observer forKeyPath:NSStringFromSelector(@selector(view)) options:NSKeyValueObservingOptionNew context:NULL];
|
||||
}];
|
||||
@ -155,14 +137,3 @@ main(int argc, char *argv[])
|
||||
return SDL_UIKitRunApp(argc, argv, SDL_main);
|
||||
}
|
||||
}
|
||||
|
||||
static int watchReturnKey(void * userdata, SDL_Event * event)
|
||||
{
|
||||
if(event->type == SDL_KEYDOWN && event->key.keysym.scancode == SDL_SCANCODE_RETURN)
|
||||
{
|
||||
auto self = (__bridge SDLViewObserver *)userdata;
|
||||
self.wasChatMessageSent = true;
|
||||
SDL_DelEventWatch(watchReturnKey, userdata);
|
||||
}
|
||||
return 1;
|
||||
}
|
Loading…
Reference in New Issue
Block a user