Compare commits

..

2 Commits

Author SHA1 Message Date
Jules Aguillon
3c62e2b6f9 layouts: Use the 'scale=""' attribute in builtin layouts
This removes the very specific 'width' values.
2025-06-18 00:32:57 +02:00
Jules Aguillon
82b8568310 Add <row scale=""> attribute
Scale the width of the keys in the row to match a value. Useful to
remove space on the right of the row without adding a 'width' attribute
to each key.
2025-06-18 00:14:00 +02:00
9 changed files with 35 additions and 102 deletions

View File

@@ -7,7 +7,6 @@ arab_pc_hindu: Layout includes some ASCII punctuation but not all, missing: !, '
arab_pc_ir: Layout includes some ASCII punctuation but not all, missing: ", %, ', ,, /, ;, <, =, >, ?, [, \, ], `, {, |, } arab_pc_ir: Layout includes some ASCII punctuation but not all, missing: ", %, ', ,, /, ;, <, =, >, ?, [, \, ], `, {, |, }
beng_national: Layout includes some ASCII punctuation but not all, missing: $ beng_national: Layout includes some ASCII punctuation but not all, missing: $
beng_provat: Layout includes some ASCII punctuation but not all, missing: $, &, *, ., /, <, >, [, \, ], `, {, |, } beng_provat: Layout includes some ASCII punctuation but not all, missing: $, &, *, ., /, <, >, [, \, ], `, {, |, }
cyrl_lynyertdz_mk: Layout includes some ASCII punctuation but not all, missing: "
cyrl_yaverti: Layout includes some ASCII punctuation but not all, missing: ~ cyrl_yaverti: Layout includes some ASCII punctuation but not all, missing: ~
cyrl_yxukeng_os: Layout includes some ASCII punctuation but not all, missing: ", #, $, &, ', @, [, ], ~ cyrl_yxukeng_os: Layout includes some ASCII punctuation but not all, missing: ", #, $, &, ', @, [, ], ~
deva_alt: Layout includes some ASCII punctuation but not all, missing: #, $, %, &, ', (, ), *, +, ., /, :, <, =, >, [, \, ], ^, _, `, {, |, }, ~ deva_alt: Layout includes some ASCII punctuation but not all, missing: #, $, %, &, ', (, ), *, +, ., /, :, <, =, >, [, \, ], ^, _, `, {, |, }, ~

View File

@@ -5,9 +5,9 @@
<string name="short_description">Легкая клавиатура для пользователей, заботящихся о конфиденциальности.</string> <string name="short_description">Легкая клавиатура для пользователей, заботящихся о конфиденциальности.</string>
<string name="store_description">Главная особенность клавиатуры — это возможность легко напечатать любой ASCII-символ жестами в углы клавиш.\n\nПриложение изначально было разработано для использования с Termux.\nНа данный момент оно также удобно в повседневном использовании.\n\nПриложение не содержит рекламы, не осуществляет никаких запросов в сеть и имеет открытый исходный код.</string> <string name="store_description">Главная особенность клавиатуры — это возможность легко напечатать любой ASCII-символ жестами в углы клавиш.\n\nПриложение изначально было разработано для использования с Termux.\nНа данный момент оно также удобно в повседневном использовании.\n\nПриложение не содержит рекламы, не осуществляет никаких запросов в сеть и имеет открытый исходный код.</string>
<string name="pref_portrait">В портретном режиме</string> <string name="pref_portrait">В портретном режиме</string>
<string name="pref_portrait_unfolded">В развернутом портретном режиме</string> <!-- <string name="pref_portrait_unfolded">In portrait mode unfolded</string> -->
<string name="pref_landscape">В ландшафтном режиме</string> <string name="pref_landscape">В ландшафтном режиме</string>
<string name="pref_landscape_unfolded">В развернутом ландшафтном режиме</string> <!-- <string name="pref_landscape_unfolded">In landscape mode unfolded</string> -->
<string name="pref_category_layout">Расположение</string> <string name="pref_category_layout">Расположение</string>
<string name="pref_label_brightness">Изменить яркость клавиатуры</string> <string name="pref_label_brightness">Изменить яркость клавиатуры</string>
<string name="pref_keyboard_opacity">Изменить прозрачность фона</string> <string name="pref_keyboard_opacity">Изменить прозрачность фона</string>

View File

