Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
private RectF inputAreaRect;
private int imeHeight;
private boolean hasOngoingImeAnimation;
private static volatile boolean sChatLikelyOpen;

// When the mouse re-grabs, every screen (chat included) is guaranteed closed.
private final GrabListener mChatStateGrabListener = isGrabbing -> {
if (isGrabbing) sChatLikelyOpen = false;
Comment thread
alexytomi marked this conversation as resolved.
Outdated
};

MinecraftProfile minecraftProfile;

Expand Down Expand Up @@ -138,6 +144,7 @@ public void onCreate(Bundle savedInstanceState) {
initLayout(R.layout.activity_basemain);
CallbackBridge.addGrabListener(touchpad);
CallbackBridge.addGrabListener(minecraftGLView);
CallbackBridge.addGrabListener(mChatStateGrabListener);

if (Tools.hasTouchController(new File(gameDirPath)) || LauncherPreferences.PREF_FORCE_ENABLE_TOUCHCONTROLLER) {
TouchControllerUtils.initialize(this, touchControllerInputView);
Expand Down Expand Up @@ -383,6 +390,7 @@ protected void onDestroy() {
super.onDestroy();
CallbackBridge.removeGrabListener(touchpad);
CallbackBridge.removeGrabListener(minecraftGLView);
CallbackBridge.removeGrabListener(mChatStateGrabListener);
ContextExecutor.clearActivity();
}

Expand Down Expand Up @@ -734,6 +742,32 @@ public void updateInputAreaRect(@Nullable RectF rect) {
refreshImeTranslation();
}

/**
* Tracks whether the in-game chat is open, so keyboard panning only kicks in
* when the chat input actually needs to be revealed above the IME.
* Chat open keys only count from gameplay (mouse grabbed), while the close
* keys or the mouse grabbing back (any screen closes) mark it closed.
* Both key lists are user-configurable from the control settings.
*/
public static void trackChatStateKey(int keycode, boolean isDown) {
if (!isDown) return;
if (LauncherPreferences.PREF_CHAT_PAN_CLOSE_KEYS.contains(keycode)) {
sChatLikelyOpen = false;
} else if (LauncherPreferences.PREF_CHAT_PAN_OPEN_KEYS.contains(keycode) && CallbackBridge.isGrabbing()) {
sChatLikelyOpen = true;
}
}

/**
* Char-input variant of the above for software keyboards, which commit
* characters instead of raw keycodes. GLFW keycodes for printable keys
* match their ASCII values, with letters using the uppercase code.
*/
public static void trackChatStateChar(char character) {
int keycode = character >= 'a' && character <= 'z' ? character - ('a' - 'A') : character;
trackChatStateKey(keycode, true);
}

private void refreshImeTranslation() {
if (imeHeight == 0) {
// Early exit
Expand All @@ -744,7 +778,7 @@ private void refreshImeTranslation() {
int inputAreaBottom;
if (inputAreaRect != null) {
inputAreaBottom = (int) inputAreaRect.bottom;
} else if (LauncherPreferences.PREF_KEYBOARD_PANNING) {
} else if (LauncherPreferences.PREF_KEYBOARD_PANNING && sChatLikelyOpen) {
inputAreaBottom = contentFrame.getHeight();
} else {
contentFrame.setTranslationY(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ public void sendKeyPresses(boolean isDown){
setActivated(isDown);
for(int keycode : mProperties.keycodes){
if(keycode >= GLFW_KEY_UNKNOWN){
MainActivity.trackChatStateKey(keycode, isDown);
sendKeyPress(keycode, EfficientAndroidLWJGLKeycode.getLwjglChar(keycode), CallbackBridge.getCurrentMods(), isDown);
CallbackBridge.setModifiers(keycode, isDown);
}else{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import net.kdt.pojavlaunch.LwjglGlfwKeycode;
import net.kdt.pojavlaunch.MainActivity;
import net.kdt.pojavlaunch.MinecraftGLSurface;
import net.kdt.pojavlaunch.R;

Expand Down Expand Up @@ -117,6 +119,7 @@ public void disable(){

/** Send the enter key. */
private void sendEnter(){
MainActivity.trackChatStateKey(LwjglGlfwKeycode.GLFW_KEY_ENTER, true);
mCharacterSender.sendEnter();
clear();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package net.kdt.pojavlaunch.prefs;

import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.preference.Preference;

import net.kdt.pojavlaunch.EfficientAndroidLWJGLKeycode;
import net.kdt.pojavlaunch.R;

import java.util.ArrayList;
import java.util.List;

/**
* Name-based picker for the keyboard panning chat key lists, similar to the
* key mapping spinner of the control editor. The stored value stays a
* comma-separated string of GLFW key codes, parsed by LauncherPreferences.
*/
public class KeyboardPanKeysPreference extends Preference {

private static final String ANDROID_NS = "http://schemas.android.com/apk/res/android";
private final String mDefaultValue;

public KeyboardPanKeysPreference(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mDefaultValue = attrs.getAttributeValue(ANDROID_NS, "defaultValue");
setOnPreferenceClickListener(preference -> {
showKeyPickerDialog();
return true;
});
}

@Override
public void onAttachedToHierarchy(@NonNull androidx.preference.PreferenceManager preferenceManager) {
super.onAttachedToHierarchy(preferenceManager);
refreshSummary();
}

private void showKeyPickerDialog() {
Context ctx = getContext();
List<Integer> keys = parseKeyCodes(getPersistedString(mDefaultValue));

View dialogView = LayoutInflater.from(ctx).inflate(R.layout.dialog_keyboard_pan_keys, null);
LinearLayout keyList = dialogView.findViewById(R.id.chatPanKeys_list);
Spinner spinner = dialogView.findViewById(R.id.chatPanKeys_spinner);
Button addButton = dialogView.findViewById(R.id.chatPanKeys_addButton);

ArrayAdapter<String> adapter = new ArrayAdapter<>(ctx, R.layout.item_centered_textview,
EfficientAndroidLWJGLKeycode.generateKeyName());
spinner.setAdapter(adapter);

rebuildKeyList(keyList, keys);

addButton.setOnClickListener(v -> {
int keycode = EfficientAndroidLWJGLKeycode.getValueByIndex(spinner.getSelectedItemPosition());
if (!keys.contains(keycode)) {
keys.add(keycode);
rebuildKeyList(keyList, keys);
}
});

new AlertDialog.Builder(ctx)
.setTitle(getTitle())
.setView(dialogView)
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
persistString(joinKeyCodes(keys));
refreshSummary();
})
.setNegativeButton(android.R.string.cancel, null)
.show();
}

/** Re-creates one tappable row per key; tapping a key removes it */
private void rebuildKeyList(LinearLayout container, List<Integer> keys) {
container.removeAllViews();
int padding = (int) (12 * getContext().getResources().getDisplayMetrics().density);
for (Integer key : keys) {
TextView keyView = new TextView(container.getContext());
keyView.setText(getKeyName(key));
keyView.setGravity(Gravity.CENTER);
keyView.setPadding(0, padding, 0, padding);
keyView.setOnClickListener(v -> {
keys.remove(key);
rebuildKeyList(container, keys);
});
container.addView(keyView);
}
}

private void refreshSummary() {
List<Integer> keys = parseKeyCodes(getPersistedString(mDefaultValue));
if (keys.isEmpty()) {
setSummary(R.string.mcl_setting_chat_pan_keys_none);
return;
}
StringBuilder nameList = new StringBuilder();
for (int key : keys) {
if (nameList.length() > 0) nameList.append(", ");
nameList.append(getKeyName(key));
}
setSummary(nameList.toString());
}

private static String getKeyName(int keycode) {
return EfficientAndroidLWJGLKeycode.generateKeyName()[EfficientAndroidLWJGLKeycode.getIndexByValue(keycode)];
}

private static List<Integer> parseKeyCodes(String stored) {
List<Integer> keys = new ArrayList<>();
if (stored != null) {
for (String part : stored.split(",")) {
try {
keys.add(Integer.valueOf(part.trim()));
} catch (NumberFormatException ignored) {
}
}
}
return keys;
}

private static String joinKeyCodes(List<Integer> keys) {
StringBuilder joined = new StringBuilder();
for (int key : keys) {
if (joined.length() > 0) joined.append(',');
joined.append(key);
}
return joined.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@

import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Set;

public class LauncherPreferences {
public static final String PREF_KEY_CURRENT_PROFILE = "currentProfile";
Expand Down Expand Up @@ -74,6 +76,8 @@ public class LauncherPreferences {

public static boolean PREF_MOUSE_GRAB_FORCE = false;
public static boolean PREF_KEYBOARD_PANNING = true;
public static Set<Integer> PREF_CHAT_PAN_OPEN_KEYS = null;
public static Set<Integer> PREF_CHAT_PAN_CLOSE_KEYS = null;


public static void loadPreferences(Context ctx) {
Expand Down Expand Up @@ -118,6 +122,10 @@ public static void loadPreferences(Context ctx) {
PREF_TOUCHCONTROLLER_VIBRATE_LENGTH = DEFAULT_PREF.getInt("touchControllerVibrateLength", 100);
PREF_MOUSE_GRAB_FORCE = DEFAULT_PREF.getBoolean("always_grab_mouse", false);
PREF_KEYBOARD_PANNING = DEFAULT_PREF.getBoolean("keyboardPanning", true);
PREF_CHAT_PAN_OPEN_KEYS = parseKeyList(DEFAULT_PREF.getString("chatPanOpenKeys", null),
LwjglGlfwKeycode.GLFW_KEY_T, LwjglGlfwKeycode.GLFW_KEY_SLASH);
PREF_CHAT_PAN_CLOSE_KEYS = parseKeyList(DEFAULT_PREF.getString("chatPanCloseKeys", null),
LwjglGlfwKeycode.GLFW_KEY_ESCAPE, LwjglGlfwKeycode.GLFW_KEY_ENTER, LwjglGlfwKeycode.GLFW_KEY_KP_ENTER);

// User may have deleted their default control
String userDefCtrl = DEFAULT_PREF.getString("defaultCtrl", Tools.CTRLDEF_FILE);
Expand All @@ -143,6 +151,27 @@ public static void loadPreferences(Context ctx) {
}
}

/**
* Parses a comma separated list of GLFW key codes into a set.
* Falls back to the given defaults when the preference is unset or empty,
* and skips anything that is not a plain number.
*/
private static Set<Integer> parseKeyList(String value, int... defaultKeys) {
Set<Integer> keys = new HashSet<>();
if (value != null) {
for (String part : value.split(",")) {
try {
keys.add(Integer.parseInt(part.trim()));
} catch (NumberFormatException ignored) {
}
}
}
if (keys.isEmpty()) {
for (int key : defaultKeys) keys.add(key);
}
return keys;
}

/**
* This functions aims at finding the best default RAM amount,
* according to the RAM amount of the physical device.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
import android.view.inputmethod.BaseInputConnection;
import android.widget.EditText;

import net.kdt.pojavlaunch.LwjglGlfwKeycode;
import net.kdt.pojavlaunch.MainActivity;

class SDLInputConnection extends BaseInputConnection
{
protected EditText mEditText;
Expand Down Expand Up @@ -49,6 +52,9 @@ public boolean sendKeyEvent(KeyEvent event) {
//
// return super.sendKeyEvent(event);
if(KeyEvent.ACTION_DOWN == event.getAction()){
if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
MainActivity.trackChatStateKey(LwjglGlfwKeycode.GLFW_KEY_ENTER, true);
}
SDLActivity.onNativeKeyDown(event.getKeyCode());
} else SDLActivity.onNativeKeyUp(event.getKeyCode());
return true;
Expand Down Expand Up @@ -123,12 +129,14 @@ protected void updateText() {
int codePoint = pendingText.codePointAt(offset);
if (codePoint == '\n') {
if (SDLActivity.onNativeSoftReturnKey()) {
MainActivity.trackChatStateKey(LwjglGlfwKeycode.GLFW_KEY_ENTER, true);
return;
}
}
/* Higher code points don't generate simulated scancodes */
if (codePoint > 0 && codePoint < 128) {
nativeGenerateScancodeForUnichar((char)codePoint);
MainActivity.trackChatStateChar((char)codePoint);
}
offset += Character.charCount(codePoint);
}
Expand Down
32 changes: 32 additions & 0 deletions app_pojavlauncher/src/main/res/layout/dialog_keyboard_pan_keys.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:padding="24dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/mcl_setting_chat_pan_keys_hint" />

<LinearLayout
android:id="@+id/chatPanKeys_list"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<Spinner
android:id="@+id/chatPanKeys_spinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp" />

<Button
android:id="@+id/chatPanKeys_addButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/mcl_setting_chat_pan_keys_add" />

</LinearLayout>
7 changes: 7 additions & 0 deletions app_pojavlauncher/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,13 @@
<string name="mcl_setting_subtitle_grab_mouse">Ensures the cursor stays inside the game. Prevents mouse from clicking touch control layout.</string>
<string name="mcl_setting_title_keyboard_panning">Keyboard panning</string>
<string name="mcl_setting_subtitle_keyboard_panning">Shift the screen upwards when the keyboard is open.</string>
<string name="mcl_setting_title_chat_pan_open_keys">Chat open keys</string>
<string name="mcl_setting_subtitle_chat_pan_open_keys">Pick the keys that mark the chat as open.</string>
<string name="mcl_setting_title_chat_pan_close_keys">Chat close keys</string>
<string name="mcl_setting_subtitle_chat_pan_close_keys">Pick the keys that mark the chat as closed.</string>
<string name="mcl_setting_chat_pan_keys_hint">Tap a key to remove it. Pick a key below and press add to add it.</string>
<string name="mcl_setting_chat_pan_keys_add">Add</string>
<string name="mcl_setting_chat_pan_keys_none">No keys set, defaults apply</string>
<string name="customctrl_passthru">Mouse pass-thru</string>
<string name="customctrl_swipeable">Swipeable</string>
<string name="customctrl_forward_lock">Forward lock</string>
Expand Down
12 changes: 12 additions & 0 deletions app_pojavlauncher/src/main/res/xml/pref_control.xml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@
android:key="keyboardPanning"
android:summary="@string/mcl_setting_subtitle_keyboard_panning"
android:title="@string/mcl_setting_title_keyboard_panning" />
<net.kdt.pojavlaunch.prefs.KeyboardPanKeysPreference
android:key="chatPanOpenKeys"
android:defaultValue="84,47"
android:dependency="keyboardPanning"
android:summary="@string/mcl_setting_subtitle_chat_pan_open_keys"
android:title="@string/mcl_setting_title_chat_pan_open_keys" />
<net.kdt.pojavlaunch.prefs.KeyboardPanKeysPreference
android:key="chatPanCloseKeys"
android:defaultValue="256,257,335"
android:dependency="keyboardPanning"
android:summary="@string/mcl_setting_subtitle_chat_pan_close_keys"
android:title="@string/mcl_setting_title_chat_pan_close_keys" />

</PreferenceCategory>

Expand Down