diff --git a/res/xml/bottom_row.xml b/res/xml/bottom_row.xml index fd3de1c..153293b 100644 --- a/res/xml/bottom_row.xml +++ b/res/xml/bottom_row.xml @@ -1,8 +1,10 @@ - - - - - + + + + + + + diff --git a/srcs/juloo.keyboard2/KeyValue.java b/srcs/juloo.keyboard2/KeyValue.java index ea04112..0c2281f 100644 --- a/srcs/juloo.keyboard2/KeyValue.java +++ b/srcs/juloo.keyboard2/KeyValue.java @@ -758,6 +758,7 @@ public final class KeyValue implements Comparable case "cursor_right": return sliderKey(Slider.Cursor_right, 1); case "cursor_up": return sliderKey(Slider.Cursor_up, 1); case "cursor_down": return sliderKey(Slider.Cursor_down, 1); + case "cursor_joystick": return sliderKey(Slider.Cursor_joystick, 1); case "selection_cancel": return editingKey("Esc", Editing.SELECTION_CANCEL, FLAG_SMALLER_FONT | FLAG_SPECIAL); case "selection_cursor_left": return sliderKey(Slider.Selection_cursor_left, -1); // Move the left side of the selection case "selection_cursor_right": return sliderKey(Slider.Selection_cursor_right, 1); @@ -870,7 +871,8 @@ public final class KeyValue implements Comparable Cursor_up(0xE005, true), Cursor_down(0xE007, true), Selection_cursor_left(0xE008, false), - Selection_cursor_right(0xE006, false); + Selection_cursor_right(0xE006, false), + Cursor_joystick(0xE001, false); final String symbol; final boolean vertical; @@ -885,6 +887,10 @@ public final class KeyValue implements Comparable return vertical; } + public boolean isJoystick() { + return this == Cursor_joystick; + } + @Override public String toString() { return symbol; } diff --git a/srcs/juloo.keyboard2/Pointers.java b/srcs/juloo.keyboard2/Pointers.java index c7feedc..e005414 100644 --- a/srcs/juloo.keyboard2/Pointers.java +++ b/srcs/juloo.keyboard2/Pointers.java @@ -143,7 +143,10 @@ public final class Pointers implements Handler.Callback if (ptr.hasFlagsAny(FLAG_P_SLIDING)) { clearLatched(); - ptr.sliding.onTouchUp(ptr); + if (ptr.joypad != null) + ptr.joypad.onTouchUp(ptr); + else + ptr.sliding.onTouchUp(ptr); return; } stopLongPress(ptr); @@ -267,7 +270,14 @@ public final class Pointers implements Handler.Callback return; if (ptr.hasFlagsAny(FLAG_P_SLIDING)) { - ptr.sliding.onTouchMove(ptr, x, y); + if (ptr.joypad != null) + { + ptr.joypad.onTouchMove(ptr, x, y); + } + else + { + ptr.sliding.onTouchMove(ptr, x, y); + } return; } @@ -472,7 +482,15 @@ public final class Pointers implements Handler.Callback int diry = dy < 0 ? -r : r; stopLongPress(ptr); ptr.flags |= FLAG_P_SLIDING; - ptr.sliding = new Sliding(x, y, dirx, diry, kv.getSlider()); + KeyValue.Slider s = kv.getSlider(); + if (s.isJoystick()) + { + ptr.joypad = new Joypad(x, y, s); + } + else + { + ptr.sliding = new Sliding(x, y, dirx, diry, s); + } } /** Return the [FLAG_P_*] flags that correspond to pressing [kv]. */ @@ -556,6 +574,8 @@ public final class Pointers implements Handler.Callback public int timeoutWhat; /** [null] when not in sliding mode. */ public Sliding sliding; + /** [null] when not in joypad mode. */ + public Joypad joypad; public Pointer(int p, KeyboardData.Key k, KeyValue v, float x, float y, Modifiers m, int f) { @@ -569,6 +589,7 @@ public final class Pointers implements Handler.Callback flags = f; timeoutWhat = -1; sliding = null; + joypad = null; } public boolean hasFlagsAny(int has) @@ -672,6 +693,117 @@ public final class Pointers implements Handler.Callback } } + /** Joypad: a 2D slider that tracks finger position in both x and y axes. + Movement is divided into 4 directional zones (up/down/left/right). + The dominant axis determines which cursor key is fired. + Direction can change without lifting the finger. */ + public final class Joypad + { + /** Accumulated distance along each axis. */ + float dx_acc = 0.f; + float dy_acc = 0.f; + /** Smoothed speed (same formula as Sliding). */ + float speed = 0.5f; + /** Coordinate of the last move. */ + float last_x; + float last_y; + /** [System.currentTimeMillis()] at the time of the last move. -1 = not started. */ + long last_move_ms = -1; + /** The slider this joypad delegates to. */ + KeyValue.Slider slider; + + static final float SPEED_SMOOTHING = 0.7f; + static final float SPEED_MAX = 4.f; + static final float SPEED_VERTICAL_MULT = 0.5f; + static final float SPEED_WORD_MULT = 0.25f; + + public Joypad(float x, float y, KeyValue.Slider s) + { + last_x = x; + last_y = y; + slider = s; + } + + public void onTouchMove(Pointer ptr, float x, float y) + { + float travelled = Math.abs(x - last_x) + Math.abs(y - last_y); + if (last_move_ms == -1) + { + if (travelled < (_config.swipe_dist_px + _config.slide_step_px)) + return; + last_move_ms = System.currentTimeMillis(); + } + + float current_speed = speed / _config.slide_step_px; + if (ptr.modifiers.has(KeyValue.Modifier.CTRL)) + current_speed *= SPEED_WORD_MULT; + + // Track both axes independently + dx_acc += (x - last_x) * current_speed; + dy_acc += (y - last_y) * current_speed * SPEED_VERTICAL_MULT; + + update_speed(travelled, x, y); + + // Determine dominant direction and fire the appropriate event + // Use the axis with the larger absolute accumulated displacement + int dx = (int)dx_acc; + int dy = (int)dy_acc; + + if (dx != 0 || dy != 0) + { + if (Math.abs(dx) >= Math.abs(dy)) + { + // Horizontal movement wins + if (dx > 0) + { + dx_acc -= dx; + _handler.onPointerHold( + KeyValue.sliderKey(KeyValue.Slider.Cursor_right, dx), ptr.modifiers); + } + else + { + dx_acc -= dx; + _handler.onPointerHold( + KeyValue.sliderKey(KeyValue.Slider.Cursor_left, -dx), ptr.modifiers); + } + } + else + { + // Vertical movement wins + if (dy > 0) + { + dy_acc -= dy; + _handler.onPointerHold( + KeyValue.sliderKey(KeyValue.Slider.Cursor_down, dy), ptr.modifiers); + } + else + { + dy_acc -= dy; + _handler.onPointerHold( + KeyValue.sliderKey(KeyValue.Slider.Cursor_up, -dy), ptr.modifiers); + } + } + } + } + + public void onTouchUp(Pointer ptr) + { + removePtr(ptr); + _handler.onPointerFlagsChanged(false); + } + + void update_speed(float travelled, float x, float y) + { + long now = System.currentTimeMillis(); + float instant_speed = Math.min(SPEED_MAX, + travelled / (float)(now - last_move_ms) + 1.f); + speed = speed + (instant_speed - speed) * SPEED_SMOOTHING; + last_move_ms = now; + last_x = x; + last_y = y; + } + } + /** Represent modifiers currently activated. Sorted in the order they should be evaluated. */ public static final class Modifiers diff --git a/srcs/special_font/001.svg b/srcs/special_font/001.svg index 176f5ce..ecb8f45 100644 --- a/srcs/special_font/001.svg +++ b/srcs/special_font/001.svg @@ -1,7 +1,4 @@ - - - + + - - - +