@@ -20,7 +20,6 @@
<item>cyrl_jcuken_kk</item> <item>cyrl_jcuken_kk</item>
<item>cyrl_jcuken_ru</item> <item>cyrl_jcuken_ru</item>
<item>cyrl_jcuken_uk</item> <item>cyrl_jcuken_uk</item>
<item>cyrl_lynyertdz_mk</item>
<item>cyrl_lynyertz_sr</item> <item>cyrl_lynyertz_sr</item>
<item>cyrl_ueishsht</item> <item>cyrl_ueishsht</item>
<item>cyrl_yaverti</item> <item>cyrl_yaverti</item>
@@ -106,7 +105,6 @@
<item>ЙЦУКЕН (Қазақша)</item> <item>ЙЦУКЕН (Қазақша)</item>
<item>ЙЦУКЕН (Русский)</item> <item>ЙЦУКЕН (Русский)</item>
<item>ЙЦУКЕН (Українська)</item> <item>ЙЦУКЕН (Українська)</item>
<item>ЉЊЕРТЅ (Македонски)</item>
<item>ЉЊЕРТЗ (Српски)</item> <item>ЉЊЕРТЗ (Српски)</item>
<item>УЕИШЩ (Български, БДС)</item> <item>УЕИШЩ (Български, БДС)</item>
<item>ЯВЕРТЪ</item> <item>ЯВЕРТЪ</item>
@@ -192,7 +190,6 @@
<item>@xml/cyrl_jcuken_kk</item> <item>@xml/cyrl_jcuken_kk</item>
<item>@xml/cyrl_jcuken_ru</item> <item>@xml/cyrl_jcuken_ru</item>
<item>@xml/cyrl_jcuken_uk</item> <item>@xml/cyrl_jcuken_uk</item>
<item>@xml/cyrl_lynyertdz_mk</item>
<item>@xml/cyrl_lynyertz_sr</item> <item>@xml/cyrl_lynyertz_sr</item>
<item>@xml/cyrl_ueishsht</item> <item>@xml/cyrl_ueishsht</item>
<item>@xml/cyrl_yaverti</item> <item>@xml/cyrl_yaverti</item>

View File

@@ -41,7 +41,6 @@
<subtype android:label="%s" android:languageTag="ko" android:imeSubtypeLocale="ko_KR" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=hangul,default_layout=latn_qwerty_us"/> <subtype android:label="%s" android:languageTag="ko" android:imeSubtypeLocale="ko_KR" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=hangul,default_layout=latn_qwerty_us"/>
<subtype android:label="%s" android:languageTag="lt" android:imeSubtypeLocale="lt_LT" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_lt,extra_keys=accent_ogonek:ą:ę:į:ų@s|accent_caron:č:š:ž@f|accent_dot_above:ė@s|accent_macron:ū@o|€"/> <subtype android:label="%s" android:languageTag="lt" android:imeSubtypeLocale="lt_LT" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_lt,extra_keys=accent_ogonek:ą:ę:į:ų@s|accent_caron:č:š:ž@f|accent_dot_above:ė@s|accent_macron:ū@o|€"/>
<subtype android:label="%s" android:languageTag="lv" android:imeSubtypeLocale="lv_LV" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_lv,extra_keys=accent_macron:ā:ē:ī:ū@o|accent_caron:č:š:ž@f|accent_ogonek:ķ:ļ:ņ@s|accent_cedille:ģ@c|€"/> <subtype android:label="%s" android:languageTag="lv" android:imeSubtypeLocale="lv_LV" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_lv,extra_keys=accent_macron:ā:ē:ī:ū@o|accent_caron:č:š:ž@f|accent_ogonek:ķ:ļ:ņ@s|accent_cedille:ģ@c|€"/>
<subtype android:label="%s" android:languageTag="mk" android:imeSubtypeLocale="mk" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=cyrillic,default_layout=cyrl_lynyertdz_mk,extra_keys=ѕ|ѓ|ќ|ѝ|ѐ|љ|њ|џ|„|“|€"/>
<subtype android:label="%s" android:languageTag="mn" android:imeSubtypeLocale="mn_MN" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=cyrillic,default_layout=cyrl_fcuzhen_mn,extra_keys=ү|ө"/> <subtype android:label="%s" android:languageTag="mn" android:imeSubtypeLocale="mn_MN" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=cyrillic,default_layout=cyrl_fcuzhen_mn,extra_keys=ү|ө"/>
<subtype android:label="%s" android:languageTag="mr" android:imeSubtypeLocale="mr_IN" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=devanagari,default_layout=deva_inscript,extra_keys=₹"/> <subtype android:label="%s" android:languageTag="mr" android:imeSubtypeLocale="mr_IN" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=devanagari,default_layout=deva_inscript,extra_keys=₹"/>
<subtype android:label="%s" android:languageTag="mt" android:imeSubtypeLocale="mt_MT" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_mt,extra_keys=accent_grave:à:è:ì:ò:ù|accent_dot_above:ċ:ż:ġ|ħ"/> <subtype android:label="%s" android:languageTag="mt" android:imeSubtypeLocale="mt_MT" android:imeSubtypeMode="keyboard" android:isAsciiCapable="true" android:imeSubtypeExtraValue="script=latin,default_layout=latn_qwerty_mt,extra_keys=accent_grave:à:è:ì:ò:ù|accent_dot_above:ċ:ż:ġ|ħ"/>

