diff --git a/1.17-1.17.1-fabric/build.gradle b/1.17-1.17.1-fabric/build.gradle index a0a3b54..4c819b7 100644 --- a/1.17-1.17.1-fabric/build.gradle +++ b/1.17-1.17.1-fabric/build.gradle @@ -1,78 +1,91 @@ -plugins { - id 'fabric-loom' version '1.5-SNAPSHOT' - id 'maven-publish' +plugins() { + id('fabric-loom').version("${loom_version}") + id('maven-publish') } version = project.mod_version group = project.maven_group -base { +base() { archivesName = project.archives_base_name } -repositories { - maven { - url 'https://repo.flowerinsnow.online/repository/maven-public/' +repositories() { + maven() { + url = 'https://maven.pkg.github.com/flowerinsnowdh/GreatScrollableTooltips' + credentials() { + username = "${System.getenv('GITHUB_USERNAME')}" + password = "${System.getenv('GITHUB_TOKEN')}" + } + } + + maven() { + url = 'https://www.cursemaven.com/' } - maven { - url 'https://maven.terraformersmc.com/releases/' + maven() { + url = 'https://maven.terraformersmc.com/releases/' } } dependencies { // To change the versions see the gradle.properties file - minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + minecraft("com.mojang:minecraft:${project.minecraft_version}") + mappings("net.fabricmc:yarn:${project.yarn_mappings}:v2") + modImplementation("net.fabricmc:fabric-loader:${project.loader_version}") // Fabric API. This is technically optional, but you probably want it anyway. - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + modImplementation("net.fabricmc.fabric-api:fabric-api:${project.fabric_version}") // Uncomment the following line to enable the deprecated Fabric API modules. // These are included in the Fabric API production distribution and allow you to update your mod to the latest modules at a later more convenient time. // modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}" - modImplementation 'com.terraformersmc:modmenu:2.0.17' - include(api('online.flowerinsnow.fnml:fnml4j-core:1.0.3')) + modImplementation("com.terraformersmc:modmenu:${modmenu_version}") + modImplementation('curse.maven:legendary-tooltips-fabric-542478:3537454') + include(api("cn.flowerinsnow.greatscrollabletooltips:common:${common_module_version}")) + include(api("com.electronwill.night-config:core:${night_config_version}")) + include(api("com.electronwill.night-config:toml:${night_config_version}")) } -processResources { - inputs.property "version", project.version +processResources() { + LinkedHashMap props = ['version': project.version] + props.forEach(inputs::property) - filesMatching("fabric.mod.json") { - expand "version": project.version + filesMatching('fabric.mod.json') { + expand(props) } } -tasks.withType(JavaCompile).configureEach { - it.options.release = 16 +tasks.withType(JavaCompile).configureEach() { + options.release = 16 } -java { +java() { // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task // if it is present. // If you remove this line, sources will not be generated. - withSourcesJar() + // withSourcesJar() sourceCompatibility = JavaVersion.VERSION_16 targetCompatibility = JavaVersion.VERSION_16 } jar { - from 'LICENSE' + from('../LICENSE') + from('../NOTICE') } // configure the maven publication -publishing { - publications { +publishing() { + publications() { mavenJava(MavenPublication) { - from components.java + from(components.java) } } // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. - repositories { + repositories() { // Add repositories to publish to here. // Notice: This block does NOT have the same function as the block in the top level. // The repositories here will be used for publishing your artifact, not for diff --git a/1.17-1.17.1-fabric/gradle.properties b/1.17-1.17.1-fabric/gradle.properties index 6d6ba3a..d7490fe 100644 --- a/1.17-1.17.1-fabric/gradle.properties +++ b/1.17-1.17.1-fabric/gradle.properties @@ -6,12 +6,16 @@ org.gradle.parallel=true # check these on https://fabricmc.net/develop minecraft_version=1.17.1 yarn_mappings=1.17.1+build.65 -loader_version=0.15.7 +loader_version=0.16.7 # Mod Properties -mod_version=8.0.0 -maven_group=online.flowerinsnow.greatscrollabletooltips +mod_version=8.1.0+fabric +maven_group=cn.flowerinsnow.greatscrollabletooltips archives_base_name=great-scrollable-tooltips # Dependencies -fabric_version=0.46.1+1.17 \ No newline at end of file +loom_version=1.8.10 +fabric_version=0.46.1+1.17 +modmenu_version=2.0.17 +night_config_version=3.8.1 +common_module_version=1.1.0 diff --git a/1.17-1.17.1-fabric/gradle/wrapper/gradle-wrapper.properties b/1.17-1.17.1-fabric/gradle/wrapper/gradle-wrapper.properties index a80b22c..df97d72 100644 --- a/1.17-1.17.1-fabric/gradle/wrapper/gradle-wrapper.properties +++ b/1.17-1.17.1-fabric/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/GreatScrollableTooltips.java b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/GreatScrollableTooltips.java new file mode 100644 index 0000000..f931d0a --- /dev/null +++ b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/GreatScrollableTooltips.java @@ -0,0 +1,93 @@ +package cn.flowerinsnow.greatscrollabletooltips; + +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.MinecraftClient; +import net.minecraft.item.ItemStack; +import net.minecraft.util.crash.CrashReport; +import cn.flowerinsnow.greatscrollabletooltips.common.config.GreatScrollableTooltipsConfig; +import cn.flowerinsnow.greatscrollabletooltips.common.object.ScrollSession; +import cn.flowerinsnow.greatscrollabletooltips.common.provider.ModEnvironmentProvider; +import cn.flowerinsnow.greatscrollabletooltips.event.PreScreenKeyPressedEvent; +import cn.flowerinsnow.greatscrollabletooltips.event.PreScreenMouseScrollEvent; +import cn.flowerinsnow.greatscrollabletooltips.event.RenderTooltipEvent; +import cn.flowerinsnow.greatscrollabletooltips.event.ScreenCloseEvent; +import cn.flowerinsnow.greatscrollabletooltips.listener.EventTriggerListener; +import cn.flowerinsnow.greatscrollabletooltips.listener.KeyScrollListener; +import cn.flowerinsnow.greatscrollabletooltips.listener.MouseScrollListener; +import cn.flowerinsnow.greatscrollabletooltips.listener.ScrollingStatusListener; +import cn.flowerinsnow.greatscrollabletooltips.manager.KeyBindingManager; + +import java.io.InputStream; +import java.nio.file.Path; + +@Environment(EnvType.CLIENT) +public class GreatScrollableTooltips implements ClientModInitializer { + public static final String MODID = "great-scrollable-tooltips"; + + private static GreatScrollableTooltips instance; + + private GreatScrollableTooltipsConfig config; + + private ScrollSession scrollSession; + + @Override + public void onInitializeClient() { + GreatScrollableTooltips.instance = this; + this.scrollSession = new ScrollSession<>(); + + this.initConfig(); + this.initListeners(); + this.initKeyBindings(); + } + + private void initConfig() { + this.config = new GreatScrollableTooltipsConfig(new ModEnvironmentProvider() { + @Override + public InputStream getDefaultConfigAsStream() { + return GreatScrollableTooltips.class.getResourceAsStream("/config.toml"); + } + + @Override + public Path getConfigFile() { + return FabricLoader.getInstance().getConfigDir().resolve(GreatScrollableTooltips.MODID + ".toml"); + } + + @Override + public void crash(Throwable throwable, String msg) { + MinecraftClient.printCrashReport(CrashReport.create(throwable, msg)); + } + }); + this.config.saveDefaultConfig(); + this.config.load(); + } + + private void initListeners() { + ClientTickEvents.END_CLIENT_TICK.register(new EventTriggerListener()); + PreScreenKeyPressedEvent.EVENT.register(new KeyScrollListener(this)); + PreScreenMouseScrollEvent.EVENT.register(new MouseScrollListener(this)); + ScrollingStatusListener scrollingStatusListener = new ScrollingStatusListener(this); + RenderTooltipEvent.Pre.EVENT.register(scrollingStatusListener); + RenderTooltipEvent.Miss.EVENT.register(scrollingStatusListener); + ScreenCloseEvent.EVENT.register(scrollingStatusListener); + } + + private void initKeyBindings() { + KeyBindingManager.registerAll(); + } + + public static GreatScrollableTooltips getInstance() { + return GreatScrollableTooltips.instance; + } + + public GreatScrollableTooltipsConfig getConfig() { + return this.config; + } + + public ScrollSession getScrollSession() { + return this.scrollSession; + } +} diff --git a/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/event/PreScreenKeyPressedEvent.java b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/event/PreScreenKeyPressedEvent.java new file mode 100644 index 0000000..86c0f77 --- /dev/null +++ b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/event/PreScreenKeyPressedEvent.java @@ -0,0 +1,20 @@ +package cn.flowerinsnow.greatscrollabletooltips.event; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.util.ActionResult; + +public interface PreScreenKeyPressedEvent { + Event EVENT = EventFactory.createArrayBacked(PreScreenKeyPressedEvent.class, listeners -> (screen, keyCode, scanCode, modifiers) -> { + for (PreScreenKeyPressedEvent listener : listeners) { + ActionResult actionResult = listener.preScreenKeyPressed(screen, keyCode, scanCode, modifiers); + if (actionResult != ActionResult.PASS) { + return actionResult; + } + } + return ActionResult.PASS; + }); + + ActionResult preScreenKeyPressed(HandledScreen screen, int keyCode, int scanCode, int modifiers); +} diff --git a/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/event/PreScreenMouseScrollEvent.java b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/event/PreScreenMouseScrollEvent.java new file mode 100644 index 0000000..484796f --- /dev/null +++ b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/event/PreScreenMouseScrollEvent.java @@ -0,0 +1,20 @@ +package cn.flowerinsnow.greatscrollabletooltips.event; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.util.ActionResult; + +public interface PreScreenMouseScrollEvent { + Event EVENT = EventFactory.createArrayBacked(PreScreenMouseScrollEvent.class, listeners -> (screen, mouseX, mouseY, amount) -> { + for (PreScreenMouseScrollEvent listener : listeners) { + ActionResult actionResult = listener.preScreenMouseScrolled(screen, mouseX, mouseY, amount); + if (actionResult != ActionResult.PASS) { + return actionResult; + } + } + return ActionResult.PASS; + }); + + ActionResult preScreenMouseScrolled(HandledScreen screen, double mouseX, double mouseY, double amount); +} diff --git a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/event/RenderTooltipEvent.java b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/event/RenderTooltipEvent.java similarity index 55% rename from 1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/event/RenderTooltipEvent.java rename to 1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/event/RenderTooltipEvent.java index 7b4393b..b886621 100644 --- a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/event/RenderTooltipEvent.java +++ b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/event/RenderTooltipEvent.java @@ -1,17 +1,17 @@ -package online.flowerinsnow.greatscrollabletooltips.event; +package cn.flowerinsnow.greatscrollabletooltips.event; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.item.ItemStack; +import net.minecraft.screen.slot.Slot; import net.minecraft.util.ActionResult; public interface RenderTooltipEvent { - interface Post { - Event EVENT = EventFactory.createArrayBacked(Post.class, listeners -> (screen, matrices, stack, x, y) -> { - for (Post listener : listeners) { - ActionResult actionResult = listener.startDrawMouseoverTooltip(screen, matrices, stack, x, y); + interface Pre { + Event
 EVENT = EventFactory.createArrayBacked(Pre.class, listeners -> (screen, matrices, x, y, focusedSlot) -> {
+            for (Pre listener : listeners) {
+                ActionResult actionResult = listener.preRenderTooltip(screen, matrices, x, y, focusedSlot);
                 if (actionResult != ActionResult.PASS) {
                     return actionResult;
                 }
@@ -19,13 +19,13 @@ interface Post {
             return ActionResult.PASS;
         });
 
-        ActionResult startDrawMouseoverTooltip(HandledScreen screen, MatrixStack matrices, ItemStack stack, int x, int y);
+        ActionResult preRenderTooltip(HandledScreen screen, MatrixStack matrices, int x, int y, Slot focusedSlot);
     }
 
     interface Miss {
         Event EVENT = EventFactory.createArrayBacked(Miss.class, listeners -> screen -> {
             for (Miss listener : listeners) {
-                ActionResult actionResult = listener.onMiss(screen);
+                ActionResult actionResult = listener.missRenderTooltip(screen);
                 if (actionResult != ActionResult.PASS) {
                     return actionResult;
                 }
@@ -33,6 +33,6 @@ interface Miss {
             return ActionResult.PASS;
         });
 
-        ActionResult onMiss(HandledScreen screen);
+        ActionResult missRenderTooltip(HandledScreen screen);
     }
 }
diff --git a/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/event/ScreenCloseEvent.java b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/event/ScreenCloseEvent.java
new file mode 100644
index 0000000..3cc9eb7
--- /dev/null
+++ b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/event/ScreenCloseEvent.java
@@ -0,0 +1,20 @@
+package cn.flowerinsnow.greatscrollabletooltips.event;
+
+import net.fabricmc.fabric.api.event.Event;
+import net.fabricmc.fabric.api.event.EventFactory;
+import net.minecraft.client.gui.screen.Screen;
+import net.minecraft.util.ActionResult;
+
+public interface ScreenCloseEvent {
+    Event EVENT = EventFactory.createArrayBacked(ScreenCloseEvent.class, listeners -> (screen) -> {
+        for (ScreenCloseEvent event : listeners) {
+            ActionResult actionResult = event.onScreenClose(screen);
+            if (actionResult != ActionResult.PASS) {
+                return actionResult;
+            }
+        }
+        return ActionResult.PASS;
+    });
+
+    ActionResult onScreenClose(Screen oldScreen);
+}
diff --git a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/listener/EventTriggerListener.java b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/listener/EventTriggerListener.java
similarity index 79%
rename from 1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/listener/EventTriggerListener.java
rename to 1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/listener/EventTriggerListener.java
index ecc7b9b..03ae577 100644
--- a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/listener/EventTriggerListener.java
+++ b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/listener/EventTriggerListener.java
@@ -1,9 +1,9 @@
-package online.flowerinsnow.greatscrollabletooltips.listener;
+package cn.flowerinsnow.greatscrollabletooltips.listener;
 
 import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.gui.screen.Screen;
-import online.flowerinsnow.greatscrollabletooltips.event.ScreenCloseEvent;
+import cn.flowerinsnow.greatscrollabletooltips.event.ScreenCloseEvent;
 
 public class EventTriggerListener implements ClientTickEvents.EndTick {
     private Screen oldScreen;
diff --git a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/listener/KeyScrollListener.java b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/listener/KeyScrollListener.java
similarity index 63%
rename from 1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/listener/KeyScrollListener.java
rename to 1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/listener/KeyScrollListener.java
index 3f0c726..935b016 100644
--- a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/listener/KeyScrollListener.java
+++ b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/listener/KeyScrollListener.java
@@ -1,17 +1,17 @@
-package online.flowerinsnow.greatscrollabletooltips.listener;
+package cn.flowerinsnow.greatscrollabletooltips.listener;
 
 import net.minecraft.client.gui.screen.ingame.HandledScreen;
 import net.minecraft.item.ItemStack;
 import net.minecraft.util.ActionResult;
-import online.flowerinsnow.greatscrollabletooltips.GreatScrollableTooltips;
-import online.flowerinsnow.greatscrollabletooltips.common.object.ScrollSession;
-import online.flowerinsnow.greatscrollabletooltips.event.PreScreenKeyPressedEvent;
-import online.flowerinsnow.greatscrollabletooltips.manager.KeyBindingManager;
+import cn.flowerinsnow.greatscrollabletooltips.GreatScrollableTooltips;
+import cn.flowerinsnow.greatscrollabletooltips.common.object.ScrollSession;
+import cn.flowerinsnow.greatscrollabletooltips.event.PreScreenKeyPressedEvent;
+import cn.flowerinsnow.greatscrollabletooltips.manager.KeyBindingManager;
 
-public class KeyScrollingListener implements PreScreenKeyPressedEvent {
+public record KeyScrollListener(GreatScrollableTooltips main) implements PreScreenKeyPressedEvent {
     @Override
     public ActionResult preScreenKeyPressed(HandledScreen screen, int keyCode, int scanCode, int modifiers) {
-        ScrollSession session = GreatScrollableTooltips.getInstance().getScrollSession();
+        ScrollSession session = this.main.getScrollSession();
         if (session.isRendering()) {
             if (KeyBindingManager.KEY_BINDING_SCROLL_UP.get().matchesKey(keyCode, scanCode)) {
                 session.addVertical(1);
diff --git a/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/listener/MouseScrollListener.java b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/listener/MouseScrollListener.java
new file mode 100644
index 0000000..32abce5
--- /dev/null
+++ b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/listener/MouseScrollListener.java
@@ -0,0 +1,31 @@
+package cn.flowerinsnow.greatscrollabletooltips.listener;
+
+import net.minecraft.client.gui.screen.Screen;
+import net.minecraft.client.gui.screen.ingame.HandledScreen;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.ActionResult;
+import cn.flowerinsnow.greatscrollabletooltips.GreatScrollableTooltips;
+import cn.flowerinsnow.greatscrollabletooltips.common.object.ScrollSession;
+import cn.flowerinsnow.greatscrollabletooltips.event.PreScreenMouseScrollEvent;
+
+public record MouseScrollListener(GreatScrollableTooltips main) implements PreScreenMouseScrollEvent {
+    @Override
+    public ActionResult preScreenMouseScrolled(HandledScreen screen, double mouseX, double mouseY, double amount) {
+        if (!this.main.getConfig().enable) {
+            return ActionResult.PASS;
+        }
+
+        ScrollSession session = this.main.getScrollSession();
+        if (!session.isRendering()) {
+            return ActionResult.PASS;
+        }
+
+        int i = Double.compare(amount, 0.0);
+        if (!Screen.hasShiftDown()) {
+            session.addVertical(i);
+        } else {
+            session.addHorizontal(i);
+        }
+        return ActionResult.PASS;
+    }
+}
diff --git a/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/listener/ScrollingStatusListener.java b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/listener/ScrollingStatusListener.java
new file mode 100644
index 0000000..d349fb2
--- /dev/null
+++ b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/listener/ScrollingStatusListener.java
@@ -0,0 +1,52 @@
+package cn.flowerinsnow.greatscrollabletooltips.listener;
+
+import net.minecraft.client.gui.screen.Screen;
+import net.minecraft.client.gui.screen.ingame.HandledScreen;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.item.ItemStack;
+import net.minecraft.screen.slot.Slot;
+import net.minecraft.util.ActionResult;
+import cn.flowerinsnow.greatscrollabletooltips.GreatScrollableTooltips;
+import cn.flowerinsnow.greatscrollabletooltips.common.object.ScrollSession;
+import cn.flowerinsnow.greatscrollabletooltips.event.RenderTooltipEvent;
+import cn.flowerinsnow.greatscrollabletooltips.event.ScreenCloseEvent;
+
+/**
+ * 处理滚动状态
+ */
+public record ScrollingStatusListener(GreatScrollableTooltips main) implements RenderTooltipEvent.Pre, RenderTooltipEvent.Miss, ScreenCloseEvent {
+    @Override
+    public ActionResult preRenderTooltip(HandledScreen screen, MatrixStack matrices, int x, int y, Slot focusedSlot) {
+        ScrollSession session = this.main.getScrollSession();
+        session.setRendering(true);
+        ItemStack itemStack = focusedSlot.getStack();
+        if (itemStack != session.getLastItemStackRendered()) {
+            session.setLastItemStackRendered(itemStack);
+
+            if (this.main.getConfig().autoReset) {
+                session.resetScroll();
+            }
+        }
+        return ActionResult.PASS;
+    }
+
+    @Override
+    public ActionResult missRenderTooltip(HandledScreen screen) {
+        ScrollSession session = this.main.getScrollSession();
+        session.setRendering(false);
+        session.setLastItemStackRendered(null);
+        if (this.main.getConfig().autoReset) {
+            session.resetScroll();;
+        }
+        return ActionResult.PASS;
+    }
+
+    @Override
+    public ActionResult onScreenClose(Screen oldScreen) {
+        ScrollSession session = this.main.getScrollSession();
+        session.setLastItemStackRendered(null);
+        session.setRendering(false);
+        session.resetScroll();
+        return ActionResult.PASS;
+    }
+}
diff --git a/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/manager/KeyBindingManager.java b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/manager/KeyBindingManager.java
new file mode 100644
index 0000000..f3c15e5
--- /dev/null
+++ b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/manager/KeyBindingManager.java
@@ -0,0 +1,20 @@
+package cn.flowerinsnow.greatscrollabletooltips.manager;
+
+import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
+import net.minecraft.client.option.KeyBinding;
+import cn.flowerinsnow.greatscrollabletooltips.util.Lazy;
+import org.lwjgl.glfw.GLFW;
+
+public class KeyBindingManager {
+    public static final Lazy KEY_BINDING_SCROLL_UP = new Lazy<>(() -> new KeyBinding("great-scrollable-tooltips.key-binding.scroll-up", GLFW.GLFW_KEY_UP, "great-scrollable-tooltips.key-binding.category"));
+    public static final Lazy KEY_BINDING_SCROLL_LEFT = new Lazy<>(() -> new KeyBinding("great-scrollable-tooltips.key-binding.scroll-left", GLFW.GLFW_KEY_LEFT, "great-scrollable-tooltips.key-binding.category"));
+    public static final Lazy KEY_BINDING_SCROLL_DOWN = new Lazy<>(() -> new KeyBinding("great-scrollable-tooltips.key-binding.scroll-down", GLFW.GLFW_KEY_DOWN, "great-scrollable-tooltips.key-binding.category"));
+    public static final Lazy KEY_BINDING_SCROLL_RIGHT = new Lazy<>(() -> new KeyBinding("great-scrollable-tooltips.key-binding.scroll-right", GLFW.GLFW_KEY_RIGHT, "great-scrollable-tooltips.key-binding.category"));
+
+    public static void registerAll() {
+        KeyBindingHelper.registerKeyBinding(KEY_BINDING_SCROLL_UP.get());
+        KeyBindingHelper.registerKeyBinding(KEY_BINDING_SCROLL_LEFT.get());
+        KeyBindingHelper.registerKeyBinding(KEY_BINDING_SCROLL_DOWN.get());
+        KeyBindingHelper.registerKeyBinding(KEY_BINDING_SCROLL_RIGHT.get());
+    }
+}
diff --git a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/mixin/AccessorSliderWidget.java b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/mixin/AccessorSliderWidget.java
similarity index 85%
rename from 1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/mixin/AccessorSliderWidget.java
rename to 1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/mixin/AccessorSliderWidget.java
index de367f7..5ab5dab 100644
--- a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/mixin/AccessorSliderWidget.java
+++ b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/mixin/AccessorSliderWidget.java
@@ -1,4 +1,4 @@
-package online.flowerinsnow.greatscrollabletooltips.mixin;
+package cn.flowerinsnow.greatscrollabletooltips.mixin;
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
diff --git a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/mixin/MixinHandledScreen.java b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/mixin/MixinHandledScreen.java
similarity index 53%
rename from 1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/mixin/MixinHandledScreen.java
rename to 1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/mixin/MixinHandledScreen.java
index 69b19a2..0b2606f 100644
--- a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/mixin/MixinHandledScreen.java
+++ b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/mixin/MixinHandledScreen.java
@@ -1,4 +1,4 @@
-package online.flowerinsnow.greatscrollabletooltips.mixin;
+package cn.flowerinsnow.greatscrollabletooltips.mixin;
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
@@ -7,7 +7,9 @@
 import net.minecraft.client.util.math.MatrixStack;
 import net.minecraft.screen.ScreenHandler;
 import net.minecraft.screen.slot.Slot;
-import online.flowerinsnow.greatscrollabletooltips.event.RenderMouseoverTooltipEvent;
+import cn.flowerinsnow.greatscrollabletooltips.event.PreScreenKeyPressedEvent;
+import cn.flowerinsnow.greatscrollabletooltips.event.PreScreenMouseScrollEvent;
+import cn.flowerinsnow.greatscrollabletooltips.event.RenderTooltipEvent;
 import org.spongepowered.asm.mixin.Final;
 import org.spongepowered.asm.mixin.Mixin;
 import org.spongepowered.asm.mixin.Shadow;
@@ -15,6 +17,7 @@
 import org.spongepowered.asm.mixin.injection.At;
 import org.spongepowered.asm.mixin.injection.Inject;
 import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
 
 @Mixin(HandledScreen.class)
 @Environment(EnvType.CLIENT)
@@ -36,13 +39,27 @@ protected MixinHandledScreen() {
 
     @Inject(
             method = "drawMouseoverTooltip",
-            at = @At("RETURN")
+            at = @At("HEAD")
     )
     public void drawMouseoverTooltip(MatrixStack matrices, int x, int y, CallbackInfo ci) {
         if (this.handler.getCursorStack().isEmpty() && this.focusedSlot != null && this.focusedSlot.hasStack()) {
-            RenderMouseoverTooltipEvent.Post.EVENT.invoker().startDrawMouseoverTooltip(THIS, matrices, this.focusedSlot.getStack(), x, y);
+            RenderTooltipEvent.Pre.EVENT.invoker().preRenderTooltip(this.THIS, matrices, x, y, this.focusedSlot);
         } else {
-            RenderMouseoverTooltipEvent.Miss.EVENT.invoker().onMiss(THIS);
+            RenderTooltipEvent.Miss.EVENT.invoker().missRenderTooltip(this.THIS);
         }
     }
+
+    @Inject(
+            method = "keyPressed",
+            at = @At("HEAD")
+    )
+    public void preKeyPressed(int keyCode, int scanCode, int modifiers, CallbackInfoReturnable cir) {
+        PreScreenKeyPressedEvent.EVENT.invoker().preScreenKeyPressed(this.THIS, keyCode, scanCode, modifiers);
+    }
+
+    @Override
+    public boolean mouseScrolled(double mouseX, double mouseY, double amount) {
+        PreScreenMouseScrollEvent.EVENT.invoker().preScreenMouseScrolled(this.THIS, mouseX, mouseY, amount);
+        return super.mouseScrolled(mouseX, mouseY, amount);
+    }
 }
diff --git a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/mixin/MixinScreen.java b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/mixin/MixinScreen.java
similarity index 51%
rename from 1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/mixin/MixinScreen.java
rename to 1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/mixin/MixinScreen.java
index 9ebe1b3..2c763ad 100644
--- a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/mixin/MixinScreen.java
+++ b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/mixin/MixinScreen.java
@@ -1,9 +1,9 @@
-package online.flowerinsnow.greatscrollabletooltips.mixin;
+package cn.flowerinsnow.greatscrollabletooltips.mixin;
 
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
 import net.minecraft.client.gui.screen.Screen;
-import online.flowerinsnow.greatscrollabletooltips.GreatScrollableTooltips;
+import cn.flowerinsnow.greatscrollabletooltips.GreatScrollableTooltips;
 import org.objectweb.asm.Opcodes;
 import org.spongepowered.asm.mixin.Mixin;
 import org.spongepowered.asm.mixin.injection.At;
@@ -12,6 +12,20 @@
 @Mixin(Screen.class)
 @Environment(EnvType.CLIENT)
 public class MixinScreen {
+    @ModifyVariable(
+            method = "renderTooltipFromComponents",
+            at = @At(
+                    value = "LOAD",
+                    opcode = Opcodes.ILOAD,
+                    ordinal = 2
+            ),
+            index = 7
+    )
+    private int modifyX(int value) {
+        GreatScrollableTooltips instance = GreatScrollableTooltips.getInstance();
+        return value + instance.getScrollSession().getHorizontal() * instance.getConfig().sensitivity;
+    }
+
     @ModifyVariable(
             method = "renderTooltipFromComponents",
             at = @At(
@@ -23,6 +37,6 @@ public class MixinScreen {
     )
     private int modifyY(int value) {
         GreatScrollableTooltips instance = GreatScrollableTooltips.getInstance();
-        return value + instance.getVertical() * instance.getConfig().sensitivity;
+        return value + instance.getScrollSession().getVertical() * instance.getConfig().sensitivity;
     }
 }
diff --git a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/modmenu/ModMenuImpl.java b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/modmenu/ModMenuImpl.java
similarity index 68%
rename from 1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/modmenu/ModMenuImpl.java
rename to 1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/modmenu/ModMenuImpl.java
index 85fee43..37e11d3 100644
--- a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/modmenu/ModMenuImpl.java
+++ b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/modmenu/ModMenuImpl.java
@@ -1,11 +1,11 @@
-package online.flowerinsnow.greatscrollabletooltips.modmenu;
+package cn.flowerinsnow.greatscrollabletooltips.modmenu;
 
 import com.terraformersmc.modmenu.api.ConfigScreenFactory;
 import com.terraformersmc.modmenu.api.ModMenuApi;
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
-import online.flowerinsnow.greatscrollabletooltips.GreatScrollableTooltips;
-import online.flowerinsnow.greatscrollabletooltips.screen.ConfigScreen;
+import cn.flowerinsnow.greatscrollabletooltips.GreatScrollableTooltips;
+import cn.flowerinsnow.greatscrollabletooltips.screen.ConfigScreen;
 
 @Environment(EnvType.CLIENT)
 public class ModMenuImpl implements ModMenuApi {
diff --git a/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/screen/ConfigScreen.java b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/screen/ConfigScreen.java
new file mode 100644
index 0000000..a8dbde4
--- /dev/null
+++ b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/screen/ConfigScreen.java
@@ -0,0 +1,147 @@
+package cn.flowerinsnow.greatscrollabletooltips.screen;
+
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.gui.DrawableHelper;
+import net.minecraft.client.gui.screen.Screen;
+import net.minecraft.client.gui.widget.ButtonWidget;
+import net.minecraft.client.gui.widget.SliderWidget;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.text.TranslatableText;
+import cn.flowerinsnow.greatscrollabletooltips.common.config.GreatScrollableTooltipsConfig;
+import cn.flowerinsnow.greatscrollabletooltips.mixin.AccessorSliderWidget;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
+@Environment(EnvType.CLIENT)
+public class ConfigScreen extends Screen {
+    private final Screen parent;
+    private final GreatScrollableTooltipsConfig config;
+    private SliderWidget sensitivitySlider;
+    public ConfigScreen(Screen parent, GreatScrollableTooltipsConfig config) {
+        super(new TranslatableText("great-scrollable-tooltips.ui.title"));
+        this.parent = parent;
+        this.config = config;
+    }
+
+    @Override
+    protected void init() {
+        this.addDrawableChild(
+                new ButtonWidget(
+                        this.width / 2 - 100, this.height / 2 - 70,
+                        200, 20,
+                        new TranslatableText(this.config.enable ? "great-scrollable-tooltips.ui.config.enable.true" : "great-scrollable-tooltips.ui.config.enable.false"),
+                        button -> {
+                            ConfigScreen screen = ConfigScreen.this;
+                            if (screen.config.enable) {
+                                button.setMessage(new TranslatableText("great-scrollable-tooltips.ui.config.enable.false"));
+                                screen.config.enable = false;
+                            } else {
+                                button.setMessage(new TranslatableText("great-scrollable-tooltips.ui.config.enable.true"));
+                                screen.config.enable = true;
+                            }
+                        }
+                )
+        );
+
+        this.addDrawableChild(
+                new ButtonWidget(
+                        this.width / 2 - 100, this.height / 2 - 45,
+                        200, 20,
+                        new TranslatableText(this.config.autoReset ? "great-scrollable-tooltips.ui.config.auto-reset.true" : "great-scrollable-tooltips.ui.config.auto-reset.false"),
+                        button -> {
+                            ConfigScreen screen = ConfigScreen.this;
+                            if (screen.config.autoReset) {
+                                button.setMessage(new TranslatableText("great-scrollable-tooltips.ui.config.auto-reset.false"));
+                                screen.config.autoReset = false;
+                            } else {
+                                button.setMessage(new TranslatableText("great-scrollable-tooltips.ui.config.auto-reset.true"));
+                                screen.config.autoReset = true;
+                            }
+                        }
+                )
+        );
+
+        this.addDrawableChild(
+                this.sensitivitySlider = new SliderWidget(
+                        this.width / 2 - 100, this.height / 2 - 20,
+                        200, 20,
+                        new TranslatableText("great-scrollable-tooltips.ui.config.sensitivity", this.config.sensitivity),
+                        new BigDecimal(this.config.sensitivity)
+                                .add(new BigDecimal(-1))
+                                .divide(new BigDecimal(99), 2, RoundingMode.DOWN)
+                                .doubleValue()
+                ) {
+                    @Override
+                    protected void updateMessage() {
+                        this.setMessage(
+                                new TranslatableText(
+                                        "great-scrollable-tooltips.ui.config.sensitivity",
+                                        BigDecimal.valueOf(this.value)
+                                                .multiply(new BigDecimal(99))
+                                                .add(BigDecimal.ONE)
+                                                .setScale(0, RoundingMode.DOWN)
+                                                .intValue()
+                                )
+                        );
+                    }
+
+                    @Override
+                    protected void applyValue() {
+                    }
+                }
+        );
+
+        this.addDrawableChild(
+                new ButtonWidget(
+                        this.width / 2 - 100, this.height / 2 + 5,
+                        200, 20,
+                        new TranslatableText("great-scrollable-tooltips.ui.config.reload"),
+                        button -> {
+                            ConfigScreen screen = ConfigScreen.this;
+                            screen.config.load();
+                            MinecraftClient.getInstance().currentScreen = new ConfigScreen(screen.parent, screen.config);
+                        }
+                )
+        );
+
+        this.addDrawableChild(
+                new ButtonWidget(
+                        this.width / 2 - 100, this.height / 2 + 30,
+                        200, 20,
+                        new TranslatableText("great-scrollable-tooltips.ui.config.save-and-exit"),
+                        button -> {
+                            ConfigScreen.this.config.sensitivity = BigDecimal.valueOf(((AccessorSliderWidget) sensitivitySlider).getValue())
+                                    .multiply(new BigDecimal(99))
+                                    .add(BigDecimal.ONE)
+                                    .setScale(0, RoundingMode.DOWN)
+                                    .intValue();
+                            ConfigScreen.this.config.save();
+                            MinecraftClient.getInstance().currentScreen = ConfigScreen.this.parent;
+                        }
+                )
+        );
+
+        this.addDrawableChild(
+                new ButtonWidget(
+                        this.width / 2 - 100, this.height / 2 + 55,
+                        200, 20,
+                        new TranslatableText("great-scrollable-tooltips.ui.config.discard-and-exit"),
+                        button -> MinecraftClient.getInstance().currentScreen = ConfigScreen.this.parent
+                )
+        );
+    }
+
+    @Override
+    public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
+        this.renderBackground(matrices);
+        super.render(matrices, mouseX, mouseY, delta);
+        DrawableHelper.drawCenteredTextWithShadow(
+                matrices, this.textRenderer,
+                new TranslatableText("great-scrollable-tooltips.ui.title").asOrderedText(),
+                this.width / 2, 20, 0xFFFFFF
+        );
+    }
+}
diff --git a/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/util/Lazy.java b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/util/Lazy.java
new file mode 100644
index 0000000..93d29e2
--- /dev/null
+++ b/1.17-1.17.1-fabric/src/main/java/cn/flowerinsnow/greatscrollabletooltips/util/Lazy.java
@@ -0,0 +1,22 @@
+package cn.flowerinsnow.greatscrollabletooltips.util;
+
+import java.util.Objects;
+import java.util.function.Supplier;
+
+public class Lazy {
+    private T value;
+    private final Supplier supplier;
+    private boolean supplied;
+
+    public Lazy(Supplier supplier) {
+        this.supplier = Objects.requireNonNull(supplier);
+    }
+
+    public T get() {
+        if (this.supplied) {
+            return this.value;
+        }
+        this.supplied = true;
+        return (this.value = this.supplier.get());
+    }
+}
\ No newline at end of file
diff --git a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/GreatScrollableTooltips.java b/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/GreatScrollableTooltips.java
deleted file mode 100644
index df6fa34..0000000
--- a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/GreatScrollableTooltips.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package online.flowerinsnow.greatscrollabletooltips;
-
-import net.fabricmc.api.ClientModInitializer;
-import net.fabricmc.api.EnvType;
-import net.fabricmc.api.Environment;
-import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.util.ActionResult;
-import online.flowerinsnow.greatscrollabletooltips.config.Config;
-import online.flowerinsnow.greatscrollabletooltips.event.MouseScrolledInParentElementEvent;
-import online.flowerinsnow.greatscrollabletooltips.event.RenderMouseoverTooltipEvent;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@Environment(EnvType.CLIENT)
-public class GreatScrollableTooltips implements ClientModInitializer {
-	public static final String MODID = "great-scrollable-tooltips";
-    public static final Logger LOGGER = LoggerFactory.getLogger(MODID);
-
-	private static GreatScrollableTooltips instance;
-
-	private Config config;
-
-	private int vertical;
-	private boolean rendering;
-
-	@Override
-	public void onInitializeClient() {
-		instance = this;
-
-		config = new Config();
-		config.saveDefaultConfig();
-		config.load();
-
-		MouseScrolledInParentElementEvent.EVENT.register((parentElement, mouseX, mouseY, amount) -> {
-			MinecraftClient client = MinecraftClient.getInstance();
-			if (client.currentScreen != null && config.enable && rendering) {
-				vertical += (int) amount;
-			}
-			return ActionResult.PASS;
-		});
-
-		RenderMouseoverTooltipEvent.Post.EVENT.register((screen, matrices, stack, x, y) -> {
-			rendering = true;
-			return ActionResult.PASS;
-		});
-
-		RenderMouseoverTooltipEvent.Miss.EVENT.register(screen -> {
-			rendering = false;
-			return ActionResult.PASS;
-		});
-
-		ClientTickEvents.END_CLIENT_TICK.register(client -> {
-			if (client.currentScreen == null) {
-				vertical = 0;
-			}
-		});
-	}
-
-	public static GreatScrollableTooltips getInstance() {
-		return instance;
-	}
-
-	public Config getConfig() {
-		return config;
-	}
-
-	public int getVertical() {
-		return vertical;
-	}
-
-	public void setVertical(int vertical) {
-		this.vertical = vertical;
-	}
-}
\ No newline at end of file
diff --git a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/event/PreScreenKeyPressedEvent.java b/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/event/PreScreenKeyPressedEvent.java
deleted file mode 100644
index ee76c4f..0000000
--- a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/event/PreScreenKeyPressedEvent.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package online.flowerinsnow.greatscrollabletooltips.event;
-
-public interface PreScreenKeyPressedEvent {
-}
diff --git a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/event/PreScreenMouseScrollEvent.java b/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/event/PreScreenMouseScrollEvent.java
deleted file mode 100644
index 5671e7d..0000000
--- a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/event/PreScreenMouseScrollEvent.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package online.flowerinsnow.greatscrollabletooltips.event;
-
-public interface PreScreenMouseScrollEvent {
-}
diff --git a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/event/ScreenCloseEvent.java b/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/event/ScreenCloseEvent.java
deleted file mode 100644
index 7dfae55..0000000
--- a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/event/ScreenCloseEvent.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package online.flowerinsnow.greatscrollabletooltips.event;
-
-public class ScreenCloseEvent {
-}
diff --git a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/listener/MouseScrollListener.java b/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/listener/MouseScrollListener.java
deleted file mode 100644
index 414df0b..0000000
--- a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/listener/MouseScrollListener.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package online.flowerinsnow.greatscrollabletooltips.listener;
-
-public class MouseScrollListener {
-}
diff --git a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/listener/ScrollingStatusListener.java b/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/listener/ScrollingStatusListener.java
deleted file mode 100644
index 5a1deac..0000000
--- a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/listener/ScrollingStatusListener.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package online.flowerinsnow.greatscrollabletooltips.listener;
-
-public class ScrollingStatusListener {
-}
diff --git a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/manager/KeyBindingManager.java b/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/manager/KeyBindingManager.java
deleted file mode 100644
index 7d008b8..0000000
--- a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/manager/KeyBindingManager.java
+++ /dev/null
@@ -1,4 +0,0 @@
-package online.flowerinsnow.greatscrollabletooltips.manager;
-
-public class KeyBindingManager {
-}
diff --git a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/screen/ConfigScreen.java b/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/screen/ConfigScreen.java
deleted file mode 100644
index 5a6e789..0000000
--- a/1.17-1.17.1-fabric/src/main/java/online/flowerinsnow/greatscrollabletooltips/screen/ConfigScreen.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package online.flowerinsnow.greatscrollabletooltips.screen;
-
-import net.fabricmc.api.EnvType;
-import net.fabricmc.api.Environment;
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.gui.DrawableHelper;
-import net.minecraft.client.gui.screen.Screen;
-import net.minecraft.client.gui.widget.ButtonWidget;
-import net.minecraft.client.gui.widget.SliderWidget;
-import net.minecraft.client.util.math.MatrixStack;
-import net.minecraft.text.TranslatableText;
-import online.flowerinsnow.greatscrollabletooltips.config.Config;
-import online.flowerinsnow.greatscrollabletooltips.mixin.AccessorSliderWidget;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-
-@Environment(EnvType.CLIENT)
-public class ConfigScreen extends Screen {
-    private final Screen parent;
-    private final Config config;
-    private SliderWidget sensitivitySlider;
-    public ConfigScreen(Screen parent, Config config) {
-        super(new TranslatableText("great-scrollable-tooltips.ui.title"));
-        this.parent = parent;
-        this.config = config;
-    }
-
-    @Override
-    protected void init() {
-        this.addDrawableChild(
-                new ButtonWidget(
-                        this.width / 2 - 100, this.height / 2 - 60,
-                        200, 20,
-                        new TranslatableText(config.enable ? "great-scrollable-tooltips.ui.config.enable.true" : "great-scrollable-tooltips.ui.config.enable.false"),
-                        button -> {
-                            if (config.enable) {
-                                button.setMessage(new TranslatableText("great-scrollable-tooltips.ui.config.enable.false"));
-                                config.enable = false;
-                            } else {
-                                button.setMessage(new TranslatableText("great-scrollable-tooltips.ui.config.enable.true"));
-                                config.enable = true;
-                            }
-                        }
-                )
-        );
-        this.addDrawableChild(
-                sensitivitySlider = new SliderWidget(this.width / 2 - 100, this.height / 2 - 35,
-                200, 20, new TranslatableText(
-                        "great-scrollable-tooltips.ui.config.sensitivity",
-                        config.sensitivity
-                ), new BigDecimal(config.sensitivity).add(new BigDecimal(-1)).divide(new BigDecimal(99), 2, RoundingMode.DOWN).doubleValue()) {
-                    @Override
-                    protected void updateMessage() {
-                        setMessage(new TranslatableText(
-                                "great-scrollable-tooltips.ui.config.sensitivity",
-                                BigDecimal.valueOf(value).multiply(new BigDecimal(99)).add(BigDecimal.ONE).setScale(0, RoundingMode.DOWN).intValue()
-                        ));
-                    }
-
-                    @Override
-                    protected void applyValue() {
-                    }
-                }
-        );
-        this.addDrawableChild(
-                new ButtonWidget(
-                        this.width / 2 - 100, this.height / 2 - 10,
-                        200, 20,
-                        new TranslatableText("great-scrollable-tooltips.ui.config.reload"),
-                        button -> {
-                            config.load();
-                            MinecraftClient.getInstance().currentScreen = new ConfigScreen(parent, config);
-                        }
-                )
-        );
-        this.addDrawableChild(
-                new ButtonWidget(
-                        this.width / 2 - 100, this.height / 2 + 15,
-                        200, 20,
-                        new TranslatableText("great-scrollable-tooltips.ui.config.save-and-exit"),
-                        button -> {
-                            config.sensitivity = BigDecimal.valueOf(((AccessorSliderWidget) sensitivitySlider).getValue()).multiply(new BigDecimal(99)).add(BigDecimal.ONE).setScale(0, RoundingMode.DOWN).intValue();
-                            config.save();
-                            MinecraftClient.getInstance().currentScreen = parent;
-                        }
-                )
-        );
-        this.addDrawableChild(
-                new ButtonWidget(
-                        this.width / 2 - 100, this.height / 2 + 40,
-                        200, 20,
-                        new TranslatableText("great-scrollable-tooltips.ui.config.discard-and-exit"),
-                        button -> MinecraftClient.getInstance().currentScreen = parent
-                )
-        );
-    }
-
-    @Override
-    public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
-        this.renderBackground(matrices);
-        super.render(matrices, mouseX, mouseY, delta);
-        DrawableHelper.drawCenteredTextWithShadow(matrices, this.textRenderer, new TranslatableText("great-scrollable-tooltips.ui.title").asOrderedText(), this.width / 2, 20, 0xFFFFFF);
-    }
-}
diff --git a/1.17-1.17.1-fabric/src/main/resources/assets/great-scrollable-tooltips/lang/en_us.json b/1.17-1.17.1-fabric/src/main/resources/assets/great-scrollable-tooltips/lang/en_us.json
index 5c777c9..27a3a8d 100644
--- a/1.17-1.17.1-fabric/src/main/resources/assets/great-scrollable-tooltips/lang/en_us.json
+++ b/1.17-1.17.1-fabric/src/main/resources/assets/great-scrollable-tooltips/lang/en_us.json
@@ -2,8 +2,16 @@
     "great-scrollable-tooltips.ui.title": "Great Scrollable Tooltips",
     "great-scrollable-tooltips.ui.config.enable.true": "Enable: §atrue",
     "great-scrollable-tooltips.ui.config.enable.false": "Enable: §cfalse",
+    "great-scrollable-tooltips.ui.config.auto-reset.true": "Auto reset: §atrue",
+    "great-scrollable-tooltips.ui.config.auto-reset.false": "Auto reset: §cfalse",
+    "great-scrollable-tooltips.ui.config.auto-reset.tooltip": "Reset scrolling when cursor moves away from item",
     "great-scrollable-tooltips.ui.config.sensitivity": "Sensitivity: %s",
     "great-scrollable-tooltips.ui.config.reload": "Reload config",
     "great-scrollable-tooltips.ui.config.save-and-exit": "Save and exit",
-    "great-scrollable-tooltips.ui.config.discard-and-exit": "Discard and exit"
+    "great-scrollable-tooltips.ui.config.discard-and-exit": "Discard and exit",
+    "great-scrollable-tooltips.key-binding.category": "Great Scrollable Tooltips",
+    "great-scrollable-tooltips.key-binding.scroll-up": "Scroll up",
+    "great-scrollable-tooltips.key-binding.scroll-left": "Scroll left",
+    "great-scrollable-tooltips.key-binding.scroll-down": "Scroll down",
+    "great-scrollable-tooltips.key-binding.scroll-right": "Scroll right"
 }
\ No newline at end of file
diff --git a/1.17-1.17.1-fabric/src/main/resources/assets/great-scrollable-tooltips/lang/zh_cn.json b/1.17-1.17.1-fabric/src/main/resources/assets/great-scrollable-tooltips/lang/zh_cn.json
index 2071b1d..5ff191e 100644
--- a/1.17-1.17.1-fabric/src/main/resources/assets/great-scrollable-tooltips/lang/zh_cn.json
+++ b/1.17-1.17.1-fabric/src/main/resources/assets/great-scrollable-tooltips/lang/zh_cn.json
@@ -2,8 +2,16 @@
     "great-scrollable-tooltips.ui.title": "Great Scrollable Tooltips",
     "great-scrollable-tooltips.ui.config.enable.true": "启用:§atrue",
     "great-scrollable-tooltips.ui.config.enable.false": "启用:§cfalse",
+    "great-scrollable-tooltips.ui.config.auto-reset.true": "自动回正: §atrue",
+    "great-scrollable-tooltips.ui.config.auto-reset.false": "自动回正: §cfalse",
+    "great-scrollable-tooltips.ui.config.auto-reset.tooltip": "当光标从物品上移开时回正滚动",
     "great-scrollable-tooltips.ui.config.sensitivity": "灵敏度:%s",
     "great-scrollable-tooltips.ui.config.reload": "重载配置",
     "great-scrollable-tooltips.ui.config.save-and-exit": "保存并退出",
-    "great-scrollable-tooltips.ui.config.discard-and-exit": "放弃并退出"
+    "great-scrollable-tooltips.ui.config.discard-and-exit": "放弃并退出",
+    "great-scrollable-tooltips.key-binding.category": "Great Scrollable Tooltips",
+    "great-scrollable-tooltips.key-binding.scroll-up": "向上滚动",
+    "great-scrollable-tooltips.key-binding.scroll-left": "向左滚动",
+    "great-scrollable-tooltips.key-binding.scroll-down": "向下滚动",
+    "great-scrollable-tooltips.key-binding.scroll-right": "向右滚动"
 }
\ No newline at end of file
diff --git a/1.17-1.17.1-fabric/src/main/resources/config.toml b/1.17-1.17.1-fabric/src/main/resources/config.toml
index 1ef9020..dc74841 100644
--- a/1.17-1.17.1-fabric/src/main/resources/config.toml
+++ b/1.17-1.17.1-fabric/src/main/resources/config.toml
@@ -1,2 +1,3 @@
-enable 'true'
-sensitivity '5'
\ No newline at end of file
+enable = true
+sensitivity = 5
+auto_reset = true
\ No newline at end of file
diff --git a/1.17-1.17.1-fabric/src/main/resources/fabric.mod.json b/1.17-1.17.1-fabric/src/main/resources/fabric.mod.json
index a1e2f64..e327de4 100644
--- a/1.17-1.17.1-fabric/src/main/resources/fabric.mod.json
+++ b/1.17-1.17.1-fabric/src/main/resources/fabric.mod.json
@@ -9,18 +9,18 @@
 	],
 	"contact": {
 		"homepage": "https://modrinth.com/project/great-scrollable-tooltips",
-		"sources": "https://github.com/flowerinsnow-lights-opensource/GreatScrollableTooltips",
-		"issues": "https://github.com/flowerinsnow-lights-opensource/GreatScrollableTooltips/issues"
+		"sources": "https://github.com/flowerinsnowdh/GreatScrollableTooltips",
+		"issues": "https://github.com/flowerinsnowdh/GreatScrollableTooltips/issues"
 	},
-	"license": "GPL-3.0",
+	"license": "MPL-2.0",
 	"icon": "assets/great-scrollable-tooltips/icon.png",
 	"environment": "client",
 	"entrypoints": {
 		"client": [
-			"online.flowerinsnow.greatscrollabletooltips.GreatScrollableTooltips"
+			"cn.flowerinsnow.greatscrollabletooltips.GreatScrollableTooltips"
 		],
 		"modmenu": [
-			"online.flowerinsnow.greatscrollabletooltips.modmenu.ModMenuImpl"
+			"cn.flowerinsnow.greatscrollabletooltips.modmenu.ModMenuImpl"
 		]
 	},
 	"mixins": [
@@ -33,12 +33,12 @@
 		"fabric": ">=0.34.9"
 	},
 	"suggests": {
-		"another-mod": ">=2.0.2"
+		"modmenu": ">=2.0.2"
 	},
 	"custom": {
 		"modmenu": {
 			"links": {
-				"modmenu.github_releases": "https://github.com/flowerinsnow-lights-opensource/GreatScrollableTooltips/releases"
+				"modmenu.github_releases": "https://github.com/flowerinsnowdh/GreatScrollableTooltips/releases"
 			}
 		}
 	}
diff --git a/1.17-1.17.1-fabric/src/main/resources/great-scrollable-tooltips.mixins.json b/1.17-1.17.1-fabric/src/main/resources/great-scrollable-tooltips.mixins.json
index 67a529a..a488619 100644
--- a/1.17-1.17.1-fabric/src/main/resources/great-scrollable-tooltips.mixins.json
+++ b/1.17-1.17.1-fabric/src/main/resources/great-scrollable-tooltips.mixins.json
@@ -1,12 +1,11 @@
 {
 	"required": true,
-	"package": "online.flowerinsnow.greatscrollabletooltips.mixin",
+	"package": "cn.flowerinsnow.greatscrollabletooltips.mixin",
 	"compatibilityLevel": "JAVA_16",
     "client": [
         "AccessorSliderWidget",
         "MixinScreen",
-        "MixinHandledScreen",
-        "MixinInventoryScreen"
+        "MixinHandledScreen"
     ],
 	"injectors": {
 		"defaultRequire": 1