diff --git a/gnu/local.mk b/gnu/local.mk
index b8ae060326..9efe2d18e9 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -44,6 +44,7 @@
 # Copyright © 2021 Arun Isaac <arunisaac@systemreboot.net>
 # Copyright © 2021 Sharlatan Hellseher <sharlatanus@gmail.com>
 # Copyright © 2021 Dmitry Polyakov <polyakov@liltechdude.xyz>
+# Copyright © 2021 Alexandr Vityazev <avityazev@posteo.org>
 #
 # This file is part of GNU Guix.
 #
@@ -1902,6 +1903,7 @@ dist_patch_DATA =						\
   %D%/packages/patches/xsane-fix-snprintf-buffer-length.patch	\
   %D%/packages/patches/xsane-support-ipv6.patch			\
   %D%/packages/patches/xsane-tighten-default-umask.patch	\
+  %D%/packages/patches/ydotool-cmakelists-remove-cpm.patch	\
   %D%/packages/patches/yggdrasil-extra-config.patch	\
   %D%/packages/patches/ytfzf-programs.patch        \
   %D%/packages/patches/ytfzf-updates.patch        \
diff --git a/gnu/packages/linux.scm b/gnu/packages/linux.scm
index 41b6dfd022..e260c1ee4c 100644
--- a/gnu/packages/linux.scm
+++ b/gnu/packages/linux.scm
@@ -52,6 +52,7 @@
 ;;; Copyright © 2020 pukkamustard <pukkamustard@posteo.net>
 ;;; Copyright © 2021 B. Wilson <elaexuotee@wilsonb.com>
 ;;; Copyright © 2021 Ivan Gankevich <i.gankevich@spbu.ru>
+;;; Copyright © 2021 Alexandr Vityazev <avityazev@posteo.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -145,6 +146,7 @@
   #:use-module (gnu packages rsync)
   #:use-module (gnu packages selinux)
   #:use-module (gnu packages swig)
+  #:use-module (gnu packages cpp)
   #:use-module (guix build-system cmake)
   #:use-module (guix build-system gnu)
   #:use-module (guix build-system go)
@@ -8524,6 +8526,40 @@ These trace events are logged in @file{/sys/kernel/debug/tracing} and reported
 through standard log mechanisms like syslog.")
     (license license:gpl2)))
 
