diff --git a/README.md b/README.md
index b2e4a063172aad1002ea54a7d4dd4a676c494064..c5f88489f19df60a683ea035ec3d7ba5ebaf4ea8 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # gnome-keyring-yubikey-unlock
 
-![](https://img.shields.io/badge/CXXSTD-C%2B%2B14-green)
+![](https://img.shields.io/badge/CXXSTD-C%2B%2B17-green)
 
 Use GnuPG to unlock gnome-keyring, which is supported by yubikey and other smartcard.
 
@@ -15,11 +15,40 @@ Currently the only solution is to set the password of `login` keyring to empty.
 
 I encrypt the `keyring-name : password` pair with GnuPG and save it as `secret-file`. Then on starting gnome, you have yubikey inserted. Then an auto-started script call GnuPG to decrypt the secret file, and pipe use the password to unlock your keyring. GnuPG will ask you to insert yubikey.
 
-## Dependencies
+## Usage
+
+> I recommend you to **configure Yubikey as GPG smartcard**. The system would just ask you to unlock gnome-keyring with your default GPG software. You may generate a new GPG key for yubikey, or move your existing GPG key into yubikey. Refer to google for these knowledge.
+
+First, download this repo. Note the `--recursive` flag, that one's important
+
+```
+git clone https://github.com/recolic/gnome-keyring-yubikey-unlock --recursive
+cd gnome-keyring-yubikey-unlock/src && make && cd ..
+```
+
+Secondly, choose an implementation: `standalone` impl only allows to unlock default keyring, and `lib` impl requires an extra library.
+
+<details>
+  <summary>Standalone Implementation</summary>
+
+```
+cd gnome-keyring-yubikey-unlock/src && make KEYRING_IMPL=standalone && cd ..
+```
+
+</details>
+
+<details>
+  <summary>Lib Implementation</summary>
+
+```
+cd gnome-keyring-yubikey-unlock/src && make KEYRING_IMPL=lib && cd ..
+```
+
+### Extra Dependency for "lib" implementation
 
 The project uses libgnome-keyring-dev
 
-### Ubuntu 20.04
+#### Ubuntu 20.04
 
 libgnome-keyring-dev is not in the repositories, you have to install it and its dependencies manually:
 
@@ -37,37 +66,32 @@ sudo dpkg -i libgnome-keyring-common_3.12.0-1build1_all.deb libgnome-keyring0_3.
 sudo apt --fix-broken -y install
 ```
 
-### Arch Linux
+#### Arch Linux
 
 ```
 sudo pacman -S libgnome-keyring
 ```
 
-### Other Distro
+#### Other Distro
 
 If your distribution is not providing libgnome-keyring, you can get the `.so` library from <https://archlinux.org/packages/extra/x86_64/libgnome-keyring/download>. 
+</details>
 
-## Usage
-
-> I recommend you to **configure Yubikey as GPG smartcard**. The system would just ask you to unlock gnome-keyring with your default GPG software. You may generate a new GPG key for yubikey, or move your existing GPG key into yubikey. Refer to google for these knowledge.
-
-First, build the project from source. Note the `--recursive` flag, that one's important
+Then, create your secret file. You may use my naive script (just in case you don't know GnuPG usage), or create an GnuPG-encrypted file by yourself.
 
-```
-git clone https://github.com/recolic/gnome-keyring-yubikey-unlock --recursive
-cd gnome-keyring-yubikey-unlock/src && make && cd ..
-```
+For example, you could say `login:My_Very_Long_Login_Password`. (You may use `seahorse` or `tools/list_keyrings.sh` to determine the name of your keyring)
 
-Then, create your secret file.
+<details>
+  <summary>To use my naive secret file creation script</summary>
 
 ```
 gnome-keyring-yubikey-unlock/create_secret_file.sh /path/to/your_secret [Your GnuPG public key]
-# input your keyring:password
+# input your keyring_name:password
 ```
 
-As an example, I need to input `login:My_Very_Long_Login_Password`. (You may use `seahorse` or `tools/list_keyrings.sh` to determine the name of your keyring)
+</details>
 
-Then, add the following command to gnome-autostart. If you don't know how to do it, [read me](doc/how-to-gnome-autostart.md)! 
+Then, add the following command to gnome-autostart. If you don't know how to do it, [read me](doc/how-to-gnome-autostart.md).
 
 ```
 /path/to/this/project/unlock_keyrings.sh /path/to/your_secret
diff --git a/src/Makefile b/src/Makefile
index 5ee5a0790d920f0d3d0137d9841876b58db1a2c0..713cfe8a870fced7580f77c54d4fc77eddce0926 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,10 +1,14 @@
 
 CXX ?= g++
-# Accepts CXXSTD >= C++14
-CXXFLAGS := $(shell pkg-config --cflags --libs gnome-keyring-1) -I ./lib -I . -std=c++14
-EXTRA_FLAGS ?=
+CXXFLAGS := -I ./lib -I . -std=c++17 -DKEYRING_IMPL_$(KEYRING_IMPL)
+
+ifeq ($(KEYRING_IMPL),lib)
+    CXXFLAGS += $(shell pkg-config --cflags --libs gnome-keyring-1)
+else ifneq ($(KEYRING_IMPL),standalone)
+$(error "KEYRING_IMPL must be set to 'lib' or 'standalone'. Example: 'make KEYRING_IMPL=standalone'")
+endif
 
 secret:
 	mkdir -p ../bin/
-	$(CXX)  unlock_keyrings.cc -o ../bin/unlock_keyrings $(CXXFLAGS) $(EXTRA_FLAGS)
+	$(CXX) unlock_keyrings.cc -o ../bin/unlock_keyrings $(CXXFLAGS)
 
diff --git a/src/keyring_op.hpp b/src/impl-libgnome-keyring.hpp
similarity index 80%
rename from src/keyring_op.hpp
rename to src/impl-libgnome-keyring.hpp
index de9d1da0c84e68c7fe2baab98a5f5a9d0efda442..f30ffddc631be1bc3363da972162ee654cf169b7 100644
--- a/src/keyring_op.hpp
+++ b/src/impl-libgnome-keyring.hpp
@@ -1,3 +1,10 @@
+/*
+ * This is an implementation to unlock gnome keyring.
+ * It talks to `org.gnome.keyring.InternalUnsupportedGuiltRiddenInterface` through `/run/user/1000/bus`,
+ *   calling the `UnlockWithMasterPassword` function, to unlock the keyring.
+ * It involves multiple send/recv, allows unlocking any keyring.
+ */
+
 #include <gnome-keyring-1/gnome-keyring.h>
 #include <string>
 #include <rlib/macro.hpp>
diff --git a/src/impl-standalone.hpp b/src/impl-standalone.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..db93ec389243a7940586afabe46f0acfd142271f
--- /dev/null
+++ b/src/impl-standalone.hpp
@@ -0,0 +1,120 @@
+/*
+ * This is another implementation to unlock gnome keyring.
+ * It sends a hand-crafted control message to `/run/user/1000/keyring/control`, to unlock the keyring.
+ * This interface is easier, not requiring external lib, but only allows unlocking default keyring.
+ *
+ * Credit: https://github.com/umglurf/gnome-keyring-unlock
+ *         https://codeberg.org/umglurf/gnome-keyring-unlock
+ *         (This repo also tells you how to unlock with TPM)
+ */
+
+#include <rlib/macro.hpp>
+#include <rlib/scope_guard.hpp>
+#include <rlib/sys/sio.hpp>
+#include <filesystem>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+
+namespace utils {
+    inline auto get_control_socket() {
+        namespace fs = std::filesystem;
+    
+        // Helper function to check if a path is a socket
+        auto is_socket = [](const fs::path& path) {
+            struct stat s;
+            return stat(path.c_str(), &s) == 0 && S_ISSOCK(s.st_mode);
+        };
+    
+        if (const char* gnome_keyring_control = std::getenv("GNOME_KEYRING_CONTROL")) {
+            fs::path control_socket = fs::path(gnome_keyring_control) / "control";
+            if (fs::exists(control_socket) && is_socket(control_socket)) {
+                return control_socket;
+            }
+        }
+    
+        if (const char* xdg_runtime_dir = std::getenv("XDG_RUNTIME_DIR")) {
+            fs::path control_socket = fs::path(xdg_runtime_dir) / "keyring/control";
+            if (fs::exists(control_socket) && is_socket(control_socket)) {
+                return control_socket;
+            }
+        }
+    
+        throw std::runtime_error("Unable to find control socket");
+    }
+    
+    inline int connect_unix_socket(std::string path) {
+        // Create a UNIX socket
+        int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
+        if (sockfd == -1) {
+            throw std::runtime_error("Unable to create unix socket");
+        }
+    
+        // Set up socket address
+        struct sockaddr_un addr {};
+        addr.sun_family = AF_UNIX;
+        std::strncpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path) - 1);
+    
+        // Connect to the socket
+        if (connect(sockfd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) == -1) {
+            close(sockfd);
+            throw std::runtime_error("Unable to connect to unix socket");
+        }
+        return sockfd;
+    }
+
+    enum ControlOp : uint32_t {
+        INITIALIZE = 0,
+        UNLOCK = 1,
+        CHANGE = 2,
+        QUIT = 4
+    };
+
+    enum ControlRes : uint32_t {
+        OK = 0,
+        DENIED = 1,
+        FAILED = 2,
+        NO_DAEMON = 3
+    };
+}
+
+constexpr auto GNOME_KEYRING_RESULT_OK = utils::ControlRes::OK;
+
+inline auto do_unlock(std::string keyring, std::string password) {
+    auto sockfd = utils::connect_unix_socket(utils::get_control_socket());
+    rlib_defer([&] { close(sockfd); });
+
+    rlib::sockIO::quick_send(sockfd, std::string(1, '\0'));
+
+    uint32_t oplen = 8 + 4 + password.size();
+    uint32_t pktBuf = htonl(oplen);
+    rlib::sockIO::sendn_ex(sockfd, &pktBuf, sizeof(pktBuf), 0);
+
+    pktBuf = htonl(utils::ControlOp::UNLOCK);
+    rlib::sockIO::sendn_ex(sockfd, &pktBuf, sizeof(pktBuf), 0);
+
+    pktBuf = htonl(password.size());
+    rlib::sockIO::sendn_ex(sockfd, &pktBuf, sizeof(pktBuf), 0);
+    rlib::sockIO::quick_send(sockfd, password);
+
+    rlib::sockIO::recvn_ex(sockfd, &pktBuf, sizeof(pktBuf));
+    if (ntohl(pktBuf) != 8)
+        throw std::runtime_error("invalid api response length: expecting len = 8");
+
+    rlib::sockIO::recvn_ex(sockfd, &pktBuf, sizeof(pktBuf));
+    return ntohl(pktBuf);
+}
+
+inline std::string keyringResultToString(int res) {
+    switch (res) {
+#define RLIB_IMPL_GEN_RESULT(value) RLIB_IMPL_GEN_RESULT_1(value, RLIB_MACRO_TO_CSTR(value))
+#define RLIB_IMPL_GEN_RESULT_1(value, cstr) case (utils::ControlRes::value): return (cstr)
+
+        RLIB_IMPL_GEN_RESULT(OK);
+        RLIB_IMPL_GEN_RESULT(DENIED);
+        RLIB_IMPL_GEN_RESULT(FAILED);
+        RLIB_IMPL_GEN_RESULT(NO_DAEMON);
+    default:
+        return std::string("Unknown Result Code: ") + std::to_string(res);
+    }
+}
\ No newline at end of file
diff --git a/src/unlock_keyrings.cc b/src/unlock_keyrings.cc
index 46eb59e96e52b7e0d943548722ff9cfeea95997c..91b1f29d5464b1c6163cda5fc5eaa7636c5296b7 100644
--- a/src/unlock_keyrings.cc
+++ b/src/unlock_keyrings.cc
@@ -1,6 +1,11 @@
 #include <rlib/log.hpp>
 #include <rlib/opt.hpp>
-#include "keyring_op.hpp"
+#ifdef KEYRING_IMPL_lib
+#include "impl-libgnome-keyring.hpp"
+#endif
+#ifdef KEYRING_IMPL_standalone
+#include "impl-standalone.hpp"
+#endif
 
 rlib::logger rlog(std::cerr);
 
@@ -39,6 +44,11 @@ int main(int argc, char **argv) {
             return 3;
         }
 
+#ifdef KEYRING_IMPL_standalone
+        rlog.warning("This implementation 'standalone' always unlocks your default keyring. Keyring name `{}` will be ignored. Build with KEYRING_IMPL=lib if necessary.", keyring_and_pswd.at(0));
+        keyring_and_pswd.at(0) = "_ignored_";
+#endif
+
         auto res = do_unlock(keyring_and_pswd.at(0), keyring_and_pswd.at(1));
         auto msg = keyringResultToString(res);
         if(res == GNOME_KEYRING_RESULT_OK)