View File

@@ -78,11 +78,6 @@ public final class KeyEventHandler
case Compose_pending: case Compose_pending:
_autocap.stop(); _autocap.stop();
break; break;
case Slider:
// Don't wait for the next key_up and move the cursor right away. This
// is called after the trigger distance have been travelled.
handle_slider(key.getSlider(), key.getSliderRepeat(), true);
break;
default: break; default: break;
} }
} }
@@ -104,7 +99,7 @@ public final class KeyEventHandler
case Modifier: break; case Modifier: break;
case Editing: handle_editing_key(key.getEditing()); break; case Editing: handle_editing_key(key.getEditing()); break;
case Compose_pending: _recv.set_compose_pending(true); break; case Compose_pending: _recv.set_compose_pending(true); break;
case Slider: handle_slider(key.getSlider(), key.getSliderRepeat(), false); break; case Slider: handle_slider(key.getSlider(), key.getSliderRepeat()); break;
case Macro: evaluate_macro(key.getMacro()); break; case Macro: evaluate_macro(key.getMacro()); break;
} }
update_meta_state(old_mods); update_meta_state(old_mods);
@@ -234,9 +229,9 @@ public final class KeyEventHandler
{ {
switch (ev) switch (ev)
{ {
case COPY: if(is_selection_not_empty()) send_context_menu_action(android.R.id.copy); break; case COPY: send_context_menu_action(android.R.id.copy); break;
case PASTE: send_context_menu_action(android.R.id.paste); break; case PASTE: send_context_menu_action(android.R.id.paste); break;
case CUT: if(is_selection_not_empty()) send_context_menu_action(android.R.id.cut); break; case CUT: send_context_menu_action(android.R.id.cut); break;
case SELECT_ALL: send_context_menu_action(android.R.id.selectAll); break; case SELECT_ALL: send_context_menu_action(android.R.id.selectAll); break;
case SHARE: send_context_menu_action(android.R.id.shareText); break; case SHARE: send_context_menu_action(android.R.id.shareText); break;
case PASTE_PLAIN: send_context_menu_action(android.R.id.pasteAsPlainText); break; case PASTE_PLAIN: send_context_menu_action(android.R.id.pasteAsPlainText); break;
@@ -266,7 +261,7 @@ public final class KeyEventHandler
} }
/** [r] might be negative, in which case the direction is reversed. */ /** [r] might be negative, in which case the direction is reversed. */
void handle_slider(KeyValue.Slider s, int r, boolean key_down) void handle_slider(KeyValue.Slider s, int r)
{ {
switch (s) switch (s)
{ {
@@ -274,8 +269,8 @@ public final class KeyEventHandler
case Cursor_right: move_cursor(r); break; case Cursor_right: move_cursor(r); break;
case Cursor_up: move_cursor_vertical(-r); break; case Cursor_up: move_cursor_vertical(-r); break;
case Cursor_down: move_cursor_vertical(r); break; case Cursor_down: move_cursor_vertical(r); break;
case Selection_cursor_left: move_cursor_sel(r, true, key_down); break; case Selection_cursor_left: move_cursor_sel(r, true); break;
case Selection_cursor_right: move_cursor_sel(r, false, key_down); break; case Selection_cursor_right: move_cursor_sel(r, false); break;
} }
} }
@@ -315,7 +310,7 @@ public final class KeyEventHandler
/** Move one of the two side of a selection. If [sel_left] is true, the left /** Move one of the two side of a selection. If [sel_left] is true, the left
position is moved, otherwise the right position is moved. */ position is moved, otherwise the right position is moved. */
void move_cursor_sel(int d, boolean sel_left, boolean key_down) void move_cursor_sel(int d, boolean sel_left)
{ {
InputConnection conn = _recv.getCurrentInputConnection(); InputConnection conn = _recv.getCurrentInputConnection();
if (conn == null) if (conn == null)
@@ -325,23 +320,10 @@ public final class KeyEventHandler
{ {
int sel_start = et.selectionStart; int sel_start = et.selectionStart;
int sel_end = et.selectionEnd; int sel_end = et.selectionEnd;
// Reorder the selection when the slider has just been pressed. The if (sel_left == (sel_start <= sel_end))
// selection might have been reversed if one end crossed the other end
// with a previous slider.
if (key_down && sel_start > sel_end)
{
sel_start = et.selectionEnd;
sel_end = et.selectionStart;
}
do
{
if (sel_left)
sel_start += d; sel_start += d;
else else
sel_end += d; sel_end += d;
// Move the cursor twice if moving it once would make the selection
// empty and stop selection mode.
} while (sel_start == sel_end);
if (conn.setSelection(sel_start, sel_end)) if (conn.setSelection(sel_start, sel_end))
return; // Fallback to sending key events if [setSelection] failed return; // Fallback to sending key events if [setSelection] failed
} }
@@ -466,13 +448,6 @@ public final class KeyEventHandler
_recv.selection_state_changed(false); _recv.selection_state_changed(false);
} }
boolean is_selection_not_empty()
{
InputConnection conn = _recv.getCurrentInputConnection();
if (conn == null) return false;
return (conn.getSelectedText(0) != null);
}
public static interface IReceiver public static interface IReceiver
{ {
public void handle_event_key(KeyValue.Event ev); public void handle_event_key(KeyValue.Event ev);

View File

@@ -315,7 +315,6 @@ public class Keyboard2 extends InputMethodService
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
// Allow to draw behind system bars // Allow to draw behind system bars
wattrs.setFitInsetsTypes(0); wattrs.setFitInsetsTypes(0);
window.setDecorFitsSystemWindows(false);
} }
updateLayoutHeightOf(window, ViewGroup.LayoutParams.MATCH_PARENT); updateLayoutHeightOf(window, ViewGroup.LayoutParams.MATCH_PARENT);
final View inputArea = window.findViewById(android.R.id.inputArea); final View inputArea = window.findViewById(android.R.id.inputArea);

View File

@@ -277,12 +277,27 @@ public class Keyboard2View extends View
width = metrics.getBounds().width(); width = metrics.getBounds().width();
WindowInsets wi = metrics.getWindowInsets(); WindowInsets wi = metrics.getWindowInsets();
int insets_types = int insets_types =
WindowInsets.Type.systemBars() WindowInsets.Type.statusBars()
| WindowInsets.Type.displayCutout() | WindowInsets.Type.displayCutout()
| WindowInsets.Type.mandatorySystemGestures(); | WindowInsets.Type.mandatorySystemGestures()
| WindowInsets.Type.navigationBars();
Insets insets = wi.getInsets(insets_types); Insets insets = wi.getInsets(insets_types);
insets_left = insets.left; insets_left = insets.left;
insets_right = insets.right; insets_right = insets.right;
// On API 35, the keyboard is allowed to draw under the
// button-navigation bar but on lower APIs, it must be discounted from
// the width.
if (VERSION.SDK_INT < 35)
{
Insets nav_insets = wi.getInsets(WindowInsets.Type.navigationBars());
width -= nav_insets.left + nav_insets.right;
insets_left -= nav_insets.left;
insets_right -= nav_insets.right;
}
// [insets.bottom] doesn't take into account the buttons that appear in
// the gesture navigation bar when the IME is showing so ensure a minimum
// of margin is added.
if (VERSION.SDK_INT >= 35)
insets_bottom = Math.max(insets.bottom, _config.bottomInsetMin); insets_bottom = Math.max(insets.bottom, _config.bottomInsetMin);
} }
else else

