Support for input cursor movement from keyboard

New class: TrackedTextField. This class keeps track of the pointer in the text field. The hidden text field now has 40 placeholder spaces and the pointer is placed at the middle. When typing, placeholder spaces won't get removed as before. Autocorrect seem to be broken a bit for now.

Additional changes:
- Added missing GLFW functions (array version of other functions)
- Hotbar handling: doubled barWidth and barHeight

Bug fix:
- Touching onto the hotbar breaks the handling of on-screen tap/long-press gestures
This commit is contained in:
khanhduytran0 committed 2022-01-11 13:58:16 +07:00
1 parent 51b55b0e07
commit 82dc17cd9c
3 files changed
+240 -109

No files matched your search

+147 -49
View File
@@ -835,29 +835,18 @@ public class GLFW
}
width.put(internalGetWindow(window).width);
height.put(internalGetWindow(window).height);
}
public static void glfwGetFramebufferSize(@NativeType("GLFWwindow *") long window, @Nullable @NativeType("int *") int[] width, @Nullable @NativeType("int *") int[] height) {
if (CHECKS) {
// check(window);
checkSafe(width, 1);
checkSafe(height, 1);
}
width[0] = internalGetWindow(window).width;
height[0] = internalGetWindow(window).height;
}
@Nullable
@Nullable
@NativeType("GLFWmonitor **")
public static PointerBuffer glfwGetMonitors() {
PointerBuffer pBuffer = PointerBuffer.allocateDirect(1);
pBuffer.put(glfwGetPrimaryMonitor());
return pBuffer;
pBuffer.put(glfwGetPrimaryMonitor());
return pBuffer;
}
public static long glfwGetPrimaryMonitor() {
// Prevent NULL check
// Prevent NULL check
return 1L;
}
@@ -885,44 +874,17 @@ public class GLFW
height.put(mGLFWWindowHeight);
}
public static void glfwGetMonitorPos(@NativeType("GLFWmonitor *") long monitor, @Nullable @NativeType("int *") int[] xpos, @Nullable @NativeType("int *") int[] ypos) {
if (CHECKS) {
// check(monitor);
checkSafe(xpos, 1);
checkSafe(ypos, 1);
}
xpos[0] = 0;
ypos[0] = 0;
}
/** Array version of: {@link #glfwGetMonitorWorkarea GetMonitorWorkarea} */
public static void glfwGetMonitorWorkarea(@NativeType("GLFWmonitor *") long monitor, @Nullable @NativeType("int *") int[] xpos, @Nullable @NativeType("int *") int[] ypos, @Nullable @NativeType("int *") int[] width, @Nullable @NativeType("int *") int[] height) {
if (CHECKS) {
// check(monitor);
checkSafe(xpos, 1);
checkSafe(ypos, 1);
checkSafe(width, 1);
checkSafe(height, 1);
}
xpos[0] = 0;
ypos[0] = 0;
width[0] = mGLFWWindowWidth;
height[0] = mGLFWWindowHeight;
}
@NativeType("GLFWmonitor *")
public static long glfwGetWindowMonitor(@NativeType("GLFWwindow *") long window) {
return internalGetWindow(window).monitor;
}
public static void glfwSetWindowMonitor(@NativeType("GLFWwindow *") long window, @NativeType("GLFWmonitor *") long monitor, int xpos, int ypos, int width, int height, int refreshRate) {
GLFWWindowProperties properties = internalGetWindow(window);
properties.monitor = monitor;
properties.x = xpos;
properties.y = ypos;
internalChangeMonitorSize(width, height);
public static void glfwSetWindowMonitor(@NativeType("GLFWwindow *") long window, @NativeType("GLFWmonitor *") long monitor, int xpos, int ypos, int width, int height, int refreshRate) {
GLFWWindowProperties properties = internalGetWindow(window);
properties.monitor = monitor;
properties.x = xpos;
properties.y = ypos;
internalChangeMonitorSize(width, height);
}
public static int glfwGetWindowAttrib(@NativeType("GLFWwindow *") long window, int attrib) {
@@ -1317,4 +1279,140 @@ return false;
public static boolean glfwGetGamepadState(int jid, GLFWGamepadState state) {
return false;
}
/** Array version of: {@link #glfwGetVersion GetVersion} */
public static void glfwGetVersion(@Nullable @NativeType("int *") int[] major, @Nullable @NativeType("int *") int[] minor, @Nullable @NativeType("int *") int[] rev) {
if (CHECKS) {
checkSafe(major, 1);
checkSafe(minor, 1);
checkSafe(rev, 1);
}
major[0] = GLFW_VERSION_MAJOR;
minor[0] = GLFW_VERSION_MINOR;
rev[0] = GLFW_VERSION_REVISION;
}
/** Array version of: {@link #glfwGetMonitorPos GetMonitorPos} */
public static void glfwGetMonitorPos(@NativeType("GLFWmonitor *") long monitor, @Nullable @NativeType("int *") int[] xpos, @Nullable @NativeType("int *") int[] ypos) {
if (CHECKS) {
// check(monitor);
checkSafe(xpos, 1);
checkSafe(ypos, 1);
}
xpos[0] = 0;
ypos[0] = 0;
}
/** Array version of: {@link #glfwGetMonitorWorkarea GetMonitorWorkarea} */
public static void glfwGetMonitorWorkarea(@NativeType("GLFWmonitor *") long monitor, @Nullable @NativeType("int *") int[] xpos, @Nullable @NativeType("int *") int[] ypos, @Nullable @NativeType("int *") int[] width, @Nullable @NativeType("int *") int[] height) {
if (CHECKS) {
// check(monitor);
checkSafe(xpos, 1);
checkSafe(ypos, 1);
checkSafe(width, 1);
checkSafe(height, 1);
}
xpos[0] = 0;
ypos[0] = 0;
width[0] = mGLFWWindowWidth;
height[0] = mGLFWWindowHeight;
}
/** Array version of: {@link #glfwGetMonitorPhysicalSize GetMonitorPhysicalSize} */
/*
public static void glfwGetMonitorPhysicalSize(@NativeType("GLFWmonitor *") long monitor, @Nullable @NativeType("int *") int[] widthMM, @Nullable @NativeType("int *") int[] heightMM) {
long __functionAddress = Functions.GetMonitorPhysicalSize;
if (CHECKS) {
check(monitor);
checkSafe(widthMM, 1);
checkSafe(heightMM, 1);
}
invokePPPV(monitor, widthMM, heightMM, __functionAddress);
}
*/
/** Array version of: {@link #glfwGetMonitorContentScale GetMonitorContentScale} */
/*
public static void glfwGetMonitorContentScale(@NativeType("GLFWmonitor *") long monitor, @Nullable @NativeType("float *") float[] xscale, @Nullable @NativeType("float *") float[] yscale) {
long __functionAddress = Functions.GetMonitorContentScale;
if (CHECKS) {
check(monitor);
checkSafe(xscale, 1);
checkSafe(yscale, 1);
}
invokePPPV(monitor, xscale, yscale, __functionAddress);
}
*/
/** Array version of: {@link #glfwGetWindowPos GetWindowPos} */
public static void glfwGetWindowPos(@NativeType("GLFWwindow *") long window, @Nullable @NativeType("int *") int[] xpos, @Nullable @NativeType("int *") int[] ypos) {
if (CHECKS) {
// check(window);
checkSafe(xpos, 1);
checkSafe(ypos, 1);
}
xpos[0] = 0;
ypos[0] = 0;
}
/** Array version of: {@link #glfwGetWindowSize GetWindowSize} */
public static void glfwGetWindowSize(@NativeType("GLFWwindow *") long window, @Nullable @NativeType("int *") int[] width, @Nullable @NativeType("int *") int[] height) {
if (CHECKS) {
// check(window);
checkSafe(width, 1);
checkSafe(height, 1);
}
width[0] = internalGetWindow(window).width;
height[0] = internalGetWindow(window).height;
}
/** Array version of: {@link #glfwGetFramebufferSize GetFramebufferSize} */
public static void glfwGetFramebufferSize(@NativeType("GLFWwindow *") long window, @Nullable @NativeType("int *") int[] width, @Nullable @NativeType("int *") int[] height) {
if (CHECKS) {
// check(window);
checkSafe(width, 1);
checkSafe(height, 1);
}
width[0] = internalGetWindow(window).width;
height[0] = internalGetWindow(window).height;
}
/** Array version of: {@link #glfwGetWindowFrameSize GetWindowFrameSize} */
public static void glfwGetWindowFrameSize(@NativeType("GLFWwindow *") long window, @Nullable @NativeType("int *") int[] left, @Nullable @NativeType("int *") int[] top, @Nullable @NativeType("int *") int[] right, @Nullable @NativeType("int *") int[] bottom) {
if (CHECKS) {
// check(window);
checkSafe(left, 1);
checkSafe(top, 1);
checkSafe(right, 1);
checkSafe(bottom, 1);
}
left[0] = top[0] = 0;
right[0] = internalGetWindow(window).width;
bottom[0] = internalGetWindow(window).height;
}
/** Array version of: {@link #glfwGetWindowContentScale GetWindowContentScale} */
/*
public static void glfwGetWindowContentScale(@NativeType("GLFWwindow *") long window, @Nullable @NativeType("float *") float[] xscale, @Nullable @NativeType("float *") float[] yscale) {
long __functionAddress = Functions.GetWindowContentScale;
if (CHECKS) {
check(window);
checkSafe(xscale, 1);
checkSafe(yscale, 1);
}
invokePPPV(window, xscale, yscale, __functionAddress);
}
*/
/** Array version of: {@link #glfwGetCursorPos GetCursorPos} */
public static void glfwGetCursorPos(@NativeType("GLFWwindow *") long window, @Nullable @NativeType("double *") double[] xpos, @Nullable @NativeType("double *") double[] ypos) {
if (CHECKS) {
// check(window);
checkSafe(xpos, 1);
checkSafe(ypos, 1);
}
xpos[0] = mGLFWCursorX;
ypos[0] = mGLFWCursorY;
}
}
+91 -58
View File
@@ -24,13 +24,13 @@
// #define DEBUG_VISIBLE_TEXT_FIELD
// #define DEBUG_VISIBLE_TOUCH
#define INPUT_SPACE_CHAR @" "
#define INPUT_SPACE_CHAR @" "
#define INPUT_FULL_LENGTH 40
#define INPUT_SPACE_LENGTH 20
#ifdef DEBUG_VISIBLE_TEXT_FIELD
UILabel *inputLengthView;
#endif
UITextField *inputView;
int inputTextLength;
BOOL shouldTriggerClick = NO;
@@ -41,6 +41,7 @@ BOOL slideableHotbar;
// TODO: key modifiers impl
#pragma mark Class GameSurfaceView
@implementation GameSurfaceView
const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) {
return gbuffer;
@@ -84,9 +85,39 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) {
@end
#pragma mark Class TrackedTextField
@interface TrackedTextField : UITextField
@property int lastPosition;
@property UITextPosition* lockPos;
@end
@implementation TrackedTextField
- (UITextPosition *)closestPositionToPoint:(CGPoint)point {
UITextPosition *position = [super closestPositionToPoint:point];
int start = [self offsetFromPosition:self.beginningOfDocument toPosition:position];
if (start - self.lastPosition != 0) {
int key = (start - self.lastPosition > 0) ? GLFW_KEY_DPAD_RIGHT : GLFW_KEY_DPAD_LEFT;
CallbackBridge_nativeSendKey(key, 0, 1, 0);
CallbackBridge_nativeSendKey(key, 0, 0, 0);
}
self.lastPosition = start;
return [self positionFromPosition:self.beginningOfDocument offset:clamp(start, 20, self.text.length - 20)];
}
- (void)setText:(NSString *)text {
[super setText:text];
self.lockPos = [self positionFromPosition:self.beginningOfDocument offset:20];
self.selectedTextRange = [self textRangeFromPosition:self.lockPos toPosition:self.lockPos];
}
@end
#pragma mark Class SurfaceViewController
@interface SurfaceViewController ()<UITextFieldDelegate, UIPointerInteractionDelegate, UIGestureRecognizerDelegate> {
}
@property TrackedTextField *inputView;
@property(nonatomic, strong) NSMutableDictionary* cc_dictionary;
@property(nonatomic, strong) NSMutableArray* swipeableButtons;
@property(nonatomic, strong) NSMutableArray* togglableVisibleButtons;
@@ -193,21 +224,19 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) {
[self.view addSubview:self.mousePointerView];
#ifndef DEBUG_VISIBLE_TEXT_FIELD
inputView = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 1, 1)];
inputView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.0f];
self.inputView = [[TrackedTextField alloc] initWithFrame:CGRectMake(0, -1, 1, 1)];
#else
inputView = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 1, 1)];
inputView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.5f];
self.inputView = [[TrackedTextField alloc] initWithFrame:CGRectMake(5 * 2 + 160.0, 5 * 2 + 30.0, 200.0, 30.0)];
self.inputView.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.5f];
inputLengthView = [[UILabel alloc] initWithFrame:CGRectMake(5 * 2 + 80.0, 5 * 2 + 30.0, 80.0, 30.0)];
inputLengthView.text = @"length=?";
inputLengthView.backgroundColor = [UIColor colorWithWhite:1.0f alpha:0.6f];
[self.view addSubview:inputLengthView];
#endif
inputView.delegate = self;
[inputView addTarget:self action:@selector(inputViewDidChange) forControlEvents:UIControlEventEditingChanged];
[inputView addTarget:self action:@selector(inputViewDidClick) forControlEvents:UIControlEventTouchDown];
self.inputView.delegate = self;
self.inputView.lastPosition = 20;
[self.inputView addTarget:self action:@selector(inputViewDidChange) forControlEvents:UIControlEventEditingChanged];
NSString *controlFilePath = [NSString stringWithFormat:@"%s/%@", getenv("POJAV_PATH_CONTROL"), (NSString *)getPreference(@"default_ctrl")];
@@ -233,9 +262,6 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) {
BOOL isToggleCtrlBtn = NO;
for (int i = 0; i < 4; i++) {
int keycodeInt = [button.properties[@"keycodes"][i] intValue];
if (keycodeInt == SPECIALBTN_KEYBOARD) {
inputView.frame = button.frame;
}
if (keycodeInt == SPECIALBTN_TOGGLECTRL) {
isToggleCtrlBtn = YES;
}
@@ -281,7 +307,7 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) {
}
}
[self.view addSubview:inputView];
[self.view addSubview:self.inputView];
[self executebtn_special_togglebtn:0];
@@ -445,7 +471,7 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) {
if (shouldTriggerClick == NO) return;
if (sender.state == UIGestureRecognizerStateRecognized) {
if (currentHotbarSlot == -1) {
inputView.text = INPUT_SPACE_CHAR;
self.inputView.text = INPUT_SPACE_CHAR;
inputTextLength = 0;
CallbackBridge_nativeSendMouseButton(
@@ -503,7 +529,7 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) {
}
if (sender.state == UIGestureRecognizerStateBegan) {
if (currentHotbarSlot == -1) {
inputView.text = INPUT_SPACE_CHAR;
self.inputView.text = INPUT_SPACE_CHAR;
inputTextLength = 0;
CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_LEFT, 1, 0);
@@ -518,7 +544,7 @@ const void * _CGDataProviderGetBytePointerCallbackOSMESA(void *info) {
|| sender.state == UIGestureRecognizerStateEnded)
{
if (currentHotbarSlot == -1) {
inputView.text = INPUT_SPACE_CHAR;
self.inputView.text = INPUT_SPACE_CHAR;
inputTextLength = 0;
CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_LEFT, 0, 0);
@@ -556,22 +582,28 @@ CallbackBridge_nativeSendKey(GLFW_KEY_Q, 0, 0, 0);
#pragma mark - Input view stuff
NSString* inputStringBefore;
int inputStringLength = INPUT_FULL_LENGTH;
-(void)inputViewDidChange {
if ([inputView.text length] < INPUT_SPACE_LENGTH) {
CallbackBridge_nativeSendKey(GLFW_KEY_BACKSPACE, 0, 1, 0);
CallbackBridge_nativeSendKey(GLFW_KEY_BACKSPACE, 0, 0, 0);
inputView.text = [@" " stringByAppendingString:inputView.text];
if (inputTextLength > 0) {
--inputTextLength;
int typedLength = (int)self.inputView.text.length - inputStringLength;
if (typedLength < 0) {
for (int i = 0; i < -typedLength; i++) {
if (self.inputView.text.length < INPUT_FULL_LENGTH) {
self.inputView.text = [@" " stringByAppendingString:self.inputView.text];
}
CallbackBridge_nativeSendKey(GLFW_KEY_BACKSPACE, 0, 1, 0);
CallbackBridge_nativeSendKey(GLFW_KEY_BACKSPACE, 0, 0, 0);
if (inputTextLength > 0) {
--inputTextLength;
}
}
#ifdef DEBUG_VISIBLE_TEXT_FIELD
inputLengthView.text = [@"length=" stringByAppendingFormat:@"%i",
inputLengthView.text = [@"length=" stringByAppendingFormat:@"%i",
inputTextLength];
#endif
} else if ([inputView.text length] > INPUT_SPACE_LENGTH) {
NSString *newText = [inputView.text substringFromIndex:INPUT_SPACE_LENGTH];
} else if (typedLength > 0) {
int index = [self.inputView offsetFromPosition:self.inputView.beginningOfDocument toPosition:self.inputView.selectedTextRange.start];
NSString *newText = [self.inputView.text substringWithRange:NSMakeRange(index - typedLength, typedLength)];
int charLength = (int) [newText length];
for (int i = 0; i < charLength; i++) {
// Directly convert unichar to jchar since both are in UTF-16 encoding.
@@ -583,30 +615,27 @@ NSString* inputStringBefore;
CallbackBridge_nativeSendChar(theChar);
}
inputView.text = [inputView.text substringFromIndex:1];
if (inputTextLength < INPUT_SPACE_LENGTH) {
++inputTextLength;
}
++inputTextLength;
#ifdef DEBUG_VISIBLE_TEXT_FIELD
inputLengthView.text = [@"length=" stringByAppendingFormat:@"%i",
inputTextLength];
#endif
}
inputStringBefore = inputView.text;
// [inputView.text substringFromIndex:inputTextLength - 1];
inputStringBefore = self.inputView.text;
// [self.inputView.text substringFromIndex:inputTextLength - 1];
} else {
#ifdef DEBUG_VISIBLE_TEXT_FIELD
NSLog(@"Compare \"%@\" vs \"%@\"", inputView.text, inputStringBefore);
NSLog(@"Compare \"%@\" vs \"%@\"", self.inputView.text, inputStringBefore);
#endif
for (int i = 0; i < INPUT_SPACE_LENGTH; i++) {
if ([inputView.text characterAtIndex:i] != [inputStringBefore characterAtIndex:i]) {
NSString *inputStringNow = [inputView.text substringFromIndex:i];
for (int i = 0; i < INPUT_FULL_LENGTH; i++) {
if ([self.inputView.text characterAtIndex:i] != [inputStringBefore characterAtIndex:i]) {
NSString *inputStringNow = [self.inputView.text substringFromIndex:i];
/*
inputView.text = [inputView.text substringToIndex:i];
self.inputView.text = [self.inputView.text substringToIndex:i];
// self notify
[self inputViewDidChange];
inputView.text = [inputView.text stringByAppendingString:inputStringNow];
self.inputView.text = [self.inputView.text stringByAppendingString:inputStringNow];
// self notify
[self inputViewDidChange];
*/
@@ -627,21 +656,13 @@ NSString* inputStringBefore;
#ifdef DEBUG_VISIBLE_TEXT_FIELD
inputLengthView.text = @"length =";
#endif
inputStringBefore = inputView.text;
// [inputView.text substringFromIndex:inputTextLength - 1];
inputStringBefore = self.inputView.text;
}
// Reset to default value
// inputView.text = INPUT_SPACE_CHAR;
}
inputStringLength = (int)self.inputView.text.length;
-(void)inputViewDidClick {
// Zero the input field so user will no longer able to select text inside.
#ifndef DEBUG_VISIBLE_TEXT_FIELD
inputView.alpha = 0.0f;
#endif
inputView.text = INPUT_SPACE_CHAR;
inputTextLength = 0;
// Reset to default value
// self.inputView.text = INPUT_SPACE_CHAR;
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField {
@@ -662,9 +683,21 @@ int currentVisibility = 1;
switch (keycode) {
case SPECIALBTN_KEYBOARD:
if (held == 0) {
[inputView resignFirstResponder];
inputView.alpha = 1.0f;
inputView.text = @"";
if (self.inputView.isFirstResponder) {
[self.inputView resignFirstResponder];
self.inputView.alpha = 1.0f;
self.inputView.text = @"";
} else {
[self.inputView becomeFirstResponder];
// Empty the input field so that user will no longer able to select text inside.
self.inputView.text = INPUT_SPACE_CHAR;
// Trigger a text field cursor lock
#ifndef DEBUG_VISIBLE_TEXT_FIELD
self.inputView.alpha = 0.0f;
#endif
inputTextLength = 0;
}
}
break;
@@ -766,7 +799,7 @@ CallbackBridge_nativeSendKey(keycode, 0, held, 0);
}
#ifndef DEBUG_VISIBLE_TEXT_FIELD
inputView.hidden = currentVisibility;
self.inputView.hidden = currentVisibility;
#endif
}
}
@@ -787,11 +820,11 @@ int touchesMovedCount;
}
CGPoint locationInView = [touch locationInView:self.view];
CGFloat screenScale = [[UIScreen mainScreen] scale];
int slot = callback_SurfaceViewController_touchHotbar(locationInView.x * screenScale, locationInView.y * screenScale);
if ([self isTouchInactive:self.hotbarTouch] && slot != -1) {
currentHotbarSlot = callback_SurfaceViewController_touchHotbar(locationInView.x * screenScale, locationInView.y * screenScale);
if ([self isTouchInactive:self.hotbarTouch] && currentHotbarSlot != -1) {
self.hotbarTouch = touch;
}
if ([self isTouchInactive:self.primaryTouch] && slot == -1) {
if ([self isTouchInactive:self.primaryTouch] && currentHotbarSlot == -1) {
self.primaryTouch = touch;
}
[self sendTouchEvent:touch withUIEvent:event withEvent:ACTION_DOWN];
+2 -2
View File
@@ -209,8 +209,8 @@ int callback_SurfaceViewController_touchHotbar(CGFloat x, CGFloat y) {
return -1;
}
int barHeight = mcscale(20);
int barWidth = mcscale(180);
int barHeight = mcscale(40); // 20
int barWidth = mcscale(360); // 180
int barX = (savedWidth / 2) - (barWidth / 2);
int barY = savedHeight - barHeight;
if (x < barX || x >= barX + barWidth || y < barY || y >= barY + barHeight) {