211 lines
6.3 KiB
Java
211 lines
6.3 KiB
Java
package net.minecraft.client;
|
|
|
|
import com.google.common.collect.Maps;
|
|
import com.google.common.collect.Sets;
|
|
import com.mojang.blaze3d.platform.InputConstants;
|
|
import com.mojang.blaze3d.platform.InputConstants.Key;
|
|
import com.mojang.blaze3d.platform.InputConstants.Type;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.function.Supplier;
|
|
import net.fabricmc.api.EnvType;
|
|
import net.fabricmc.api.Environment;
|
|
import net.minecraft.Util;
|
|
import net.minecraft.client.resources.language.I18n;
|
|
import net.minecraft.network.chat.Component;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public class KeyMapping implements Comparable<KeyMapping> {
|
|
private static final Map<String, KeyMapping> ALL = Maps.<String, KeyMapping>newHashMap();
|
|
private static final Map<Key, KeyMapping> MAP = Maps.<Key, KeyMapping>newHashMap();
|
|
private static final Set<String> CATEGORIES = Sets.<String>newHashSet();
|
|
public static final String CATEGORY_MOVEMENT = "key.categories.movement";
|
|
public static final String CATEGORY_MISC = "key.categories.misc";
|
|
public static final String CATEGORY_MULTIPLAYER = "key.categories.multiplayer";
|
|
public static final String CATEGORY_GAMEPLAY = "key.categories.gameplay";
|
|
public static final String CATEGORY_INVENTORY = "key.categories.inventory";
|
|
public static final String CATEGORY_INTERFACE = "key.categories.ui";
|
|
public static final String CATEGORY_CREATIVE = "key.categories.creative";
|
|
private static final Map<String, Integer> CATEGORY_SORT_ORDER = Util.make(Maps.<String, Integer>newHashMap(), hashMap -> {
|
|
hashMap.put("key.categories.movement", 1);
|
|
hashMap.put("key.categories.gameplay", 2);
|
|
hashMap.put("key.categories.inventory", 3);
|
|
hashMap.put("key.categories.creative", 4);
|
|
hashMap.put("key.categories.multiplayer", 5);
|
|
hashMap.put("key.categories.ui", 6);
|
|
hashMap.put("key.categories.misc", 7);
|
|
});
|
|
private final String name;
|
|
private final Key defaultKey;
|
|
private final String category;
|
|
private Key key;
|
|
private boolean isDown;
|
|
private int clickCount;
|
|
|
|
public static void click(Key key) {
|
|
KeyMapping keyMapping = (KeyMapping)MAP.get(key);
|
|
if (keyMapping != null) {
|
|
keyMapping.clickCount++;
|
|
}
|
|
}
|
|
|
|
public static void set(Key key, boolean held) {
|
|
KeyMapping keyMapping = (KeyMapping)MAP.get(key);
|
|
if (keyMapping != null) {
|
|
keyMapping.setDown(held);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Completely recalculates whether any keybinds are held, from scratch.
|
|
*/
|
|
public static void setAll() {
|
|
for (KeyMapping keyMapping : ALL.values()) {
|
|
if (keyMapping.key.getType() == Type.KEYSYM && keyMapping.key.getValue() != InputConstants.UNKNOWN.getValue()) {
|
|
keyMapping.setDown(InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), keyMapping.key.getValue()));
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void releaseAll() {
|
|
for (KeyMapping keyMapping : ALL.values()) {
|
|
keyMapping.release();
|
|
}
|
|
}
|
|
|
|
public static void resetToggleKeys() {
|
|
for (KeyMapping keyMapping : ALL.values()) {
|
|
if (keyMapping instanceof ToggleKeyMapping toggleKeyMapping) {
|
|
toggleKeyMapping.reset();
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void resetMapping() {
|
|
MAP.clear();
|
|
|
|
for (KeyMapping keyMapping : ALL.values()) {
|
|
MAP.put(keyMapping.key, keyMapping);
|
|
}
|
|
}
|
|
|
|
public KeyMapping(String name, int keyCode, String category) {
|
|
this(name, Type.KEYSYM, keyCode, category);
|
|
}
|
|
|
|
public KeyMapping(String name, Type type, int keyCode, String category) {
|
|
this.name = name;
|
|
this.key = type.getOrCreate(keyCode);
|
|
this.defaultKey = this.key;
|
|
this.category = category;
|
|
ALL.put(name, this);
|
|
MAP.put(this.key, this);
|
|
CATEGORIES.add(category);
|
|
}
|
|
|
|
/**
|
|
* Returns {@code true} if the key is pressed (used for continuous querying). Should be used in tickers.
|
|
*/
|
|
public boolean isDown() {
|
|
return this.isDown;
|
|
}
|
|
|
|
public String getCategory() {
|
|
return this.category;
|
|
}
|
|
|
|
/**
|
|
* Returns {@code true} on the initial key press. For continuous querying use {@link isKeyDown()}. Should be used in key events.
|
|
*/
|
|
public boolean consumeClick() {
|
|
if (this.clickCount == 0) {
|
|
return false;
|
|
} else {
|
|
this.clickCount--;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private void release() {
|
|
this.clickCount = 0;
|
|
this.setDown(false);
|
|
}
|
|
|
|
public String getName() {
|
|
return this.name;
|
|
}
|
|
|
|
public Key getDefaultKey() {
|
|
return this.defaultKey;
|
|
}
|
|
|
|
/**
|
|
* Binds a new KeyCode to this
|
|
*/
|
|
public void setKey(Key key) {
|
|
this.key = key;
|
|
}
|
|
|
|
public int compareTo(KeyMapping keyMapping) {
|
|
return this.category.equals(keyMapping.category)
|
|
? I18n.get(this.name).compareTo(I18n.get(keyMapping.name))
|
|
: ((Integer)CATEGORY_SORT_ORDER.get(this.category)).compareTo((Integer)CATEGORY_SORT_ORDER.get(keyMapping.category));
|
|
}
|
|
|
|
/**
|
|
* Returns a supplier which gets a keybind's current binding (eg, <code>key.forward</code> returns <samp>W</samp> by default), or the keybind's name if no such keybind exists (eg, <code>key.invalid</code> returns <samp>key.invalid</samp>)
|
|
*/
|
|
public static Supplier<Component> createNameSupplier(String key) {
|
|
KeyMapping keyMapping = (KeyMapping)ALL.get(key);
|
|
return keyMapping == null ? () -> Component.translatable(key) : keyMapping::getTranslatedKeyMessage;
|
|
}
|
|
|
|
/**
|
|
* Returns {@code true} if the supplied {@code KeyMapping} conflicts with this
|
|
*/
|
|
public boolean same(KeyMapping binding) {
|
|
return this.key.equals(binding.key);
|
|
}
|
|
|
|
public boolean isUnbound() {
|
|
return this.key.equals(InputConstants.UNKNOWN);
|
|
}
|
|
|
|
public boolean matches(int keysym, int scancode) {
|
|
return keysym == InputConstants.UNKNOWN.getValue()
|
|
? this.key.getType() == Type.SCANCODE && this.key.getValue() == scancode
|
|
: this.key.getType() == Type.KEYSYM && this.key.getValue() == keysym;
|
|
}
|
|
|
|
/**
|
|
* Returns {@code true} if the {@code KeyMapping} is set to a mouse key and the key matches.
|
|
*/
|
|
public boolean matchesMouse(int key) {
|
|
return this.key.getType() == Type.MOUSE && this.key.getValue() == key;
|
|
}
|
|
|
|
public Component getTranslatedKeyMessage() {
|
|
return this.key.getDisplayName();
|
|
}
|
|
|
|
/**
|
|
* Returns {@code true} if the {@code KeyMapping} is using the default key and key modifier
|
|
*/
|
|
public boolean isDefault() {
|
|
return this.key.equals(this.defaultKey);
|
|
}
|
|
|
|
public String saveString() {
|
|
return this.key.getName();
|
|
}
|
|
|
|
public void setDown(boolean value) {
|
|
this.isDown = value;
|
|
}
|
|
|
|
@Nullable
|
|
public static KeyMapping get(String name) {
|
|
return (KeyMapping)ALL.get(name);
|
|
}
|
|
}
|