View File

@@ -108,10 +108,7 @@ public final class Pointers implements Handler.Callback
{ {
// No existing pointer, latch the key. // No existing pointer, latch the key.
if (latched) if (latched)
{
add_fake_pointer(key, kv, lock); add_fake_pointer(key, kv, lock);
_handler.onPointerFlagsChanged(false);
}
} }
else if ((ptr.flags & FLAG_P_FAKE) == 0) else if ((ptr.flags & FLAG_P_FAKE) == 0)
{} // Key already latched but not by a fake ptr, do nothing. {} // Key already latched but not by a fake ptr, do nothing.
@@ -121,7 +118,6 @@ public final class Pointers implements Handler.Callback
removePtr(ptr); removePtr(ptr);
if (latched) if (latched)
add_fake_pointer(key, kv, lock); add_fake_pointer(key, kv, lock);
_handler.onPointerFlagsChanged(false);
} }
else if ((ptr.flags & FLAG_P_LOCKED) != 0) else if ((ptr.flags & FLAG_P_LOCKED) != 0)
{} // Existing ptr is locked but [lock] is false, do not continue. {} // Existing ptr is locked but [lock] is false, do not continue.
@@ -310,6 +306,7 @@ public final class Pointers implements Handler.Callback
// Start sliding mode // Start sliding mode
if (new_value.getKind() == KeyValue.Kind.Slider) if (new_value.getKind() == KeyValue.Kind.Slider)
startSliding(ptr, x, y, dx, dy, new_value); startSliding(ptr, x, y, dx, dy, new_value);
_handler.onPointerDown(new_value, true);
} }
} }
@@ -472,7 +469,7 @@ public final class Pointers implements Handler.Callback
stopLongPress(ptr); stopLongPress(ptr);
ptr.flags |= FLAG_P_SLIDING; ptr.flags |= FLAG_P_SLIDING;
ptr.sliding = new Sliding(x, y, dirx, diry, kv.getSlider()); ptr.sliding = new Sliding(x, y, dirx, diry, kv.getSlider());
_handler.onPointerDown(kv, true); _handler.onPointerHold(kv, ptr.modifiers);
} }
/** Return the [FLAG_P_*] flags that correspond to pressing [kv]. */ /** Return the [FLAG_P_*] flags that correspond to pressing [kv]. */
@@ -608,10 +605,6 @@ public final class Pointers implements Handler.Callback
static final float SPEED_SMOOTHING = 0.7f; static final float SPEED_SMOOTHING = 0.7f;
/** Avoid absurdly large values. */ /** Avoid absurdly large values. */
static final float SPEED_MAX = 4.f; static final float SPEED_MAX = 4.f;
/** Make vertical sliders slower. The intention is to make the up/down
slider slower, as we have less visibility and do smaller movements in
that direction. */
static final float SPEED_VERTICAL_MULT = 0.5f;
public void onTouchMove(Pointer ptr, float x, float y) public void onTouchMove(Pointer ptr, float x, float y)
{ {
@@ -625,9 +618,8 @@ public final class Pointers implements Handler.Callback
return; return;
last_move_ms = System.currentTimeMillis(); last_move_ms = System.currentTimeMillis();
} }
d += ((x - last_x) * speed * direction_x d += ((x - last_x) * direction_x + (y - last_y) * direction_y)
+ (y - last_y) * speed * SPEED_VERTICAL_MULT * direction_y) * speed / _config.slide_step_px;
/ _config.slide_step_px;
update_speed(travelled, x, y); update_speed(travelled, x, y);
// Send an event when [abs(d)] exceeds [1]. // Send an event when [abs(d)] exceeds [1].
int d_ = (int)d; int d_ = (int)d;