+(define-public ydotool
+  (package
+    (name "ydotool")
+    (version "0.2.0")
+    (source
+     (origin
+       (method git-fetch)
+       (uri (git-reference
+             (url "https://github.com/ReimuNotMoe/ydotool")
+             (commit (string-append "v" version))))
+       (file-name (git-file-name name version))
+       (sha256
+        (base32
+         "17mgg9cqw4wjkmp9k6c8kgm7v2bvri5y49giqkbs6l2hv6ap5m9a"))
+       (patches (search-patches "ydotool-cmakelists-remove-cpm.patch"))))
+    (build-system cmake-build-system)
+    (arguments
+     `(#:tests? #f                    ;No tests
+       #:configure-flags
+       (let* ((out (assoc-ref %outputs "out")))
+         (list (string-append "-DCMAKE_INSTALL_MANDIR=" out "/share/man")
+               (string-append "-DCMAKE_INSTALL_SYSCONFDIR=" out "/etc")))))
+    (inputs
+     `(("libuinputplus" ,libuinputplus)
+       ("libevdevplus" ,libevdevplus)
+       ("cxxopts" ,cxxopts-next)
+       ("iodash" ,iodash)
+       ("scdoc" ,scdoc)))
+    (home-page "https://github.com/ReimuNotMoe/ydotool")
+    (synopsis "Generic Linux command-line automation tool (no X!)")
+    (description "@code{ydotool} is a Linux command-line tool that simulates
+keyboard input, mouse actions, etc. programmatically or manually.")
+    (license license:agpl3+)))
+
 (define-public libgpiod
   (package
     (name "libgpiod")
diff --git a/gnu/packages/patches/ydotool-cmakelists-remove-cpm.patch b/gnu/packages/patches/ydotool-cmakelists-remove-cpm.patch
new file mode 100644
index 0000000000..42ee38fd94
--- /dev/null
+++ b/gnu/packages/patches/ydotool-cmakelists-remove-cpm.patch
@@ -0,0 +1,118 @@
+From f68869deba8b71ff77cc0a2acd22eb449a61f7e9 Mon Sep 17 00:00:00 2001
+From: Alexandr Vityazev <avityazev@posteo.org>
+Date: Sat, 25 Sep 2021 23:15:15 +0300
+Subject: [PATCH] CMakeLists: remove CPM.
+
+- CMakeLists: remove CPM, remove linking cxxopts - header-only library,
+- add targets to install binaries;
+- ADD: Daemon/80-uinput.rules, Daemon/CMakeLists, manpage/CMakeLists.
+
+---
+ CMakeLists.txt         | 48 ++++++------------------------------------
+ Daemon/80-uinput.rules |  1 +
+ Daemon/CMakeLists.txt  |  1 +
+ manpage/CMakeLists.txt |  9 ++++++++
+ 4 files changed, 17 insertions(+), 42 deletions(-)
+ create mode 100644 Daemon/80-uinput.rules
+ create mode 100644 Daemon/CMakeLists.txt
+ create mode 100644 manpage/CMakeLists.txt
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 3dd15bf..8a882c5 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -3,41 +3,6 @@ project(ydotool)
+
+ set(CMAKE_CXX_STANDARD 17)
+
+-set(CPM_DOWNLOAD_VERSION 0.27.5)
+-set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
+-
+-if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION}))
+-    message(STATUS "Downloading CPM.cmake")
+-    file(DOWNLOAD https://github.com/TheLartians/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake ${CPM_DOWNLOAD_LOCATION})
+-endif()
+-
+-include(${CPM_DOWNLOAD_LOCATION})
+-
+-CPMAddPackage(
+-        NAME IODash
+-        GITHUB_REPOSITORY YukiWorkshop/IODash
+-        VERSION 0.1.0
+-)
+-
+-CPMAddPackage(
+-        NAME libevdevPlus
+-        GITHUB_REPOSITORY YukiWorkshop/libevdevPlus
+-        VERSION 0.2.1
+-)
+-
+-CPMAddPackage(
+-        NAME libuInputPlus
+-        GITHUB_REPOSITORY YukiWorkshop/libuInputPlus
+-        VERSION 0.2.1
+-)
+-
+-CPMAddPackage(
+-        NAME cxxopts
+-        GITHUB_REPOSITORY jarro2783/cxxopts
+-        VERSION 3.0.0
+-        GIT_TAG 2d8e17c4f88efce80e274cb03eeb902e055a91d3
+-)
+-
+ set(SOURCE_FILES_LIBRARY
+         CommonIncludes.hpp
+         Library/Tool.hpp Library/Tool.cpp
+@@ -59,15 +24,14 @@ set(SOURCE_FILES_CLIENT
+         CommonIncludes.hpp
+         Client/ydotool.cpp Client/ydotool.hpp)
+
+-include_directories(${libevdevPlus_SOURCE_DIR})
+-include_directories(${libuInputPlus_SOURCE_DIR})
+-include_directories(${IODash_SOURCE_DIR})
+-include_directories(${IODash_SOURCE_DIR}/cpp_modules/portable-endian) # FIXME
+-include_directories(${cxxopts_SOURCE_DIR}/include)
+-
+ add_executable(ydotoold ${SOURCE_FILES_DAEMON})
+-target_link_libraries(ydotoold PUBLIC cxxopts uInputPlus evdevPlus)
++target_link_libraries(ydotoold PUBLIC uInputPlus evdevPlus)
++install(TARGETS ydotoold DESTINATION ${CMAKE_INSTALL_BINDIR})
+
+ add_library(ydotool_library STATIC ${SOURCE_FILES_LIBRARY})
+ add_executable(ydotool ${SOURCE_FILES_CLIENT})
+ target_link_libraries(ydotool ydotool_library dl pthread uInputPlus evdevPlus)
++install(TARGETS ydotool DESTINATION ${CMAKE_INSTALL_BINDIR})
++
++add_subdirectory(manpage)
++add_subdirectory(Daemon)
+diff --git a/Daemon/80-uinput.rules b/Daemon/80-uinput.rules
+new file mode 100644
+index 0000000..fad61d4
+--- /dev/null
++++ b/Daemon/80-uinput.rules
+@@ -0,0 +1 @@
++KERNEL=="uinput", GROUP="input", MODE="0660", OPTIONS+="static_node=uinput"
+diff --git a/Daemon/CMakeLists.txt b/Daemon/CMakeLists.txt
+new file mode 100644
+index 0000000..0f478f8
+--- /dev/null
++++ b/Daemon/CMakeLists.txt
+@@ -0,0 +1 @@
++install(FILES 80-uinput.rules DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/udev/rules.d/)
+diff --git a/manpage/CMakeLists.txt b/manpage/CMakeLists.txt
+new file mode 100644
+index 0000000..c749dfc
+--- /dev/null
++++ b/manpage/CMakeLists.txt
+@@ -0,0 +1,9 @@
++function(man_page section page)
++  set(src "${CMAKE_CURRENT_SOURCE_DIR}/${page}.${section}.scd")
++  set(bin "${CMAKE_CURRENT_BINARY_DIR}/${page}.${section}")
++  add_custom_target(${page}.${section} ALL COMMAND scdoc < ${src} > ${bin})
++  install(FILES ${bin} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${section}/)
++endfunction(man_page)
++
++man_page(1 ydotool)
++man_page(8 ydotoold)
+--
+2.33.0