View File

@@ -1,43 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<keyboard name="ЉЊЕРТЅ (Македонски)" script="cyrillic">
<row scale="11">
<key key0="љ" key2="1" key4="esc"/>
<key key0="њ" key1="~" key2="2" key3="\@"/>
<key key0="е" key1="!" key2="3" key3="\#" key4="ѐ"/>
<key key0="р" key2="4" key3="$"/>
<key key0="т" key2="5" key3="%"/>
<key key0="ѕ" key2="6" key3="^"/>
<key key0="у" key2="7" key3="&amp;"/>
<key key0="и" key2="8" key3="*" key4="ѝ"/>
<key key0="о" key2="9" key3="(" key4=")"/>
<key key0="п" key2="0" key3="[" key4="]"/>
<key key0="ш" key2="€" key3="{" key4="}"/>
</row>
<row scale="11">
<key key0="а" key1="tab"/>
<key key0="с"/>
<key key0="д"/>
<key key0="ф"/>
<key key0="г"/>
<key key0="х"/>
<key key0="ј"/>
<key key0="к"/>
<key key0="л" key2="|" key3="\\"/>
<key key0="ч" key2="-" key3="_"/>
<key key0="ќ" key2="=" key3="+"/>
</row>
<row scale="11">
<key width="1.5" key0="shift" key2="loc capslock"/>
<key key0="з"/>
<key key0="џ"/>
<key key0="ц"/>
<key key0="в" key2="&lt;" key3="."/>
<key key0="б" key2="&gt;" key3=","/>
<key key0="н" key2="\?" key3="/"/>
<key key0="м" key2=":" key3=";"/>
<key key0="ѓ" key2="`" key3="'"/>
<key key0="ж" key2="“" key3="„"/>
<key width="1.5" key0="backspace" key2="delete"/>
</row>
</keyboard>