[
  {
    "path": ".circleci/config.yml",
    "content": "version: 2\n\njobs:\n  build:\n    docker:\n      # using custom image, see .circleci/images/primary/Dockerfile\n      # - image: govgo/robotgoci:1.10.3\n      - image: golang:1.25.0\n    working_directory: /gopath/src/github.com/go-vgo/robotgo\n    steps:\n      - checkout\n      # specify any bash command here prefixed with `run: `\n      - run: apt update\n      - run:\n          apt -y install gcc libc6-dev\n          libx11-dev xorg-dev libxtst-dev\n          xsel xclip\n          # libpng++-dev\n          # xcb libxcb-xkb-dev x11-xkb-utils libx11-xcb-dev libxkbcommon-x11-dev libxkbcommon-dev\n      - run: apt -y install xvfb\n      #\n      #  override:\n      - run: go get -v -t -d ./...\n      - run: xvfb-run go test -v ./...\n      #\n      # codecov.io\n      # - run: xvfb-run go test -v -covermode=count -coverprofile=coverage.out\n      # - run: bash <(curl -s https://codecov.io/bash)\n"
  },
  {
    "path": ".circleci/images/primary/Dockerfile",
    "content": "# FROM golang:1.10.1\nFROM golang:1.24.2-stretch AS build\n# FROM govgo/go:1.11.1\n\nRUN apt update && apt install -y --no-install-recommends \\\n    # customize dependencies\n    libx11-dev xorg-dev \\\n    libxtst-dev \\\n    # Bitmap\n    libpng++-dev \\\n    # Event:\n    xcb libxcb-xkb-dev \\\n    x11-xkb-utils libx11-xcb-dev \\\n    libxkbcommon-x11-dev libxkbcommon-dev \\\n    # Clipboard:\n    xsel xclip && \\\n    #\n    apt remove --purge --auto-remove && \\\n    apt clean               && \\\n    rm -rf /var/lib/apt/lists/*\n\nRUN go get -u github.com/go-vgo/robotgo"
  },
  {
    "path": ".github/CODEOWNERS",
    "content": "# general\n* @vcaesar"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "# Contributing to Robotgo\n\n"
  },
  {
    "path": ".github/issue_template.md",
    "content": "1. Please **speak English (English only)**, this is the language everybody of us can speak and write.\n2. Please take a moment to **search** that an issue **doesn't already exist**.\n3. Please make sure `Golang, GCC` is installed correctly before installing RobotGo.\n<!-- 4. Please ask questions or config/deploy problems on our Gitter channel: https://gitter.im/go-vgo/robotgo -->\n4. Please give all relevant information below for bug reports, incomplete details will be handled as an invalid report.\n\n**You MUST delete the content above including this line before posting, otherwise your issue will be invalid.**\n\n- Robotgo version (or commit ref):\n- Go version:\n- Gcc version:\n- Operating system and bit:\n- Resolution:\n- Can you reproduce the bug at [Examples](https://github.com/go-vgo/robotgo/blob/master/examples/):\n  - [ ] Yes (provide example code)\n  - [ ] No\n  - [ ] Not relevant\n- Provide example code:\n\n```Go\n\n```\n\n- Log gist:\n\n## Description\n\n...\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "The pull request will be closed without any reasons if it does not satisfy any of following requirements:\n\n1. Make sure you are targeting the `master` branch, pull requests on release branches are only allowed for bug fixes.\n2. Add new features, please provide the reasons and test code.\n3. Please read contributing guidelines: [CONTRIBUTING](https://github.com/go-vgo/robotgo/blob/master/CONTRIBUTING.md) and sign the CLA.\n4. Describe what your pull request does and which issue you're targeting (if any and **Please use English**)\n5. ... if it is not related to any particular issues, explain why we should not reject your pull request.\n6. The Commits must **use English**, must be test and No useless submissions.\n\n**You MUST delete the content above including this line before posting, otherwise your pull request will be invalid.**\n\n**Please provide Issues links to:**\n\n- Issues: #1\n\n**Provide test code:**\n\n```Go\n\n```\n\n## Description\n\n...\n"
  },
  {
    "path": ".github/workflows/go.yml",
    "content": "name: Go\non: [push]\njobs:\n  test:\n    # name: build\n    strategy:\n      matrix:\n        # go: [1.12.x, 1.13.x]\n        os: [macOS-latest, windows-latest] # ubuntu-latest\n    runs-on: ${{ matrix.os }}\n\n    steps:\n      - name: Set up Go 1.26.0\n        uses: actions/setup-go@v6\n        with:\n          go-version: 1.26.x\n        id: go\n\n      - name: Check out code into the Go module directory\n        uses: actions/checkout@v6\n\n      - name: Get dependencies\n        run: |\n          go get -v -t -d ./...\n\n      - name: Build\n        run: go build -v .\n      - name: Test\n        run: go test -v robot_info_test.go\n        # run: go test -v .\n"
  },
  {
    "path": ".gitignore",
    "content": "# Object files\n.DS_Store\n.vscode\n.idea\n\nrobot_test.png\n# Examples\nexamples/screen/screen\nexamples/screen/saveCapture.png\n#\nexamples/bitmap/test.png\nexamples/bitmap/test2.png\nexamples/bitmap/test.tif\nexamples/bitmap/test31.tif\nexamples/bitmap/tocbitmap.png\nexamples/bitmap/teststr.png\ntest/test.png\n\n# Debug files\n*.dSYM/\n*.su\ndebug\n\n# Architecture specific extensions/prefixes\n*.[568vq]\n[568vq].out\n\n*.cgo1.go\n*.cgo2.c\n_cgo_defun.c\n_cgo_gotypes.go\n_cgo_export.*\n\n_testmain.go\n\n*.o\n*.ko\n*.obj\n*.elf\n\n# Precompiled Headers\n*.gch\n*.pch\n\n#\ncdeps/hook\nevent/hook\nvendor\n\n# Libraries\n*.lib\n# !cdeps/win32/libpng.lib\n# !cdeps/win32/zlib.lib\n# !cdeps/win64/libpng.lib\n# !cdeps/win64/zlib.lib\n# ##\n*.a\n!cdeps/mac/libpng.a\n!cdeps/mac/amd/libpng.a\n!cdeps/mac/m1/libpng.a\n# \n!cdeps/win32/libpng.a\n!cdeps/win64/libpng.a\n!cdeps/win/amd/win32/libpng.a\n!cdeps/win/amd/win64/libpng.a\n!cdeps/win/arm/libpng.a\n#\n*.la\n*.lo\n\n# Shared objects (inc. Windows DLLs)\n*.dll\n*.so\n*.so.*\n*.dylib\n\n# Executables\n*.exe\n*.out\n*.app\n*.i*86\n*.x86_64\n*.hex\n\n# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736\n .glide/\n\n#\nexamples/bitmap/test_IMG.png\nexamples/bitmap/imgToBitmap/test_01.png\nexamples/bitmap/imgToBitmap/test_002.jpeg\nexamples/bitmap/imgToBitmap/test_003.jpeg\nexamples/bitmap/imgToBitmap/test_1.png\nexamples/bitmap/imgToBitmap/test_2.jpeg\nexamples/bitmap/imgToBitmap/test.png\nexamples/bitmap/imgToBitmap/test_7.jpeg\nrobot_img.png\nexamples/bitmap/bitmapTobytes/out.jpg\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: go\n\nos:\n  - linux\n  - osx\n\ngo:\n  # - 1.7.x\n  # - 1.8.x\n  # - 1.9.x\n  # - 1.10.x\n  # - 1.11.x\n  # - 1.12.x\n  # - 1.13.x\n  # - 1.14.x\n  # - 1.15.x\n  # - 1.16.x\n  # - 1.17.x\n  # - 1.18.x\n  - 1.19.x\n  # - tip\n\naddons:\n  apt:\n    packages:\n      - libx11-dev xorg-dev\n      - libxtst-dev libpng++-dev\n      - xcb libxcb-xkb-dev x11-xkb-utils libx11-xcb-dev libxkbcommon-x11-dev\n      #  - libusb-dev\n      - libxkbcommon-dev\n      - xsel\n      - xclip\n      #\n      - xvfb\n# script:\n#  - sudo apt update\n#  - sudo apt install libx11-dev\n#  - sudo apt install xorg-dev\n#  - sudo apt install libxtst-dev libpng++-dev\n#  # Event:\n#  - sudo apt install xcb libxcb-xkb-dev x11-xkb-utils libx11-xcb-dev libxkbcommon-x11-dev\n#  - sudo apt install libxkbcommon-dev\n#  # Clipboard:\n#  - sudo apt install xsel\n#  - sudo apt install xclip\n#  - go test -v .\n\nbefore_install:\n  - export PATH=$PATH:$HOME/gopath/bin\n  - go get -v -t -d ./...\n\nscript:\n  - if [ \"${TRAVIS_OS_NAME}\" = \"linux\" ]; then xvfb-run go test -v ./...; fi\n  - if [ \"${TRAVIS_OS_NAME}\" = \"osx\" ]; then go test -v ./...; fi\n"
  },
  {
    "path": "CLA.md",
    "content": "### AtomAI Individual Contributor License Agreement\n\nVersion: 2025-11-19 (https://cla-assistant.io/)\n\nThank you for your interest in contributing to open source software projects (“Projects”) made available by AtomAI SE or its affiliates (“AtomAI”). This Individual Contributor License Agreement (“Agreement”) sets out the terms governing any source code, object code, bug fixes, configuration changes, tools, specifications, documentation, data, materials, feedback, information or other works of authorship that you submit or have submitted, in any form and in any manner, to AtomAI in respect of any of the Projects (collectively “Contributions”). If you have any questions respecting this Agreement, please contact info@atomai.cc.\n\nYou agree that the following terms apply to all of your past, present and future Contributions. Except for the licenses granted in this Agreement, you retain all of your right, title and interest in and to your Contributions.\n\n**Copyright License.** You hereby grant, and agree to grant, to AtomAI a non-exclusive, perpetual, irrevocable, worldwide, fully-paid, royalty-free, transferable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, and distribute your Contributions and such derivative works, with the right to sublicense the foregoing rights through multiple tiers of sublicensees.\n\n**Patent License.** You hereby grant, and agree to grant, to AtomAI a non-exclusive, perpetual, irrevocable, worldwide, fully-paid, royalty-free, transferable patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer your Contributions, where such license applies only to those patent claims licensable by you that are necessarily infringed by your Contributions alone or by combination of your Contributions with the Project to which such Contributions were submitted, with the right to sublicense the foregoing rights through multiple tiers of sublicensees.\n\n**Moral Rights.** To the fullest extent permitted under applicable law, you hereby waive, and agree not to assert, all of your “moral rights” in or relating to your Contributions for the benefit of AtomAI, its assigns, and their respective direct and indirect sublicensees.\n\n**Third Party Content/Rights.** If your Contribution includes or is based on any source code, object code, bug fixes, configuration changes, tools, specifications, documentation, data, materials, feedback, information or other works of authorship that were not authored by you (“Third Party Content”) or if you are aware of any third party intellectual property or proprietary rights associated with your Contribution (“Third Party Rights”), then you agree to include with the submission of your Contribution full details respecting such Third Party Content and Third Party Rights, including, without limitation, identification of which aspects of your Contribution contain Third Party Content or are associated with Third Party Rights, the owner/author of the Third Party Content and Third Party Rights, where you obtained the Third Party Content, and any applicable third party license terms or restrictions respecting the Third Party Content and Third Party Rights. For greater certainty, the foregoing obligations respecting the identification of Third Party Content and Third Party Rights do not apply to any portion of a Project that is incorporated into your Contribution to that same Project.\n\n**Representations.** You represent that, other than the Third Party Content and Third Party Rights identified by you in accordance with this Agreement, you are the sole author of your Contributions and are legally entitled to grant the foregoing licenses and waivers in respect of your Contributions. If your Contributions were created in the course of your employment with your past or present employer(s), you represent that such employer(s) has authorized you to make your Contributions on behalf of such employer(s) or such employer (s) has waived all of their right, title or interest in or to your Contributions.\n\n**Disclaimer.** To the fullest extent permitted under applicable law, your Contributions are provided on an \"asis\" basis, without any warranties or conditions, express or implied, including, without limitation, any implied warranties or conditions of non-infringement, merchantability or fitness for a particular purpose. You are not required to provide support for your Contributions, except to the extent you desire to provide support.\n\n**No Obligation.** You acknowledge that AtomAI is under no obligation to use or incorporate your Contributions into any of the Projects. The decision to use or incorporate your Contributions into any of the Projects will be made at the sole discretion of AtomAI or its authorized delegates.\n\n**Disputes.** This Agreement shall be governed by and construed in accordance with the laws of the State of Wyoming, United States of America, without giving effect to its principles or rules regarding conflicts of laws, other than such principles directing application of Wyoming law. The parties hereby submit to venue in, and jurisdiction of the courts located in Wyoming, Wyoming for purposes relating to this Agreement.\nIn the event that any of the provisions of this Agreement shall be held by a court or other tribunal of competent jurisdiction to be unenforceable, the remaining portions hereof shall remain in full force and effect.\n\n**Assignment.** You agree that AtomAI may assign this Agreement, and all of its rights, obligations and licenses hereunder.\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contribution Guidelines\n\n## Introduction\n\nThis document explains how to contribute changes to the Robotgo project. It assumes you have followed the README.md and [API Document](https://github.com/go-vgo/robotgo/blob/master/docs/doc.md).\nSensitive security-related issues should be reported to [info@atomai.cc](info@atomaicc).\n\n<!-- [security@Robotgo.io](mailto:security@Robotgo.io.) -->\n\n## Bug reports\n\nPlease search the issues on the issue tracker with a variety of keywords to ensure your bug is not already reported.\n\nIf unique, [open an issue](https://github.com/go-vgo/robotgo/issues/new) and answer the questions so we can understand and reproduce the problematic behavior.\n\nThe burden is on you to convince us that it is actually a bug in Robotgo. This is easiest to do when you write clear, concise instructions so we can reproduce the behavior (even if it seems obvious). The more detailed and specific you are, the faster we will be able to help you. Check out [How to Report Bugs Effectively](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html).\n\nPlease be kind, remember that Robotgo comes at no cost to you, and you're getting free help.\n\n## Discuss your design\n\nThe project welcomes submissions but please let everyone know what you're working on if you want to change or add something to the Robotgo repositories.\n\nBefore starting to write something new for the Robotgo project, please [file an issue](https://github.com/go-vgo/robotgo/issues/new). Significant changes must go through the [change proposal process](https://github.com/go-vgo/proposals) before they can be accepted.\n\nThis process gives everyone a chance to validate the design, helps prevent duplication of effort, and ensures that the idea fits inside the goals for the project and tools. It also checks that the design is sound before code is written; the code review tool is not the place for high-level discussions.\n\n## Testing redux\n\nBefore sending code out for review, run all the tests for the whole tree to make sure the changes don't break other usage and keep the compatibility on upgrade. You must be test on Mac, Windows, Linux and other. You should install the CLI for Circle CI, as we are using the server for continuous testing.\n\n## Code review\n\nIn addition to the owner, Changes to Robotgo must be reviewed before they are accepted, no matter who makes the change even if it is a maintainer. We use GitHub's pull request workflow to do that and we also use [LGTM](http://lgtm.co) to ensure every PR is reviewed by vz or least 2 maintainers.\n\n## Sign your work\n\nThe sign-off is a simple line at the end of the explanation for the patch. Your signature certifies that you wrote the patch or otherwise have the right to pass it on as an open-source patch.\n\n## Maintainers\n\nTo make sure every PR is checked, we got team maintainers. A maintainer should be a contributor of Robotgo and contributed at least 4 accepted PRs.\n\n## Owners\n\nSince Robotgo is a pure community organization without any company support, Copyright 2016 The go-vgo Project Developers.\n\n## Versions\n\nRobotgo has the `master` branch as a tip branch and has version branches such as `v0.30.0`. `v0.40.0` is a release branch and we will tag `v0.40.0` for binary download. If `v0.40.0` has bugs, we will accept pull requests on the `v0.40.0` branch and publish a `v0.40.1` tag, after bringing the bug fix also to the master branch.\n\nSince the `master` branch is a tip version, if you wish to use Robotgo in production, please download the latest release tag version. All the branches will be protected via GitHub, all the PRs to every branch must be reviewed by two maintainers and must pass the automatic tests.\n\n## Copyright\n\nCode that you contribute should use the standard copyright header:\n\n```\n// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n```\n\nFiles in the repository contain copyright from the year they are added to the year they are last changed. If the copyright author is changed, just paste the header below the old one.\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "# Robotgo\n\n<!-- <img align=\"right\" src=\"https://raw.githubusercontent.com/go-vgo/robotgo/master/logo.jpg\"> -->\n<!-- [![codecov](https://codecov.io/gh/go-vgo/robotgo/branch/master/graph/badge.svg)](https://codecov.io/gh/go-vgo/robotgo) -->\n\n[![Build Status](https://github.com/go-vgo/robotgo/workflows/Go/badge.svg)](https://github.com/go-vgo/robotgo/commits/master)\n[![CircleCI Status](https://circleci.com/gh/go-vgo/robotgo.svg?style=shield)](https://circleci.com/gh/go-vgo/robotgo)\n![Appveyor](https://ci.appveyor.com/api/projects/status/github/go-vgo/robotgo?branch=master&svg=true)\n[![Go Report Card](https://goreportcard.com/badge/github.com/go-vgo/robotgo)](https://goreportcard.com/report/github.com/go-vgo/robotgo)\n[![GoDoc](https://pkg.go.dev/badge/github.com/go-vgo/robotgo?status.svg)](https://pkg.go.dev/github.com/go-vgo/robotgo?tab=doc)\n[![GitHub release](https://img.shields.io/github/release/go-vgo/robotgo.svg)](https://github.com/go-vgo/robotgo/releases/latest)\n\n> Golang Desktop Automation, auto test and AI Computer Use. <br>\n> Control the mouse, keyboard, read the screen, process, Window Handle, image and bitmap and global event listener.\n\nRobotGo supports Mac, Windows, and Linux (X11); and robotgo supports arm64 and x86-amd64.\n\n[RobotGo-Pro](https://github.com/vcaesar/robotgo-pro) get the JavaScript, Python, Lua and others version, tech supports, new features and newest robotgo version (such as Wayland support, \"no open-source version forever\").\n\n## Contents\n\n- [Docs](#docs)\n- [Binding](#binding)\n- [Requirements](#requirements)\n- [Installation](#installation)\n- [Update](#update)\n- [Examples](#examples)\n- [Type Conversion and keys](https://github.com/go-vgo/robotgo/blob/master/docs/keys.md)\n- [Cross-Compiling](https://github.com/go-vgo/robotgo/blob/master/docs/install.md#crosscompiling)\n- [Authors](#authors)\n- [Plans](#plans)\n- [License](#license)\n\n## Docs\n\n- [GoDoc](https://godoc.org/github.com/go-vgo/robotgo) <br>\n- [API Docs](https://github.com/go-vgo/robotgo/blob/master/docs/doc.md) (Deprecated, no updated)\n\n## Binding:\n\n[ADB](https://github.com/vcaesar/adb), packaging android adb API.\n\n## Requirements:\n\nNow, Please make sure `Golang, GCC` is installed correctly before installing RobotGo.\n\n### ALL:\n\n```\nGolang\n\nGCC\n```\n\n#### For MacOS:\n\n```\nbrew install go\n```\n\nXcode Command Line Tools; <br>\nAnd Privacy setting, add Screen Recording and Accessibility under: <br>\n`System Settings > Privacy & Security > Accessibility, Screen & System Audio Recording`.\n\n```\nxcode-select --install\n```\n\n#### For Windows:\n\n```\nwinget install Golang.go\n```\n\n[llvm-mingw](https://github.com/mstorsjo/llvm-mingw)\n\n```\nwinget install MartinStorsjo.LLVM-MinGW.UCRT\n```\n\nor [Mingw-w64](https://sourceforge.net/projects/mingw-w64/files)\n\n```\nwinget install BrechtSanders.WinLibs.POSIX.UCRT\n```\n\nOr Download the [Mingw-w64](https://sourceforge.net/projects/mingw-w64/files) and the others gcc, then set system environment variables like `C:\\mingw64\\bin` to the env `Path`.\n[Set environment variables to run GCC from command line](https://www.youtube.com/results?search_query=Set+environment+variables+to+run+GCC+from+command+line).\n\n`Or The others GCC` (Except the Mingw-w64, you should compile the \"libpng\" with yourself when use the [bitmap](https://github.com/vcaesar/bitmap).)\n\n#### For everything else:\n\n```\nGCC\n\nX11 with the XTest extension (the Xtst library)\n\n\"Clipboard\": xsel xclip\n\n\"Bitmap\": libpng (Just used by the \"bitmap\".)\n\n\"Event-Gohook\": xcb, xkb, libxkbcommon (Just used by the \"hook\".)\n```\n\n##### Ubuntu:\n\n```yml\n# sudo apt install golang\nsudo snap install go  --classic\n\n# gcc\nsudo apt install gcc libc6-dev\n\n# x11\nsudo apt install libx11-dev xorg-dev libxtst-dev\n\n# Clipboard\nsudo apt install xsel xclip\n\n# Bitmap\nsudo apt install libpng++-dev\n\n# GoHook\nsudo apt install xcb libxcb-xkb-dev x11-xkb-utils libx11-xcb-dev libxkbcommon-x11-dev libxkbcommon-dev\n```\n\n##### Fedora:\n\n```yml\n# x11\nsudo dnf install libXtst-devel\n\n# Clipboard\nsudo dnf install xsel xclip\n\n# Bitmap\nsudo dnf install libpng-devel\n\n# GoHook\nsudo dnf install libxkbcommon-devel libxkbcommon-x11-devel xorg-x11-xkb-utils-devel\n```\n\n## Installation:\n\nWith Go module support (Go 1.11+), just import:\n\n```go\nimport \"github.com/go-vgo/robotgo\"\n```\n\nOtherwise, to install the robotgo package, run the command:\n\n```\ngo get github.com/go-vgo/robotgo\n```\n\npng.h: No such file or directory? Please see [issues/47](https://github.com/go-vgo/robotgo/issues/47).\n\n## Update:\n\n```\ngo get -u github.com/go-vgo/robotgo\n```\n\nNote go1.10.x C file compilation cache problem, [golang #24355](https://github.com/golang/go/issues/24355).\n`go mod vendor` problem, [golang #26366](https://github.com/golang/go/issues/26366).\n\n## [Examples:](https://github.com/go-vgo/robotgo/blob/master/examples)\n\n#### [Mouse](https://github.com/go-vgo/robotgo/blob/master/examples/mouse/main.go)\n\n```Go\npackage main\n\nimport (\n  \"fmt\"\n  \"github.com/go-vgo/robotgo\"\n)\n\nfunc main() {\n  robotgo.MouseSleep = 300\n\n  robotgo.Move(100, 100)\n  fmt.Println(robotgo.Location())\n  robotgo.Move(100, -200) // multi screen supported\n  robotgo.MoveSmooth(120, -150)\n  fmt.Println(robotgo.Location())\n\n  robotgo.ScrollDir(10, \"up\")\n  robotgo.ScrollDir(20, \"right\")\n\n  robotgo.Scroll(0, -10)\n  robotgo.Scroll(100, 0)\n\n  robotgo.MilliSleep(100)\n  robotgo.ScrollSmooth(-10, 6)\n  // robotgo.ScrollRelative(10, -100)\n\n  robotgo.Move(10, 20)\n  robotgo.MoveRelative(0, -10)\n  robotgo.DragSmooth(10, 10)\n\n  robotgo.Click(\"wheelRight\")\n  robotgo.Click(\"left\", true)\n  robotgo.MoveSmooth(100, 200, 1.0, 10.0)\n\n  robotgo.Toggle(\"left\")\n  robotgo.Toggle(\"left\", \"up\")\n}\n```\n\n#### [Keyboard](https://github.com/go-vgo/robotgo/blob/master/examples/key/main.go)\n\n```Go\npackage main\n\nimport (\n  \"fmt\"\n\n  \"github.com/go-vgo/robotgo\"\n)\n\nfunc main() {\n  robotgo.Type(\"Hello World\")\n  robotgo.Type(\"だんしゃり\", 0, 1)\n  // robotgo.Type(\"テストする\")\n\n  robotgo.Type(\"Hi, Seattle space needle, Golden gate bridge, One world trade center.\")\n  robotgo.Type(\"Hi galaxy, hi stars, hi MT.Rainier, hi sea. こんにちは世界.\")\n  robotgo.Sleep(1)\n\n  // ustr := uint32(robotgo.CharCodeAt(\"Test\", 0))\n  // robotgo.UnicodeType(ustr)\n\n  robotgo.KeySleep = 100\n  robotgo.KeyTap(\"enter\")\n  // robotgo.Type(\"en\")\n  robotgo.KeyTap(\"i\", \"alt\", \"cmd\")\n\n  arr := []string{\"alt\", \"cmd\"}\n  robotgo.KeyTap(\"i\", arr)\n\n  robotgo.MilliSleep(100)\n  robotgo.KeyToggle(\"a\")\n  robotgo.KeyToggle(\"a\", \"up\")\n\n  robotgo.WriteAll(\"Test\")\n  text, err := robotgo.ReadAll()\n  if err == nil {\n    fmt.Println(text)\n  }\n}\n```\n\n#### [Screen](https://github.com/go-vgo/robotgo/blob/master/examples/screen/main.go)\n\n```Go\npackage main\n\nimport (\n  \"fmt\"\n  \"strconv\"\n\n  \"github.com/go-vgo/robotgo\"\n  \"github.com/vcaesar/imgo\"\n)\n\nfunc main() {\n  x, y := robotgo.Location()\n  fmt.Println(\"pos: \", x, y)\n\n  color := robotgo.GetPixelColor(100, 200)\n  fmt.Println(\"color---- \", color)\n\n  sx, sy := robotgo.GetScreenSize()\n  fmt.Println(\"get screen size: \", sx, sy)\n\n  bit := robotgo.CaptureScreen(10, 10, 30, 30)\n  defer robotgo.FreeBitmap(bit)\n\n  img := robotgo.ToImage(bit)\n  imgo.Save(\"test.png\", img)\n\n  num := robotgo.DisplaysNum()\n  for i := 0; i < num; i++ {\n    robotgo.DisplayID = i\n    img1, _ := robotgo.CaptureImg()\n    path1 := \"save_\" + strconv.Itoa(i)\n    robotgo.Save(img1, path1+\".png\")\n    robotgo.SaveJpeg(img1, path1+\".jpeg\", 50)\n\n    img2, _ := robotgo.CaptureImg(10, 10, 20, 20)\n    robotgo.Save(img2, \"test_\"+strconv.Itoa(i)+\".png\")\n\n    x, y, w, h := robotgo.GetDisplayBounds(i)\n    img3, err := robotgo.CaptureImg(x, y, w, h)\n    fmt.Println(\"Capture error: \", err)\n    robotgo.Save(img3, path1+\"_1.png\")\n  }\n}\n```\n\n#### [Bitmap](https://github.com/vcaesar/bitmap/blob/main/examples/main.go)\n\n```Go\npackage main\n\nimport (\n  \"fmt\"\n\n  \"github.com/go-vgo/robotgo\"\n  \"github.com/vcaesar/bitmap\"\n)\n\nfunc main() {\n  bit := robotgo.CaptureScreen(10, 20, 30, 40)\n  // use `defer robotgo.FreeBitmap(bit)` to free the bitmap\n  defer robotgo.FreeBitmap(bit)\n\n  fmt.Println(\"bitmap...\", bit)\n  img := robotgo.ToImage(bit)\n  // robotgo.SavePng(img, \"test_1.png\")\n  robotgo.Save(img, \"test_1.png\")\n\n  bit2 := robotgo.ToCBitmap(robotgo.ImgToBitmap(img))\n  fx, fy := bitmap.Find(bit2)\n  fmt.Println(\"FindBitmap------ \", fx, fy)\n  robotgo.Move(fx, fy)\n\n  arr := bitmap.FindAll(bit2)\n  fmt.Println(\"Find all bitmap: \", arr)\n\n  fx, fy = bitmap.Find(bit)\n  fmt.Println(\"FindBitmap------ \", fx, fy)\n\n  bitmap.Save(bit, \"test.png\")\n}\n```\n\n#### [OpenCV](https://github.com/vcaesar/gcv)\n\n```Go\npackage main\n\nimport (\n  \"fmt\"\n  \"math/rand\"\n\n  \"github.com/go-vgo/robotgo\"\n  \"github.com/vcaesar/gcv\"\n  \"github.com/vcaesar/bitmap\"\n)\n\nfunc main() {\n  opencv()\n}\n\nfunc opencv() {\n  name := \"test.png\"\n  name1 := \"test_001.png\"\n  robotgo.SaveCapture(name1, 10, 10, 30, 30)\n  robotgo.SaveCapture(name)\n\n  fmt.Print(\"gcv find image: \")\n  fmt.Println(gcv.FindImgFile(name1, name))\n  fmt.Println(gcv.FindAllImgFile(name1, name))\n\n  bit := bitmap.Open(name1)\n  defer robotgo.FreeBitmap(bit)\n  fmt.Print(\"find bitmap: \")\n  fmt.Println(bitmap.Find(bit))\n\n  // bit0 := robotgo.CaptureScreen()\n  // img := robotgo.ToImage(bit0)\n  // bit1 := robotgo.CaptureScreen(10, 10, 30, 30)\n  // img1 := robotgo.ToImage(bit1)\n  // defer robotgo.FreeBitmapArr(bit0, bit1)\n  img, _ := robotgo.CaptureImg()\n  img1, _ := robotgo.CaptureImg(10, 10, 30, 30)\n\n  fmt.Print(\"gcv find image: \")\n  fmt.Println(gcv.FindImg(img1, img))\n  fmt.Println()\n\n  res := gcv.FindAllImg(img1, img)\n  fmt.Println(res[0].TopLeft.Y, res[0].Rects.TopLeft.X, res)\n  x, y := res[0].TopLeft.X, res[0].TopLeft.Y\n  robotgo.Move(x, y-rand.Intn(5))\n  robotgo.MilliSleep(100)\n  robotgo.Click()\n\n  res = gcv.FindAll(img1, img) // use find template and sift\n  fmt.Println(\"find all: \", res)\n  res1 := gcv.Find(img1, img)\n  fmt.Println(\"find: \", res1)\n\n  img2, _, _ := robotgo.DecodeImg(\"test_001.png\")\n  x, y = gcv.FindX(img2, img)\n  fmt.Println(x, y)\n}\n```\n\n#### [Event](https://github.com/robotn/gohook/blob/master/examples/main.go)\n\n```Go\npackage main\n\nimport (\n  \"fmt\"\n\n  // \"github.com/go-vgo/robotgo\"\n  hook \"github.com/robotn/gohook\"\n)\n\nfunc main() {\n  add()\n  low()\n  event()\n}\n\nfunc add() {\n  fmt.Println(\"--- Please press ctrl + shift + q to stop hook ---\")\n  hook.Register(hook.KeyDown, []string{\"q\", \"ctrl\", \"shift\"}, func(e hook.Event) {\n    fmt.Println(\"ctrl-shift-q\")\n    hook.End()\n  })\n\n  fmt.Println(\"--- Please press w---\")\n  hook.Register(hook.KeyDown, []string{\"w\"}, func(e hook.Event) {\n    fmt.Println(\"w\")\n  })\n\n  s := hook.Start()\n  <-hook.Process(s)\n}\n\nfunc low() {\n\tevChan := hook.Start()\n\tdefer hook.End()\n\n\tfor ev := range evChan {\n\t\tfmt.Println(\"hook: \", ev)\n\t}\n}\n\nfunc event() {\n  ok := hook.AddEvents(\"q\", \"ctrl\", \"shift\")\n  if ok {\n    fmt.Println(\"add events...\")\n  }\n\n  keve := hook.AddEvent(\"k\")\n  if keve {\n    fmt.Println(\"you press... \", \"k\")\n  }\n\n  mleft := hook.AddEvent(\"mleft\")\n  if mleft {\n    fmt.Println(\"you press... \", \"mouse left button\")\n  }\n}\n```\n\n#### [Window](https://github.com/go-vgo/robotgo/blob/master/examples/window/main.go)\n\n```Go\npackage main\n\nimport (\n  \"fmt\"\n\n  \"github.com/go-vgo/robotgo\"\n)\n\nfunc main() {\n  fpid, err := robotgo.FindIds(\"Google\")\n  if err == nil {\n    fmt.Println(\"pids... \", fpid)\n\n    if len(fpid) > 0 {\n      robotgo.Type(\"Hi galaxy!\", fpid[0])\n      robotgo.KeyTap(\"a\", fpid[0], \"cmd\")\n\n      robotgo.KeyToggle(\"a\", fpid[0])\n      robotgo.KeyToggle(\"a\", fpid[0], \"up\")\n\n      robotgo.ActivePid(fpid[0])\n\n      robotgo.Kill(fpid[0])\n    }\n  }\n\n  robotgo.ActiveName(\"chrome\")\n\n  isExist, err := robotgo.PidExists(100)\n  if err == nil && isExist {\n    fmt.Println(\"pid exists is\", isExist)\n\n    robotgo.Kill(100)\n  }\n\n  abool := robotgo.Alert(\"test\", \"robotgo\")\n  if abool {\n \t  fmt.Println(\"ok@@@ \", \"ok\")\n  }\n\n  title := robotgo.GetTitle()\n  fmt.Println(\"title@@@ \", title)\n}\n```\n\n## Authors\n\n- [The author is Evans](https://github.com/vcaesar)\n- [Maintainers](https://github.com/orgs/go-vgo/people)\n\n## Plans\n\n- Refactor some C code to Go (such as x11, windows)\n- Better multiscreen support\n- Wayland support\n- Update Window Handle\n- Try to support Android and IOS\n\n## Contributors\n\n- See [contributors page](https://github.com/go-vgo/robotgo/graphs/contributors) for full list of contributors.\n- See [Contribution Guidelines](https://github.com/go-vgo/robotgo/blob/master/CONTRIBUTING.md).\n\n## License\n\nRobotgo is primarily distributed under the terms of \"the Apache License (Version 2.0)\", with portions covered by various BSD-like licenses.\n\nSee [LICENSE-APACHE](http://www.apache.org/licenses/LICENSE-2.0), [LICENSE](https://github.com/go-vgo/robotgo/blob/master/LICENSE).\n"
  },
  {
    "path": "appveyor.yml",
    "content": "# version format\nversion: \"{build}\"\n\n# Operating system (build VM template)\n# os: Windows Server 2012 R2\nos: Visual Studio 2017\n\n# Platform.\n# platform:\n#   - x64\n#   - x86\n\nclone_folder: c:\\gopath\\src\\github.com\\go-vgo\\robotgo\n\n# Environment variables\nenvironment:\n  global:\n    GOPATH: C:\\gopath\n    CC: gcc.exe\n  matrix:\n    - GOARCH: amd64\n      # GOVERSION: 1.9.3\n      GETH_ARCH: amd64\n      MSYS2_ARCH: x86_64\n      MSYS2_BITS: 64\n      MSYSTEM: MINGW64\n      PATH: C:\\msys64\\mingw64\\bin\\;C:\\Program Files (x86)\\NSIS\\;%PATH%\n    - GOARCH: 386\n      # GOVERSION: 1.9.3\n      GETH_ARCH: 386\n      MSYS2_ARCH: i686\n      MSYS2_BITS: 32\n      MSYSTEM: MINGW32\n      PATH: C:\\msys64\\mingw32\\bin\\;C:\\Program Files (x86)\\NSIS\\;%PATH%\n  # - COMPILER: MINGW_W64\n  #   ARCHITECTURE: x64\n  GOVERSION: 1.25.0\n  # GOPATH: c:\\gopath\n\n# scripts that run after cloning repository\n# install:\n#   - set PATH=%GOPATH%\\bin;c:\\go\\bin;%PATH%\n#   - go version\n#   - go env\n#   - gcc --version\n# - python --version\n\ninstall:\n  - set PATH=%GOPATH%\\bin;c:\\go\\bin;%PATH%\n  - git submodule update --init\n  - rmdir C:\\go /s /q\n  - appveyor DownloadFile https://storage.googleapis.com/golang/go%GOVERSION%.windows-%GETH_ARCH%.zip\n  - 7z x go%GOVERSION%.windows-%GETH_ARCH%.zip -y -oC:\\ > NUL\n  - go version\n  - go env\n  - gcc --version\n\n# To run your custom scripts instead of automatic MSBuild\nbuild_script:\n  # We need to disable firewall - https://github.com/appveyor/ci/issues/1579#issuecomment-309830648\n  - ps: Disable-NetFirewallRule -DisplayName 'File and Printer Sharing (SMB-Out)'\n  - cd c:\\gopath\\src\\github.com\\go-vgo\\robotgo\n  - git branch\n  - go get -t ./...\n\n# To run your custom scripts instead of automatic tests\ntest_script:\n  # Unit tests\n  - ps: Add-AppveyorTest \"Unit Tests\" -Outcome Running\n  - go test -v github.com/go-vgo/robotgo/...\n  - ps: Update-AppveyorTest \"Unit Tests\" -Outcome Passed\n\n# notifications:\n#   - provider: Email\n#     to:\n#       - .io\n#     on_build_failure: true\n#     on_build_status_changed: true\n# to disable deployment\ndeploy: off\n"
  },
  {
    "path": "base/LICENSE",
    "content": "The software is licensed under the terms of the MIT license.\n\nCopyright 2010 Michael Sanders, AE and the go-vgo Project Developers.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE."
  },
  {
    "path": "base/MMBitmap.h",
    "content": "#pragma once\n#ifndef MMBITMAP_H\n#define MMBITMAP_H\n\n#include \"types.h\"\n#include \"rgb.h\"\n#include <assert.h>\n#include <stdint.h>\n\nstruct _MMBitmap {\n\tuint8_t *imageBuffer;  /* Pixels stored in Quad I format; */\n\tint32_t width;          /* Never 0, unless image is NULL. */\n\tint32_t height;         /* Never 0, unless image is NULL. */\n\t\n\tint32_t bytewidth;      /* The aligned width (width + padding). */\n\tuint8_t bitsPerPixel;  /* Should be either 24 or 32. */\n\tuint8_t bytesPerPixel; /* For convenience; should be bitsPerPixel / 8. */\n};\n\ntypedef struct _MMBitmap MMBitmap;\ntypedef MMBitmap *MMBitmapRef;\n\n#define MMBitmapPointInBounds(image, p) ((p).x < (image)->width && (p).y < (image)->height)\n\n/* Get pointer to pixel of MMBitmapRef. No bounds checking is performed */\n#define MMRGBColorRefAtPoint(image, x, y) \\\n\t\t\t(MMRGBColor *)(assert(MMBitmapPointInBounds(image, MMPointInt32Make(x, y))), \\\n\t        ((image)->imageBuffer) + (((image)->bytewidth * (y)) + ((x) * (image)->bytesPerPixel)))\n\n/* Dereference pixel of MMBitmapRef. Again, no bounds checking is performed. */\n#define MMRGBColorAtPoint(image, x, y) *MMRGBColorRefAtPoint(image, x, y)\n\n/* Hex/integer value of color at point. */\n#define MMRGBHexAtPoint(image, x, y) hexFromMMRGB(MMRGBColorAtPoint(image, x, y))\n\n#endif /* MMBITMAP_H */"
  },
  {
    "path": "base/base.go",
    "content": "// https://github.com/golang/go/issues/26366\npackage base\n"
  },
  {
    "path": "base/bitmap_free_c.h",
    "content": "#include \"MMBitmap.h\"\n#include <assert.h>\n#include <string.h>\n\nMMBitmapRef createMMBitmap_c(uint8_t *buffer, int32_t width, int32_t height, \n\tint32_t bytewidth, uint8_t bitsPerPixel, uint8_t bytesPerPixel\n) {\n\tMMBitmapRef bitmap = malloc(sizeof(MMBitmap));\n\tif (bitmap == NULL) { return NULL; }\n\n\tbitmap->imageBuffer = buffer;\n\tbitmap->width = width;\n\tbitmap->height = height;\n\tbitmap->bytewidth = bytewidth;\n\tbitmap->bitsPerPixel = bitsPerPixel;\n\tbitmap->bytesPerPixel = bytesPerPixel;\n\n\treturn bitmap;\n}\n\nvoid destroyMMBitmap(MMBitmapRef bitmap) {\n\tassert(bitmap != NULL);\n\n\tif (bitmap->imageBuffer != NULL) {\n\t\tfree(bitmap->imageBuffer);\n\t\tbitmap->imageBuffer = NULL;\n\t}\n\n\tfree(bitmap);\n}\n\nvoid destroyMMBitmapBuffer(char * bitmapBuffer, void * hint) {\n\tif (bitmapBuffer != NULL) {\n\t\tfree(bitmapBuffer);\n\t}\n}\n"
  },
  {
    "path": "base/deadbeef_rand.h",
    "content": "#ifndef DEADBEEF_RAND_H\n#define DEADBEEF_RAND_H\n\n#include <stdint.h>\n\n#define DEADBEEF_MAX UINT32_MAX\n/* Dead Beef Random Number Generator From: http://inglorion.net/software/deadbeef_rand */\n\n/* Generates a random number between 0 and DEADBEEF_MAX. */\nuint32_t deadbeef_rand(void);\n\n/* Seeds with the given integer. */\nvoid deadbeef_srand(uint32_t x);\n\n/* Generates seed from the current time. */\nuint32_t deadbeef_generate_seed(void);\n\n/* Seeds with the above function. */\n#define deadbeef_srand_time() deadbeef_srand(deadbeef_generate_seed())\n\n/* Returns random double in the range [a, b).*/\n#define DEADBEEF_UNIFORM(a, b) \\\n\t((a) + (deadbeef_rand() / (((double)DEADBEEF_MAX / (b - a) + 1))))\n\n/* Returns random integer in the range [a, b).*/\n#define DEADBEEF_RANDRANGE(a, b) (uint32_t)DEADBEEF_UNIFORM(a, b)\n\n#endif /* DEADBEEF_RAND_H */\n"
  },
  {
    "path": "base/deadbeef_rand_c.h",
    "content": "#include \"deadbeef_rand.h\"\n#include <time.h>\n\nstatic uint32_t deadbeef_seed;\nstatic uint32_t deadbeef_beef = 0xdeadbeef;\n\nuint32_t deadbeef_rand(void) {\n\tdeadbeef_seed = (deadbeef_seed << 7) ^ ((deadbeef_seed >> 25) + deadbeef_beef);\n\tdeadbeef_beef = (deadbeef_beef << 7) ^ ((deadbeef_beef >> 25) + 0xdeadbeef);\n\treturn deadbeef_seed;\n}\n\nvoid deadbeef_srand(uint32_t x) {\n\tdeadbeef_seed = x;\n\tdeadbeef_beef = 0xdeadbeef;\n}\n\n/* Taken directly from the documentation: http://inglorion.net/software/cstuff/deadbeef_rand/ */\nuint32_t deadbeef_generate_seed(void) {\n\t  uint32_t t = (uint32_t)time(NULL);\n\t  uint32_t c = (uint32_t)clock();\n\t  return (t << 24) ^ (c << 11) ^ t ^ (size_t) &c;\n}\n"
  },
  {
    "path": "base/inline_keywords.h",
    "content": "#pragma once\n\n/* A complicated, portable model for declaring inline functions in header files. */\n#if !defined(H_INLINE)\n    #if defined(__GNUC__)\n        #define H_INLINE static __inline__ __attribute__((always_inline))\n    #elif defined(__MWERKS__) || defined(__cplusplus)\n        #define H_INLINE static inline\n    #elif defined(_MSC_VER)\n        #define H_INLINE static __inline\n    #elif TARGET_OS_WIN32\n        #define H_INLINE static __inline__\n    #endif\n#endif /* H_INLINE */\n"
  },
  {
    "path": "base/microsleep.h",
    "content": "#pragma once\n#ifndef MICROSLEEP_H\n#define MICROSLEEP_H\n\n#include \"os.h\"\n#include \"inline_keywords.h\"\n\n// todo: removed\n#if !defined(IS_WINDOWS)\n\t/* Make sure nanosleep gets defined even when using C89. */\n\t#if !defined(__USE_POSIX199309) || !__USE_POSIX199309\n\t\t#define __USE_POSIX199309 1\n\t#endif\n\n\t#include <time.h> /* For nanosleep() */\n#endif\n\n/* A more widely supported alternative to usleep(), based on Sleep() in Windows and nanosleep() */\nH_INLINE void microsleep(double milliseconds) {\n#if defined(IS_WINDOWS)\n\tSleep((DWORD)milliseconds); /* (Unfortunately truncated to a 32-bit integer.) */\n#else\n\t/* Technically, nanosleep() is not an ANSI function */\n\tstruct timespec sleepytime;\n\tsleepytime.tv_sec = milliseconds / 1000;\n\tsleepytime.tv_nsec = (milliseconds - (sleepytime.tv_sec * 1000)) * 1000000;\n\tnanosleep(&sleepytime, NULL);\n#endif\n}\n\n#endif /* MICROSLEEP_H */\n"
  },
  {
    "path": "base/os.h",
    "content": "#pragma once\n#ifndef OS_H\n#define OS_H\n\n#if !defined(IS_MACOSX) && defined(__APPLE__) && defined(__MACH__)\n\t#define IS_MACOSX\n#endif /* IS_MACOSX */\n\n#if !defined(IS_WINDOWS) && (defined(WIN32) || defined(_WIN32) || \\\n                            defined(__WIN32__) || defined(__WINDOWS__) || defined(__CYGWIN__))\n\t#define IS_WINDOWS\n#endif /* IS_WINDOWS */\n\n#if !defined(USE_X11) && !defined(NUSE_X11) && !defined(IS_MACOSX) && !defined(IS_WINDOWS)\n\t#define USE_X11\n#endif /* USE_X11 */\n\n#if defined(IS_WINDOWS)\n\t#define STRICT /* Require use of exact types. */\n\t#define WIN32_LEAN_AND_MEAN 1 /* Speed up compilation. */\n\t#include <windows.h>\n#elif !defined(IS_MACOSX) && !defined(USE_X11)\n\t#error \"Sorry, this platform isn't supported yet!\"\n#endif\n\n/* Interval to align by for large buffers (e.g. bitmaps). Must be a power of 2. */\n#ifndef BYTE_ALIGN\n\t#define BYTE_ALIGN 4 /* Bytes to align pixel buffers to. */\n\t/* #include <stddef.h> */\n\t/* #define BYTE_ALIGN (sizeof(size_t)) */\n#endif /* BYTE_ALIGN */\n\n#if BYTE_ALIGN == 0\n\t/* No alignment needed. */\n\t#define ADD_PADDING(width) (width)\n#else\n\t/* Aligns given width to padding. */\n\t#define ADD_PADDING(width) (BYTE_ALIGN + (((width) - 1) & ~(BYTE_ALIGN - 1)))\n#endif\n\n#if defined(IS_WINDOWS)\n\t#if defined (_WIN64)\n\t\t#define RobotGo_64\n\t#else\n\t\t#define RobotGo_32\n\t#endif\n#else\n\t#if defined (__x86_64__)\n\t\t#define RobotGo_64\n\t#else\n\t\t#define RobotGo_32\n\t#endif\n#endif\n\n#endif /* OS_H */\n"
  },
  {
    "path": "base/pubs.h",
    "content": "#if defined(IS_WINDOWS)\n    BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {\n        uint32_t *count = (uint32_t*)dwData;\n        (*count)++;\n        return TRUE;\n    }\n   \n    typedef struct{\n\t    HWND hWnd;\n\t    DWORD dwPid;\n\t}WNDINFO;\n\n\tBOOL CALLBACK EnumWindowsProc(HWND hWnd, LPARAM lParam){\n\t    WNDINFO* pInfo = (WNDINFO*)lParam;\n\t    DWORD dwProcessId = 0;\n\t    GetWindowThreadProcessId(hWnd, &dwProcessId);\n\n\t    if (dwProcessId == pInfo->dwPid) {\n\t        pInfo->hWnd = hWnd;\n\t        return FALSE;\n\t    }\n\t    return TRUE;\n\t}\n\n\tHWND GetHwndByPid(DWORD dwProcessId) {\n\t    WNDINFO info = {0};\n\t    info.hWnd = NULL;\n\t    info.dwPid = dwProcessId;\n\t    EnumWindows(EnumWindowsProc, (LPARAM)&info);\n\n\t    return info.hWnd;\n\t}\n#endif"
  },
  {
    "path": "base/rgb.h",
    "content": "#pragma once\n#ifndef RGB_H\n#define RGB_H\n\n#include <stdlib.h> /* For abs() */\n#include <math.h>\n#include \"inline_keywords.h\" /* For H_INLINE */\n#include <stdint.h>\n\n/* #define MMRGB_IS_BGR (offsetof(MMRGBColor, red) > offsetof(MMRGBColor, blue)) */\n#define MMRGB_IS_BGR 1\n\nstruct _MMRGBColor {\n\tuint8_t blue;\n\tuint8_t green;\n\tuint8_t red;\n};\ntypedef struct _MMRGBColor MMRGBColor;\n\n/* MMRGBHex is a hexadecimal color value*/\ntypedef uint32_t MMRGBHex;\n\n#define MMRGBHEX_MIN 0x000000\n#define MMRGBHEX_MAX 0xFFFFFF\n\n/* Converts rgb color to hexadecimal value. */\n#define RGB_TO_HEX(red, green, blue) (((red) << 16) | ((green) << 8) | (blue))\n\n/* Convenience wrapper for MMRGBColors. */\nH_INLINE MMRGBHex hexFromMMRGB(MMRGBColor rgb) {\n\treturn RGB_TO_HEX(rgb.red, rgb.green, rgb.blue);\n}\n\n#define RED_FROM_HEX(hex) ((hex >> 16) & 0xFF)\n#define GREEN_FROM_HEX(hex) ((hex >> 8) & 0xFF)\n#define BLUE_FROM_HEX(hex) (hex & 0xFF)\n\n/* Converts hexadecimal color to MMRGBColor. */\nH_INLINE MMRGBColor MMRGBFromHex(MMRGBHex hex) {\n\tMMRGBColor color;\n\tcolor.red = RED_FROM_HEX(hex);\n\tcolor.green = GREEN_FROM_HEX(hex);\n\tcolor.blue = BLUE_FROM_HEX(hex);\n\treturn color;\n}\n\n/* Check absolute equality of two RGB colors. */\n#define MMRGBColorEqualToColor(c1, c2) ((c1).red == (c2).red && \\\n                                        (c1).blue == (c2).blue && \\\n                                        (c1).green == (c2).green)\n\n/* Returns whether two colors are similar within the given range, |tolerance|.*/\nH_INLINE int MMRGBColorSimilarToColor(MMRGBColor c1, MMRGBColor c2, float tolerance) {\n\t/* Speedy case */\n\tif (tolerance <= 0.0f) {\n\t\treturn MMRGBColorEqualToColor(c1, c2);\n\t} else { /* Otherwise, use a Euclidean space to determine similarity */\n\t\tuint8_t d1 = c1.red - c2.red;\n\t\tuint8_t d2 = c1.green - c2.green;\n\t\tuint8_t d3 = c1.blue - c2.blue;\n\t\treturn sqrt((double)(d1 * d1) + (d2 * d2) +\n\t\t            (d3 * d3)) <= (tolerance * 442.0f);\n\t}\n}\n\n/* Identical to MMRGBColorSimilarToColor, only for hex values. */\nH_INLINE int MMRGBHexSimilarToColor(MMRGBHex h1, MMRGBHex h2, float tolerance) {\n\tif (tolerance <= 0.0f) {\n\t\treturn h1 == h2;\n\t} else {\n\t\tint d1 = RED_FROM_HEX(h1) - RED_FROM_HEX(h2);\n\t\tint d2 = GREEN_FROM_HEX(h1) - GREEN_FROM_HEX(h2);\n\t\tint d3 = BLUE_FROM_HEX(h1) - BLUE_FROM_HEX(h2);\n\t\treturn sqrt((double)(d1 * d1) + (d2 * d2) +\n\t\t            (d3 * d3)) <= (tolerance * 442.0f);\n\t}\n}\n\n#endif /* RGB_H */\n"
  },
  {
    "path": "base/types.h",
    "content": "#pragma once\n#ifndef TYPES_H\n#define TYPES_H\n\n#include \"os.h\"\n#include \"inline_keywords.h\" /* For H_INLINE */\n#include <stddef.h>\n#include <stdint.h>\n#include <stdbool.h>\n\n/* Some generic, cross-platform types. */\n#ifdef RobotGo_64\n\ttypedef int64_t\t\t\tintptr;\t\n\ttypedef uint64_t\t\tuintptr;\t\n#else\n\ttypedef int32_t\t\t\t intptr;\n\ttypedef uint32_t\t\t uintptr;\t// Unsigned pointer integer\n#endif\n\nstruct _MMPointInt32 {\n\tint32_t x;\n\tint32_t y;\n};\ntypedef struct _MMPointInt32 MMPointInt32;\n\nstruct _MMSizeInt32 {\n\tint32_t w;\n\tint32_t h;\n};\ntypedef struct _MMSizeInt32 MMSizeInt32;\n\nstruct _MMRectInt32 {\n\tMMPointInt32 origin;\n\tMMSizeInt32 size;\n};\ntypedef struct _MMRectInt32 MMRectInt32;\n\nH_INLINE MMPointInt32 MMPointInt32Make(int32_t x, int32_t y) {\n\tMMPointInt32 point;\n\tpoint.x = x;\n\tpoint.y = y;\n\treturn point;\n}\n\nH_INLINE MMSizeInt32 MMSizeInt32Make(int32_t w, int32_t h) {\n\tMMSizeInt32 size;\n\tsize.w = w;\n\tsize.h = h;\n\treturn size;\n}\n\nH_INLINE MMRectInt32 MMRectInt32Make(int32_t x, int32_t y, int32_t w, int32_t h) {\n\tMMRectInt32 rect;\n\trect.origin = MMPointInt32Make(x, y);\n\trect.size = MMSizeInt32Make(w, h);\n\treturn rect;\n}\n\n#define MMPointZero MMPointInt32Make(0, 0)\n\n#if defined(IS_MACOSX)\n\t#define CGPointFromMMPointInt32(p) CGPointMake((CGFloat)(p).x, (CGFloat)(p).y)\n\t#define MMPointInt32FromCGPoint(p) MMPointInt32Make((int32_t)(p).x, (int32_t)(p).y)\n#elif defined(IS_WINDOWS)\n\t#define MMPointInt32FromPOINT(p) MMPointInt32Make((int32_t)p.x, (int32_t)p.y)\n#endif\n\n#endif /* TYPES_H */\n"
  },
  {
    "path": "base/xdisplay_c.h",
    "content": "#include <stdio.h> /* For fputs() */\n#include <stdlib.h> /* For atexit() */\n#include <X11/Xlib.h>\n\nstatic Display *mainDisplay = NULL;\nstatic int registered = 0;\n\nstatic char *displayName = NULL;\nstatic int hasDisplayNameChanged = 0;\n\nvoid XCloseMainDisplay(void) {\n\tif (mainDisplay != NULL) {\n\t\tXCloseDisplay(mainDisplay);\n\t\tmainDisplay = NULL;\n\t}\n}\n\nDisplay *XGetMainDisplay(void) {\n\t/* Close the display if displayName has changed */\n\tif (hasDisplayNameChanged) {\n\t\tXCloseMainDisplay();\n\t\thasDisplayNameChanged = 0;\n\t}\n\n\tif (mainDisplay == NULL) {\n\t\t/* First try the user set displayName */\n\t\tmainDisplay = XOpenDisplay(displayName);\n\n\t\t/* Then try using environment variable DISPLAY */\n\t\tif (mainDisplay == NULL && displayName != NULL) {\n\t\t\tmainDisplay = XOpenDisplay(NULL);\n\t\t}\n\n\t\t/* Fall back to the most likely :0.0*/\n\t\tif (mainDisplay == NULL) {\n\t\t\tmainDisplay = XOpenDisplay(\":0.0\");\n\t\t}\n\n\t\tif (mainDisplay == NULL) {\n\t\t\tfputs(\"Could not open main display\\n\", stderr);\n\t\t} else if (!registered) {\n\t\t\tatexit(&XCloseMainDisplay);\n\t\t\tregistered = 1;\n\t\t}\n\t}\n\n\treturn mainDisplay;\n}\n\nvoid setXDisplay(char *name) {\n\tdisplayName = strdup(name);\n\thasDisplayNameChanged = 1;\n}\n\nchar *getXDisplay(void) {\n\treturn displayName;\n}\n"
  },
  {
    "path": "clipboard/README.md",
    "content": "This directory based on [clipboard](https://github.com/atotto/clipboard).\n\n[![Build Status](https://travis-ci.org/atotto/clipboard.svg?branch=master)](https://travis-ci.org/atotto/clipboard)\n[![GoDoc](https://godoc.org/github.com/atotto/clipboard?status.svg)](http://godoc.org/github.com/atotto/clipboard)\n<!--[![Build Status](https://drone.io/github.com/atotto/clipboard/status.png)](https://drone.io/github.com/atotto/clipboard/latest) -->\n\n# Clipboard for Go\n\nProvide copying and pasting to the Clipboard for Go.\n\n<!--Download shell commands at https://drone.io/github.com/atotto/clipboard/files-->\n\nBuild:\n\n    $ go get github.com/atotto/clipboard\n\nPlatforms:\n\n* OSX\n* Windows 7 (probably work on other Windows)\n* Linux, Unix (requires 'xclip' or 'xsel' command to be installed)\n\n\nDocument: \n\n* http://godoc.org/github.com/atotto/clipboard\n\nNotes:\n\n* Text string only\n* UTF-8 text encoding only (no conversion)\n\nTODO:\n\n* Clipboard watcher(?)\n\n## Commands:\n\npaste shell command:\n\n    $ go get github.com/atotto/clipboard/cmd/gopaste\n    $ # example:\n    $ gopaste > document.txt\n\ncopy shell command:\n\n    $ go get github.com/atotto/clipboard/cmd/gocopy\n    $ # example:\n    $ cat document.txt | gocopy\n\n\n\n"
  },
  {
    "path": "clipboard/clipboard.go",
    "content": "// Copyright 2013 @atotto. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n/*\nPackage clipboard read/write on clipboard\n*/\npackage clipboard\n\n// import ()\n\n// ReadAll read string from clipboard\nfunc ReadAll() (string, error) {\n\treturn readAll()\n}\n\n// WriteAll write string to clipboard\nfunc WriteAll(text string) error {\n\treturn writeAll(text)\n}\n\n// Unsupported might be set true during clipboard init,\n// to help callers decide whether or not to\n// offer clipboard options.\nvar Unsupported bool\n"
  },
  {
    "path": "clipboard/clipboard_darwin.go",
    "content": "// Copyright 2013 @atotto. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n//go:build darwin\n// +build darwin\n\npackage clipboard\n\nimport (\n\t\"os/exec\"\n)\n\nvar (\n\tpasteCmdArgs = \"pbpaste\"\n\tcopyCmdArgs  = \"pbcopy\"\n)\n\nfunc getPasteCommand() *exec.Cmd {\n\treturn exec.Command(pasteCmdArgs)\n}\n\nfunc getCopyCommand() *exec.Cmd {\n\treturn exec.Command(copyCmdArgs)\n}\n\nfunc readAll() (string, error) {\n\tpasteCmd := getPasteCommand()\n\tout, err := pasteCmd.Output()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn string(out), nil\n}\n\nfunc writeAll(text string) error {\n\tcopyCmd := getCopyCommand()\n\tin, err := copyCmd.StdinPipe()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := copyCmd.Start(); err != nil {\n\t\treturn err\n\t}\n\tif _, err := in.Write([]byte(text)); err != nil {\n\t\treturn err\n\t}\n\tif err := in.Close(); err != nil {\n\t\treturn err\n\t}\n\n\treturn copyCmd.Wait()\n}\n"
  },
  {
    "path": "clipboard/clipboard_test.go",
    "content": "// Copyright 2013 @atotto. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n//go:build darwin || windows\n// +build darwin windows\n\npackage clipboard_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/go-vgo/robotgo/clipboard\"\n)\n\nfunc TestCopyAndPaste(t *testing.T) {\n\texpected := \"日本語\"\n\n\terr := clipboard.WriteAll(expected)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tactual, err := clipboard.ReadAll()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif actual != expected {\n\t\tt.Errorf(\"want %s, got %s\", expected, actual)\n\t}\n}\n\nfunc TestMultiCopyAndPaste(t *testing.T) {\n\texpected1 := \"French: éèêëàùœç\"\n\texpected2 := \"Weird UTF-8: 💩☃\"\n\n\terr := clipboard.WriteAll(expected1)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tactual1, err := clipboard.ReadAll()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif actual1 != expected1 {\n\t\tt.Errorf(\"want %s, got %s\", expected1, actual1)\n\t}\n\n\terr = clipboard.WriteAll(expected2)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tactual2, err := clipboard.ReadAll()\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif actual2 != expected2 {\n\t\tt.Errorf(\"want %s, got %s\", expected2, actual2)\n\t}\n}\n\nfunc BenchmarkReadAll(b *testing.B) {\n\tfor i := 0; i < b.N; i++ {\n\t\tclipboard.ReadAll()\n\t}\n}\n\nfunc BenchmarkWriteAll(b *testing.B) {\n\ttext := \"いろはにほへと\"\n\tfor i := 0; i < b.N; i++ {\n\t\tclipboard.WriteAll(text)\n\t}\n}\n"
  },
  {
    "path": "clipboard/clipboard_unix.go",
    "content": "// Copyright 2013 @atotto. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n//go:build freebsd || linux || netbsd || openbsd || solaris || dragonfly\n// +build freebsd linux netbsd openbsd solaris dragonfly\n\npackage clipboard\n\nimport (\n\t\"errors\"\n\t\"os/exec\"\n)\n\nconst (\n\txsel  = \"xsel\"\n\txclip = \"xclip\"\n)\n\nvar (\n\t// Primary choose primary mode on unix\n\tPrimary bool\n\n\tpasteCmdArgs, copyCmdArgs []string\n\n\txselPasteArgs = []string{xsel, \"--output\", \"--clipboard\"}\n\txselCopyArgs  = []string{xsel, \"--input\", \"--clipboard\"}\n\n\txclipPasteArgs = []string{xclip, \"-out\", \"-selection\", \"clipboard\"}\n\txclipCopyArgs  = []string{xclip, \"-in\", \"-selection\", \"clipboard\"}\n\n\terrMissingCommands = errors.New(\"No clipboard utilities available. Please install xsel or xclip\")\n)\n\nfunc init() {\n\tpasteCmdArgs = xclipPasteArgs\n\tcopyCmdArgs = xclipCopyArgs\n\n\tif _, err := exec.LookPath(xclip); err == nil {\n\t\treturn\n\t}\n\n\tpasteCmdArgs = xselPasteArgs\n\tcopyCmdArgs = xselCopyArgs\n\n\tif _, err := exec.LookPath(xsel); err == nil {\n\t\treturn\n\t}\n\n\tUnsupported = true\n}\n\nfunc getPasteCommand() *exec.Cmd {\n\tif Primary {\n\t\tpasteCmdArgs = pasteCmdArgs[:1]\n\t}\n\treturn exec.Command(pasteCmdArgs[0], pasteCmdArgs[1:]...)\n}\n\nfunc getCopyCommand() *exec.Cmd {\n\tif Primary {\n\t\tcopyCmdArgs = copyCmdArgs[:1]\n\t}\n\treturn exec.Command(copyCmdArgs[0], copyCmdArgs[1:]...)\n}\n\nfunc readAll() (string, error) {\n\tif Unsupported {\n\t\treturn \"\", errMissingCommands\n\t}\n\n\tpasteCmd := getPasteCommand()\n\tout, err := pasteCmd.Output()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn string(out), nil\n}\n\nfunc writeAll(text string) error {\n\tif Unsupported {\n\t\treturn errMissingCommands\n\t}\n\tcopyCmd := getCopyCommand()\n\tin, err := copyCmd.StdinPipe()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif err := copyCmd.Start(); err != nil {\n\t\treturn err\n\t}\n\tif _, err := in.Write([]byte(text)); err != nil {\n\t\treturn err\n\t}\n\tif err := in.Close(); err != nil {\n\t\treturn err\n\t}\n\n\treturn copyCmd.Wait()\n}\n"
  },
  {
    "path": "clipboard/clipboard_windows.go",
    "content": "// Copyright 2013 @atotto. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\n//go:build windows\n// +build windows\n\npackage clipboard\n\nimport (\n\t\"syscall\"\n\t\"time\"\n\t\"unsafe\"\n)\n\nconst (\n\tcfUnicodetext = 13\n\t// gmemFixed     = 0x0000\n\tgmemMoveable = 0x0002\n)\n\nvar (\n\tuser32           = syscall.MustLoadDLL(\"user32\")\n\topenClipboard    = user32.MustFindProc(\"OpenClipboard\")\n\tcloseClipboard   = user32.MustFindProc(\"CloseClipboard\")\n\temptyClipboard   = user32.MustFindProc(\"EmptyClipboard\")\n\tgetClipboardData = user32.MustFindProc(\"GetClipboardData\")\n\tsetClipboardData = user32.MustFindProc(\"SetClipboardData\")\n\n\tkernel32     = syscall.NewLazyDLL(\"kernel32\")\n\tglobalAlloc  = kernel32.NewProc(\"GlobalAlloc\")\n\tglobalFree   = kernel32.NewProc(\"GlobalFree\")\n\tglobalLock   = kernel32.NewProc(\"GlobalLock\")\n\tglobalUnlock = kernel32.NewProc(\"GlobalUnlock\")\n\tlstrcpy      = kernel32.NewProc(\"lstrcpyW\")\n)\n\n// waitOpenClipboard opens the clipboard, waiting for up to a second to do so.\nfunc waitOpenClipboard() error {\n\tstarted := time.Now()\n\tlimit := started.Add(time.Second)\n\tvar (\n\t\tr   uintptr\n\t\terr error\n\t)\n\tfor time.Now().Before(limit) {\n\t\tr, _, err = openClipboard.Call(0)\n\t\tif r != 0 {\n\t\t\treturn nil\n\t\t}\n\t\ttime.Sleep(time.Millisecond)\n\t}\n\n\treturn err\n}\n\nfunc readAll() (string, error) {\n\t// r, _, err := openClipboard.Call(0)\n\terr := waitOpenClipboard()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer closeClipboard.Call()\n\n\th, _, err := getClipboardData.Call(cfUnicodetext)\n\tif h == 0 {\n\t\treturn \"\", err\n\t}\n\n\tl, _, err := globalLock.Call(h)\n\tif l == 0 {\n\t\treturn \"\", err\n\t}\n\n\ttext := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(l))[:])\n\n\tr, _, err := globalUnlock.Call(h)\n\tif r == 0 {\n\t\treturn \"\", err\n\t}\n\n\treturn text, nil\n}\n\nfunc writeAll(text string) error {\n\terr := waitOpenClipboard()\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer closeClipboard.Call()\n\n\tr, _, err := emptyClipboard.Call(0)\n\tif r == 0 {\n\t\treturn err\n\t}\n\n\tdata := syscall.StringToUTF16(text)\n\n\t// \"If the hMem parameter identifies a memory object, the object must have\n\t// been allocated using the function with the GMEM_MOVEABLE flag.\"\n\th, _, err := globalAlloc.Call(gmemMoveable,\n\t\tuintptr(len(data)*int(unsafe.Sizeof(data[0]))))\n\tif h == 0 {\n\t\treturn err\n\t}\n\n\tdefer func() {\n\t\tif h != 0 {\n\t\t\tglobalFree.Call(h)\n\t\t}\n\t}()\n\n\tl, _, err := globalLock.Call(h)\n\tif l == 0 {\n\t\treturn err\n\t}\n\n\tr, _, err = lstrcpy.Call(l, uintptr(unsafe.Pointer(&data[0])))\n\tif r == 0 {\n\t\treturn err\n\t}\n\n\tr, _, err = globalUnlock.Call(h)\n\tif r == 0 {\n\t\tif err.(syscall.Errno) != 0 {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tr, _, err = setClipboardData.Call(cfUnicodetext, h)\n\tif r == 0 {\n\t\treturn err\n\t}\n\n\th = 0 // suppress deferred cleanup\n\treturn nil\n}\n"
  },
  {
    "path": "clipboard/cmd/gocopy/gocopy.go",
    "content": "package main\n\nimport (\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/go-vgo/robotgo/clipboard\"\n)\n\nfunc main() {\n\tout, err := io.ReadAll(os.Stdin)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tif err := clipboard.WriteAll(string(out)); err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "clipboard/cmd/gopaste/gopaste.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/go-vgo/robotgo/clipboard\"\n)\n\nfunc main() {\n\ttext, err := clipboard.ReadAll()\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Print(text)\n}\n"
  },
  {
    "path": "clipboard/example/example.go",
    "content": "package main\n\nimport (\n\t\"log\"\n\n\t\"github.com/go-vgo/robotgo/clipboard\"\n)\n\nfunc main() {\n\terr := clipboard.WriteAll(\"日本語\")\n\tif err != nil {\n\t\tlog.Println(\"clipboard write all error: \", err)\n\t}\n\n\ttext, err := clipboard.ReadAll()\n\tif err != nil {\n\t\tlog.Println(\"clipboard read all error: \", err)\n\t\treturn\n\t}\n\n\tif text != \"\" {\n\t\tlog.Println(\"text is: \", text)\n\t\t// Output: 日本語\n\t}\n}\n"
  },
  {
    "path": "cv/README.md",
    "content": "robotgo gocv\n\n"
  },
  {
    "path": "cv/gocv.go",
    "content": "package cv\n"
  },
  {
    "path": "doc.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\npackage robotgo\n\n/*\nKeys are supported:\n\t\"A-Z a-z 0-9\"\n\n\t\"backspace\"\n\t\"delete\"\n\t\"enter\"\n\t\"tab\"\n\t\"esc\"\n\t\"escape\"\n\t\"up\"\t\tUp arrow key\n\t\"down\"\t\tDown arrow key\n\t\"right\"\t\tRight arrow key\n\t\"left\"\t\tLeft arrow key\n\t\"home\"\n\t\"end\"\n\t\"pageup\"\n\t\"pagedown\"\n\n\t\"f1\"\n\t\"f2\"\n\t\"f3\"\n\t\"f4\"\n\t\"f5\"\n\t\"f6\"\n\t\"f7\"\n\t\"f8\"\n\t\"f9\"\n\t\"f10\"\n\t\"f11\"\n\t\"f12\"\n\t\"f13\"\n\t\"f14\"\n\t\"f15\"\n\t\"f16\"\n\t\"f17\"\n\t\"f18\"\n\t\"f19\"\n\t\"f20\"\n\t\"f21\"\n\t\"f22\"\n\t\"f23\"\n\t\"f24\"\n\n\t\"cmd\"\t\tthis is the \"win\" key for windows\n\t\"lcmd\"\t\tleft command\n\t\"rcmd\"\t\tright command\n\t// \"command\"\n\t\"alt\"\n\t\"lalt\"\t\tleft alt\n\t\"ralt\"\t\tright alt\n\t\"ctrl\"\n\t\"lctrl\"\t\tleft ctrl\n\t\"rctrl\"\t\tright ctrl\n\t\"control\"\n\t\"shift\"\n\t\"lshift\"\tleft shift\n\t\"rshift\"\tright shift\n\t// \"right_shift\"\n\t\"capslock\"\n\t\"space\"\n\t\"print\"\n\t\"printscreen\"      // No Mac support\n\t\"insert\"\n\t\"menu\"\t\t\t\tWindows only\n\n\t\"audio_mute\"\t\tMute the volume\n\t\"audio_vol_down\"\tLower the volume\n\t\"audio_vol_up\"\t\tIncrease the volume\n\t\"audio_play\"\n\t\"audio_stop\"\n\t\"audio_pause\"\n\t\"audio_prev\"\t\tPrevious Track\n\t\"audio_next\"\t\tNext Track\n\t\"audio_rewind\"      Linux only\n\t\"audio_forward\"     Linux only\n\t\"audio_repeat\"      Linux only\n\t\"audio_random\"      Linux only\n\n\n\t\"num0\"\n\t\"num1\"\n\t\"num2\"\n\t\"num3\"\n\t\"num4\"\n\t\"num5\"\n\t\"num6\"\n\t\"num7\"\n\t\"num8\"\n\t\"num9\"\n\t\"num_lock\"\n\n\t\"num.\"\n\t\"num+\"\n\t\"num-\"\n\t\"num*\"\n\t\"num/\"\n\t\"num_clear\"\n\t\"num_enter\"\n\t\"num_equal\"\n\n\t\"lights_mon_up\"\t\t Turn up monitor brightness\t\t\t\t\tNo Windows support\n\t\"lights_mon_down\"\t Turn down monitor brightness\t\t\t\tNo Windows support\n\t\"lights_kbd_toggle\"\t Toggle keyboard backlight on/off\t\t\tNo Windows support\n\t\"lights_kbd_up\"\t\t Turn up keyboard backlight brightness\t\tNo Windows support\n\t\"lights_kbd_down\"\t Turn down keyboard backlight brightness\tNo Windows support\n*/\n\n/*\n## Type Conversion\n\n|     | type conversion\t    |  func\n|-----|---------------------|----------------------\n|\t*\t| robotgo.Bitmap -> robotgo.CBitmap | robotgo.ToCBitmap()\n|\t\t| robotgo.Bitmap -> *image.RGBA | robotgo.ToRGBAGo()\n|\t*\t| robotgo.CBitmap -> C.MMBitmapRef | robotgo.ToMMBitmapRef()\n|\t\t| robotgo.CBitmap -> robotgo.Bitmap | robotgo.ToBitmap()\n|\t\t| robotgo.CBitmap -> image.Image | robotgo.ToImage()\n|\t\t| robotgo.CBitmap -> *image.RGBA | robotgo.ToRGBA()\n|\t*\t| C.MMBitmapRef -> robotgo.CBitmap | robotgo.CBitmap()\n|\t*\t| image.Image -> robotgo.Bitmap | robotgo.ImgToBitmap()\n|\t\t| image.Image -> robotgo.CBitmap | robotgo.ImgToCBitmap()\n|\t\t| image.Image -> []byte | robotgo.ToByteImg()\n|\t\t| image.Image -> string | robotgo.ToStringImg()\n|\t*\t| *image.RGBA -> robotgo.Bitmap | robotgo.RGBAToBitmap()\n|\t*\t| []byte -> image.Image | robotgo.ByteToImg()\n|\t\t| []byte-> robotgo.CBitmap | robotgo.ByteToCBitmap()\n|\t\t| []byte -> string | string()\n|\t*\t| string -> image.Image | robotgo.StrToImg()\n|\t\t| string -> byte | []byte()\n*/\n"
  },
  {
    "path": "docs/CHANGELOG.md",
    "content": "# CHANGELOG\n\n<!--### RobotGo-->\n## RobotGo v0.100.0, MT. Baker; Enhancement bitmap and image, add arm support...\n\n### Add\n\n- [NEW] add more image function support\n- [NEW] add ImgToBitmap(), ToImg(), FindEveryBitmap(), FindEveryColor(), Svae(), Read(), SaveJpeg() and other function support\n\n- [NEW] add func ToImage: convert C.MMBitmapRef to standard image.Image\n- [NEW] add ToImage examples code\n- [NEW] add more image function and update go mod\n\n- [NEW] add find every color function\n- [NEW] add free and find all point function\n- [NEW] update find bitmap and color\n\n- [NEW] add byte to image function\n- [NEW] add more image convert function\n\n- [NEW] add mac os M1 support\n- [NEW] add windows arm support\n\n- [NEW] add more key toggle and press function\n\n- [NEW] add ToRGBA() function support\n- [NEW] add ImgToBitmap and RGBAToBitmap support\n- [NEW] Update and move image function to img.go\n\n- [NEW] add more img to bitmap examples code and Update file name\n\n### Update\n\n- [NEW] Update README.md and CHANGELOG.md\n- [NEW] add macOS to .travis.yml\n- [NEW] update go mod pkg\n\n- [NEW] Update hook examples link to newest\n- [NEW] update dockerfile and appveyor to go1.14.4\n\n- [NEW] Update README.md, add more examples\n- [NEW] move hook and event to gohook\n- [NEW] move cbitmap and bitmap-bytes to bitmap dir\n\n- [NEW] update some name\n- [NEW] update dockerfile and appveyor.yml\n\n- [NEW] update clipboard code\n- [NEW] update hook code and more API\n\n- [NEW] optimize code and update version\n- [NEW] add paste string err return and optimize code\n- [NEW] update go.yml and travis.yml to go1.15\n- [NEW] Update Ubuntu apt-get to apt\n\n- [NEW] update go version and key code\n- [NEW] update test code and go mod\n- [NEW] Update README.md and test code\n\n- [NEW] update parameter name and version\n- [NEW] update dockerfile and appveyor.yml\n- [NEW] update error return and print\n\n- [NEW] update ShowAlert optimize return code\n- [NEW] add more test and update go mod\n\n- [NEW] compatible with 32-bit platforms\n- [NEW] add more bitmap examples\n\n- [NEW] update point structure to public\n\n- [NEW] add more examples\n- [NEW] update examples and version\n- [NEW] Update clipboard example code\n\n- [NEW] Update README.md Section ####Other to windows (#348) …\n- [NEW] Update png.h path\n- [NEW] Update go mod\n- [NEW] Update circle.yml and travis.yml\n\n- [NEW] Remove unless example code and update circle.yml\n- [NEW] Removed drop api example code and Update README.md\n\n- [NEW] Update go mod and xx.yml\n- [NEW] Update README.md and example\n\n- [NEW] add more bitmap examples code\n- [NEW] Update go mod and Update README.md\n- [NEW] gofmt to 1.17 build tag\n- [NEW] Update bitmap examples code\n\n- [NEW] Update version and keycode\n- [NEW] Update docs remove drop API\n\n\n### Fixed\n\n- [FIX] Update go mod and fixed #290\n- [FIX] Update gohook to v0.30.2 fixed bug\n- [FIX] Fixed Mouse buttons reversed type\n- [FIX] Fixed returns \"Invalid key code specified.\" if specified character is not v… … add keyCodeForCharFallBack\n\n- [FIX] This fixes the disappearing backslash issue #351\n- [FIX] Export ToUC function and update test code\n- [FIX] Fixes #258: char* arrays in C not being copied correctly\n- [FIX] Fixed Linux TypeStr() function double quote\n\n- [FIX] update free bitmap fixed #333\n- [FIX] update gops to v0.20.0 fixed bug and other mod pkg\n- [FIX] update gohook fixed warning\n\n\n\n## RobotGo v0.90.0, MT. Rainier\n\n### Add\n\nadd gohook modern and concurrent API\nadd new gohook examples, thks for cauefcr\n\nSupport for multiple screens\nadd getMousePos() multiple screens support\nadd move smooth multiple screens support\n\nadd all platform system scale support\nadd get screen size test code\n\nadd screen and bitmap multiple screens support\nadd int32_t types support\n\nupdate keycode type use uint16 with gohook, not type convert\nadd ToBitmapBytes func (#204)\n\ngohook: sched_yield support for non-POSIX windows gcc\n\nadd gops test code support\nadd Process() function test code\nadd more gops test code\n\nadd more win32 function export\n\nadd get mouse color function\n\nadd uint32 to Chex function support\n\nadd key_Toggles() c function\nadd keyTap and keyToggle \"...string\" parameters support, Fixed #209\n\nadd robotgo simple test code\n\nadd Is64Bit() c and go function\n\nadd process FindPath() function\n\nadd keycode \"delete\" support and fixed \"\\\\\" error\nadd more keycode support, \"up, down, left, right\"...\n\nexport hook keycode and add godoc\n\nuse robotn fork xgb and update go mod\n\nadd hook example to robotgo examples\n\nupdate gohook and tt mod file\n\nadd more and update test code\n\nadd drag smooth function support and examples\n\nadd ShowAlert() test support\n\nupdate keypress rand sleep [reduce] and update code style, update c delay default value to 0\n\nadd mouse toggle return and add more test\n\nadd SetDelay function code and update other code\n\nadd scaled function code\n\nadd go opencv file\n\nadd readme.md file\n\nadd move mouse and move smooth relative code\n\nadd move mouse and move smooth relative examples\n\nadd more test code and update go tt mod\n\nadd more bitmap test code\n\nadd SaveImg function code\n\nadd drop function hint print support\n\nadd more key test code\nadd more test code\nadd paste string test code\nadd xvfb run codecov test\n\nadd keycode test support\n\nadd FindPath example code\n\nadd KeyTap() args[2] delay support\n\nadd find bitmap nil args support\n\nadd find color nil args support\n\nadd drag and move mouse multiple screens support\n\nadd drag mouse test code\n\nUse CGDisplayBounds not CGDisplayPixelsWide, optimize get mac display size …\n\nUpdate TypeStr function, add type delay and speed support\n\nupdate PasteStr function code return error\n\n### Update\n\nUpdate robot info test code and Add go.yml test support\n\nuse while not for match special key map\nremove unless x11 special key and sort\n\nupdate go mod pkg\nupdate mod vendor\nremove vendor and update .gitignore\n\nupdate and fmt config.yml, add Linux go test support\nupdate Linux CI support x11 test\n\nmove hook to hook.go\n\nupdate appveyor and test code\nupdate version and code style\n\nupdate move mouse smooth test code\n\nupdate clipboard code and add test code\n\nupdate test code and add codecov support\n\nupdate show alert test code\n\nupdate keycode.go\n\nupdate window examples code\n\nupdate test code remove windows alert test\n\nmove gops code to ps.go\n\nupdate version\n\nupdate unix get title type\n\ngofmt go code and update code style\n\nadd ToBitmapBytes examples code\n\nupdate example code, fixed golint warning\n\nupdate bitmap example code\n\nUpdate CHANGELOG.md\n\nupdate code style\n\nupdate godoc\n\nupdate keytap code and code style\n\nupdate Bitmap struct delete fuzzy api\n\nupdate key examples code\n\nadd bitmap from string clear api\n\nupdate go mod vendor\nupdate go mod pkg not proxy\n\nupdate bitmap example code\n\nupdate test code fixed appveyor CI\n\nupdate test code fixed equal error\n\nupdate hook godoc\n\nupdate event example code\n\nupdate godoc and code style\n\nupdate key example code\n\nUpdate example README.md\n\nupdate and tidy go mod\n\nupdate code remove duplicate code and update godoc\n\nupdate xgb getXid log\n\nupdate GetBounds x11 error log\n\nupdate cgo code and version\n\nupdate TypeString function code [Drop]\n\nupdate key example code\n\nUpdate TypeStr function, optimize x11 type string\n\nUpdate TypeStrDelay function, remove unused code\n\nupdate code fixed x11 type sleep\n\nUpdate key example code\n\nuse gops to simplify code\nupdate key examples code\n\nupdate bitmap examples code\n\nupdate colorpicker and findcolor example code\n\nupdate bitmap example code\n\nupdate robotgo test code, add more test\n\nUpdate README.md\n\nrename type names make clearer\n\nupdate types.h code and fixed bug\n\nremove unused code fixed x11 build error\n\nupdate robot info test code and appveyor\n\nUpdate README.md, Add more CI badge\n\nupdate gohook pkg and robot info test code\n\nUpdate linux upper code, add more special key support\n\nCreate go.yml\nUpdate go.yml\nadd more test and update go.yml\nUpdate dockerfile to go1.13.5\n\nupdate dockerfile and appveyor.yml\nUpdate dockerfile and appveyor.yml to go1.14.3\n\nremove Travis go1.11.x\nupdate appveyor and dockerfile to go1.13.1\nupdate dockerfile, go.yml and appveyor.yml to go1.14\n\nupdate travis.yml to go1.14.x and remove go1.13.x\nUpdate and fmt appveyor.ymlu\nupdate dockerfile and appveyor to go1.12.5\n\nupdate appveyor and dockerfile to go1.12.6\n\nadd CI go1.13 support\nupdate config.yml\nupdate and fmt travis.yml\nUpdate Travis remove go1.12.x\n\nUpdate issue and pull request template\n\n### Fix\n\nUpdate to utf-code function Fixed #189\n\nUpdate x11 keypress upper code Fixed #243\n\ntype conversion needed in addMouse (#201)\n\nupdate hook, Fixed #202 fatal error: concurrent map writes\n\nadd key Kind Fixed #203\n\noptimize get title code, Fixed #165 and typo\n\nFixed gohook#3 mouse is_drag error on x11\n\nFixed #213 AddEvents() can't listen correctly multiple times\n\nupdate clipboard error hand Fixed #212\n\nUpdate go.mod fixing issue \"invalid pseudo-version: does not match version …\n\nupdate keyboard example code, #238\n\nupdate go mod file Fixed #239\n\nupdate gops and other mod files fixed bug\n\n\n## RobotGo v0.80.0, Sierra Nevada\n\n# Sierra Nevada\n\n### Add\n\n- [NEW] Add asynchronous event support\n- [NEW] Add multiple keypress event listener support\n- [NEW] Add hook start and end func\n- [NEW] Add AddEvents, AddMouse, AddMousePos hook function\n- [NEW] Add mul() scale func and optimize code\n- [NEW] Refactor AddEvent() func and add keycode.go, update example\n- [NEW] Add mouse map keycode\n- [NEW] Add android null file\n- [NEW] Add AddEvent \"center\" support\n- [NEW] Update README.md, Add binding link\n\n <br/>\n\n- [NEW] Format README.md and docs markdown\n- [NEW] Update bitmap_save return code\n- [NEW] Optimize code not defer and remove useless code\n- [NEW] Update code style and godoc\n- [NEW] Update go mod vendor\n- [NEW] Add more event examples\n- [NEW] add AddEvents, AddMouse, AddMousePos examples code\n\n\n### Update\n\n- [NEW] Update event example code add print hint\n- [NEW] Update godoc\n- [NEW] Update CHANGELOG.md\n- [NEW] Update .gitignore\n- [NEW] Update code style and examples\n- [NEW] Update pkg to newest\n- [NEW] Update CI add go1.12.x support\n- [NEW] Move GetText() func code\n\n### Fix\n\n- [FIX] Add AddEvents func, Fixed #98, #61, #69...\n- [FIX] Add asynchronous event support, Fixed #196, #89...\n- [FIX] add AddMouse func, Fixed #138\n- [FIX] Update _Ctype_char to C.char, Fixed go1.12 build error #191\n- [FIX] Update hook, Fixed #195 warning and json break bug\n- [FIX] Fixed color picker, Update README.md and docs\n\n\nSee Commits for more details, after Jan 7.\n\n\n## RobotGo v0.70.0, Caloris Montes\n\n# Caloris Montes\n\n### Add\n\n- [NEW] Update keyboard use sendInput not keybd_event\n- [NEW] Update mouse use sendInput not mouse_event\n- [NEW] Add drag mouse other button support\n- [NEW] Add more numpad key support\n- [NEW] Add numpad key and escape abbreviation support\n- [NEW] Add new window10 zoom ratio\n- [NEW] Add linux numpad key support\n- [NEW] Add key \"insert, printscreen\" mac support\n- [NEW] Add check mouse button func\n- [NEW] Add keyTap run error return support and update godoc\n\n\n <br/>\n\n- [NEW] Optimize and clearer keytap code\n- [NEW] Optimize and clean keyToggle code\n- [NEW] Update dockerfile clean image\n- [NEW] Add color picker and getMousePos() example\n- [NEW] Use go mod not dep, add go.mod remove dep files\n- [NEW] Add GetColors func return string\n- [NEW] Optimize defer code\n<br/>\n\n- [NEW] Add more godoc\n- [NEW] Add add key \"ctrl\", \"cmd\" [ abbreviation ] support\n- [NEW] Add add key \"capslock\", \"numpad_lock\" support\n- [NEW] Add left and right \"Ctrl, Shift, Alt, command\" key support\n- [NEW] Update check key flags support \"cmd\" and \"ctrl\"\n- [NEW] Update key docs\n- [NEW] Add millisleep func and update godoc\n- [NEW] Add AddEvent() key \"cmd\" support\n- [NEW] Update key example code\n- [NEW] Update README.md, add Note go1.10.x issue\n- [NEW] Update keytap and toggle return \"\" and code style\n\n\n### Update\n\n- [NEW] Update issue template more obvious\n- [NEW] Update godoc\n- [NEW] Update CHANGELOG.md\n- [NEW] Update .gitignore\n- [NEW] Update code style and examples\n- [NEW] Update pkg to newest\n- [NEW] Add more scale example\n- [NEW] Add drag mouse example\n<br/>\n\n- [NEW] Update key docs and clear file name\n- [NEW] Remove old useless code\n- [NEW] Update README.md\n- [NEW] Update CI add go1.11.4 version\n\n### Fix\n\n- [FIX] Fixed bitmapClick() parameter bug\n- [FIX] Fixed some README.md typo\n- [FIX] Update scale example code close #153\n- [FIX] Update code style and fixed #endif error\n\n\nSee Commits for more details, after Otc 8.\n\n\n## RobotGo v0.60.0, Mount Olympus: Mytikas\n\n### Add\n\n- [NEW] Add GetBounds func support (add get_client and get_frame C_func)\n- [NEW] Add GetXId and GetXidFromPid func\n- [NEW] Refactoring GetTitle() func allow by pid\n- [NEW] Refactoring CloseWindow() allow by pid\n- [NEW] Add SetHandPid() and GetHandPid() func support\n- [NEW] Add FindCBitmap func support\n <br/>\n\n- [NEW] Refactoring bitmap example code\n- [NEW] Refactoring key example code\n- [NEW] Refactoring window example code\n- [NEW] Add an cbitmap example [#169]\n- [NEW] Refactoring screen and event example code\n- [NEW] Refactoring mouse example code\n<br/>\n\n- [NEW] Add more godoc\n- [NEW] Add getTitle example by pid\n- [NEW] Add close window example by pid\n- [NEW] Add getBounds example\n- [NEW] Split func and remove dep more clean\n- [NEW] Simplify SaveCapture code\n- [NEW] Update and merged get_pixel_color remove duplicate code\n- [NEW] Update README.md, add Note go1.10.x\n\n\n### Update\n\n- [NEW] Update issue template more obvious\n- [NEW] Move public mdata to pub\n- [NEW] Update godoc\n- [NEW] Update CHANGELOG.md\n- [NEW] Move some pub method to pub.h and rename some c_func\n- [NEW] Update code style and name style ( key, window and other )\n- [NEW] Update robotgo unix export getXidFromPid func\n- [NEW] Update set handle return use bool\n<br/>\n\n- [NEW] Update code style and move scale to win_sys.h\n- [NEW] Update example add more lang\n- [NEW] Update pkg to newest\n- [NEW] Remove duplicate code and old useless code\n- [NEW] Update and clean README.md\n- [NEW] Update CI add go1.11.x version\n- [NEW] Update scroll godoc and clearer parameter name\n- [NEW] Update hint and code style\n- [NEW] Update FindIds doc and only set name once in loop\n\n### Fix\n\n- [FIX] Update type_string fixed #155, fixed window missing  some character\n- [FIX] Fixed GetWindowText return address of local variable and not use ternary operator ( GetTittle )\n- [FIX] Update README.md Fixed Release badge\n\nSee Commits for more details, after Aug 8.\n\n\n## RobotGo v0.50.0, The Appalachian Mountains\n\n## Add\n\n- [NEW] Add simple ocr support\n- [NEW] Add max and min window api and win32.h file\n- [NEW] Automatic free internal bitmap and add bitmapStr example\n- [NEW] Update findBitmap and findColor default tolerance 0.5 to 0.01, [improve find accuracy and time]\n- [NEW] Add more Window example\n- [NEW] Add cross compile docs\n- [NEW] Add free bitmap and tolerance godoc\n- [NEW] Add GetForegroundWindow and FindWindow func support\n- [NEW] Add bitmap to CBitmap func, Add ToCBitmap example to examples\n- [NEW] Add get Scale and GetScaleSize func, get primary display DPI scale factor fix #129, #135\n   Add Custom DPI Scaling support,\n   Add scale default value,\n   Add scale example\n\n## Update\n\n- [NEW] Update README.md [add freeBitmap example]\n- [NEW] Optimize findColor and uniform API with findBitmap\n- [NEW] Update godoc, CI and README.md\n- [NEW] Update CHANGELOG.md\n- [NEW] Update examples [add freeBitmap and update findColor]\n- [NEW] Optimize bitmap code, optimize args and not try [many methods]\n- [NEW] Update getPid type to int32\n- [NEW] Update var and other code style, fix non-standard code\n   Update code and update some name\n- [NEW] Update pkg to newest\n- [NEW] Remove duplicate code and old useless code\n- [NEW] Update mouse click and fix moveClick and movesClick args\n- [NEW] Update code style use if not try\n- [NEW] Update clipboard example\n- [NEW] Update typestr use return not else\n- [NEW] Update mouse toggle, keytap and savebitmap func args\n- [NEW] Update examples remove duplicate code\n- [NEW] Update bitmap and other examples\n- [NEW] Simplify linux dependency installation commands\n- [NEW] Update issue_template.md\n-[NEW] Update pull_request_template.md\n- [NEW] Move govendor to dep\n- [NEW] Update robotgo ci to 1.10.3\n\n## Fix\n\n- [FIX] Update active pid to fix #140, fixed linux activePid\n- [FIX] Fixed findBitmap and findPic memory leak\n- [FIX] Add getPxColor destroyMMBitmap fix memory leak\n- [FIX] Fix float args not float32\n- [FIX] Fix windows clipboard memory leak\n- [FIX] Update macos .a downgrade to 10.10 just warning not exit [fix #102, #128, #134]\n- [FIX] use 10.10 to compile .a verifyed multi os\n- [FIX] Fix #145 not assert\n- [FIX] Fix some warning use supplemental code\n\nSee Commits for more details, after Apr 30.\n\n\n## RobotGo v0.49.0, Olympus Mons\n\n### Add\n\n- [NEW] Add get image size func\n- [NEW] Add linux type string utf-8 support\n- [NEW] Add scroll mouse support x, y\n- [NEW] Add AddEvent() \"esc\" support fix #105\n- [NEW] Add AddEvent \"space\" fix #110\n- [NEW] Add clipboard choose primary mode on unix\n- [NEW] Add move smooth return\n- [NEW] Add more bitmap func and examples\n- [NEW] Add MicroSleep func\n- [NEW] Add find image by path\n\n\n### Update\n\n- [NEW] Update KeyToggle code\n- [NEW] Update activePid allow Windows via hwnd\n- [NEW] Update godoc and README.md\n- [NEW] Update CHANGELOG.md\n- [NEW] Update Kill() parameter and examples\n- [NEW] Update examples and remove useless function\n- [NEW] Update appveyor, circle and dockerfile\n- [NEW] Update code style\n- [NEW] Update and optimize func\n- [NEW] Update travis support go 1.10\n- [NEW] Update CI (use custom go image) and add func internalFindBitmap\n- [NEW] Update godoc and deprecated GetBHandle\n- [NEW] Optimize code func args and name\n\n\n### Fix\n\n- [FIX] Fix mac input method keytap not work\n- [FIX] Fix clipboard golint\n- [FIX] Update move smooth fix #96 (set mouse smooth speed)\n- [FIX] Fix Getportion param to go type\n- [FIX] Fix XFlush wait for events flushing\n\nSee Commits for more details, after Jan 25.\n\n## RobotGo v0.48.0, Ben Nevis\n\n### Add\n\n- [NEW] Add active window by name func ActiveName\n- [NEW] Add type string utf-8 support\n\nAdd func CharCodeAt, UnicodeType, PasteStr and update TypeStr, TypeString\n\n- [NEW] Add count of bitmap func CountBitmap\n- [NEW] Add func SaveCapture and examples\n- [NEW] Add time sleep func Sleep\n- [NEW] Add more key listen\n- [NEW] Add func PointInBounds and examples\n- [NEW] Add func GetPxColor return C.MMRGBHex\n- [NEW] Add FindColorCS param tolerance\n- [NEW] Add func ToBitmap and examples\n- [NEW] Add CBitmap type and examples\n- [NEW] Add more examples\n- [NEW] Add func ToMMBitmapRef\n- [NEW] Add func BitmapClick and MovesClick\n- [NEW] Add func ToMMRGBHex convert color hex\n- [NEW] Add  func count bitmap color and CountColorCS\n- [NEW] Add more color processing and conversion\n\nAdd func ToMMRGBHex, U32ToHex, U8ToHex, PadHex, HexToRgb, RgbToHex and examples\n\n- [NEW] Add func tochar bitmap and gostring and fmt code\n\n\n### Update\n- [NEW] Remove robot and examples\n- [NEW] Update vendor and appveyor.yml\n- [NEW] Update keyboard code\n- [NEW] Update godoc\n- [NEW] Update CHANGELOG.md\n- [NEW] Change TostringBitmap return string\n- [NEW] Update C language code and other naming\n- [NEW] Update code and code style\n- [NEW] Update move mouse smooth\n\n\n### Fix\n\n- [FIX] Fix mac set active and active by pid\n- [FIX] Fix windows active by pid #101\n- [FIX] Fix FindColor param tolerance\n- [FIX] Fix find bitmap float args\n- [FIX] Fix some range error\n- [FIX] Update doc fix #97\n- [FIX] Update README.md fix link error\n\nSee Commits for more details, after Dec 13.\n\n## RobotGo v0.47.0, Mount Cook\n\n### Add\n\n- [NEW] Add windows 32bit and 64bit dependency\n- [NEW] Add macOs dependency\n- [NEW] Add pkg to vendor\n\nSolve the problem of dependence, remove zlib/libpng dependencies\n\n- [NEW] Add FindColorCS(x, y, w, h int, color CHex), CHex type and examples #84\n- [NEW] Add kill the process\n- [NEW] Add public event and update code\n- [NEW] Add  Windows 32bit and 64bit Appveyor CI\n\n\n### Update\n- [NEW] Update png io\n- [NEW] Update cgo link\n- [NEW] Update .gitignore\n- [NEW] Update README.md and godoc\n- [NEW] Update CHANGELOG.md\n- [NEW] Update circle to 2.0, add robotgo Dockerfile custom image\n- [NEW] Update and fmt C code\n- [NEW] Update GetTitle default value \"null\" to \"\"\n\n\n### Fix\n\n- [FIX] Fix FindColor inconvenient parameters\n- [FIX] Fix installation requirements #72\n- [FIX] Fix GetTitle `return address of local variable` in the higher gcc version. #81\n\nSee Commits for more details, after Nov 10.\n\n\n## RobotGo v0.46.6, Pyrenees Mountains: Aneto Peak\n\n## RobotGo v0.46.0, Pyrenees Mountains\n\n### Add\n\n- [NEW] Add ActivePID\n- [NEW] Add FindBit\n- [NEW] Add robot branch, where there is no zlib and libpng dependency\n\n### Update\n\n- [NEW] Update README.md\n- [NEW] Update FindIds\n- [NEW] Update examples\n- [NEW] Update vendor\n- [NEW] Update godoc and docs\n- [NEW] Update and fix bitmap\n\n### Fix\n\n- [FIX] Fix MoveMouseSmooth args\n- [FIX] Fix name err\n- [FIX] Fix FindBitmap\n\n## RobotGo v0.45.0, Mount Qomolangma\n\n### Add\n- [NEW] Add Process\n- [NEW] Add TypeStr\n- [NEW] Add DeepCopyBit\n- [NEW] Add CopyBitpb\n- [NEW] Add ReadBitmap\n- [NEW] Add vendor.json\n- [NEW] Add ReadAll: clipboard\n- [NEW] Add WriteAll: clipboard\n- [NEW] Add Pids : get the all process id\n- [NEW] Add FindName: find the process name by the process id\n- [NEW] Add FindNames: find the all process name\n- [NEW] Add PidExists: determine whether the process exists\n- [NEW] Add FindIds: find the process id by the process name\n- [NEW] Add FreeBitmap and Update docs\n\n\n### Update\n- [NEW] Update docs\n- [NEW] Update test\n- [NEW] Update godoc\n- [NEW] Update CHANGELOG.md\n- [NEW] Update .gitignore\n- [NEW] Update examples and docs\n- [NEW] Update examples link\n- [NEW] Update README.md and clipboard\n\n\n### Fix\n\n- [FIX] Fix release key\n- [FIX] Fix godoc error\n\n\n## RobotGo v0.44.0, Mount Kailash\n\n### Add\n\n- Add CHANGELOG.md\n- Format some code\n- Add fedora dependencies\n\n### Update\n\n- Update test\n- Update keys.md\n- Update and Split example\n- Update godoc and docs\n- Update and Cleanup README.md\n- Update CONTRIBUTING.md and issue_template.md\n\n### Fix\n\n- Fix typesetting and MD error\n- Fix fedora dependencies #55\n- Fix doc.md and README.md\n\n"
  },
  {
    "path": "docs/README.md",
    "content": "# Docs\n\nDocuments are not necessarily updated synchronously, slower than godoc, please see examples and godoc."
  },
  {
    "path": "docs/archive/README_zh.md",
    "content": "# Robotgo\n\n# !!! Warning: this page not updated !!!\n\n[![Build Status](https://github.com/go-vgo/robotgo/workflows/Go/badge.svg)](https://github.com/go-vgo/robotgo/commits/master)\n[![CircleCI Status](https://circleci.com/gh/go-vgo/robotgo.svg?style=shield)](https://circleci.com/gh/go-vgo/robotgo)\n[![Build Status](https://travis-ci.org/go-vgo/robotgo.svg)](https://travis-ci.org/go-vgo/robotgo)\n![Appveyor](https://ci.appveyor.com/api/projects/status/github/go-vgo/robotgo?branch=master&svg=true)\n[![Go Report Card](https://goreportcard.com/badge/github.com/go-vgo/robotgo)](https://goreportcard.com/report/github.com/go-vgo/robotgo)\n[![GoDoc](https://godoc.org/github.com/go-vgo/robotgo?status.svg)](https://godoc.org/github.com/go-vgo/robotgo)\n[![GitHub release](https://img.shields.io/github/release/go-vgo/robotgo.svg)](https://github.com/go-vgo/robotgo/releases/latest)\n[![Join the chat at https://gitter.im/go-vgo/robotgo](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/go-vgo/robotgo?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)\n\n> Golang 跨平台自动化系统，控制键盘、鼠标、位图、图像、读取屏幕，进程、窗口句柄以及全局事件监听\n\nRobotGo 支持 Mac, Windows, and Linux(X11).\n\n<br>\n\n提 Issues 请到 [Github](https://github.com/go-vgo/robotgo), 便于统一管理和即时更新; `REDAME_zh.md 已废弃, 不再更新`\n\n## Contents\n\n- [Docs](#docs)\n- [Binding](#binding)\n- [Requirements](#requirements)\n- [Installation](#installation)\n- [Update](#update)\n- [Examples](#examples)\n- [Cross-Compiling](#crosscompiling)\n- [Authors](#authors)\n- [Plans](#plans)\n- [Donate](#donate)\n- [Contributors](#contributors)\n- [License](#license)\n\n## Docs\n\n- [GoDoc](https://godoc.org/github.com/go-vgo/robotgo) <br>\n\n<!-- - [中文文档](https://github.com/go-vgo/robotgo/blob/master/docs/doc_zh.md) (弃用)\n- [English Docs](https://github.com/go-vgo/robotgo/blob/master/docs/doc.md) (弃用) -->\n\n## Binding:\n\n[Robotn](https://github.com/vcaesar/robotn), binding JavaScript and other, support more language.\n\n## Requirements:\n\n环境要求:\n\n在安装 RobotGo 之前, 请确保 `Golang、GCC` 被正确安装\n\n### ALL:\n\n```\nGolang\n\nGCC\n```\n\n#### For Mac OS X:\n\nXcode Command Line Tools (And Privacy setting: [#277](https://github.com/go-vgo/robotgo/issues/277) )\n\n```\nxcode-select --install\n```\n\n#### For Windows:\n\n[MinGW-w64](https://sourceforge.net/projects/mingw-w64/files) (推荐使用)\n\n```\nOr the other GCC (But you should compile the \"libpng\" with yourself.\nOr you can removed the bitmap.go.)\n```\n\n#### For everything else (Linux 等其他系统):\n\n```\nGCC,\nlibpng(bitmap)\n\nX11 with the XTest extension (also known as the Xtst library)\n\n事件:\n\nxcb, xkb, libxkbcommon\n\nClipboard:\n\nxsel xclip\n```\n\n##### Ubuntu:\n\n```yml\nsudo apt install gcc libc6-dev\n\nsudo apt install libx11-dev xorg-dev libxtst-dev libpng++-dev\n\nsudo apt install xcb libxcb-xkb-dev x11-xkb-utils libx11-xcb-dev libxkbcommon-x11-dev libxkbcommon-dev\n\nsudo apt install xsel xclip\n```\n\n##### Fedora:\n\n```yml\nsudo dnf install libXtst-devel libxkbcommon-devel libxkbcommon-x11-devel xorg-x11-xkb-utils-devel\n\nsudo dnf install libpng-devel\n\nsudo dnf install xsel xclip\n```\n\n## Installation:\n\nWith Go module support (Go 1.11+), just import:\n\n```go\nimport \"github.com/go-vgo/robotgo\"\n```\n\nOtherwise, to install the robotgo package, run the command:\n\n```\ngo get github.com/go-vgo/robotgo\n```\n\npng.h: No such file or directory? Please see [issues/47](https://github.com/go-vgo/robotgo/issues/47).\n\n## Update:\n\n```\ngo get -u github.com/go-vgo/robotgo\n```\n\n注意 go1.10.x C 文件编译缓存问题, [golang #24355](https://github.com/golang/go/issues/24355).\n`go mod vendor` problem, [golang #26366](https://github.com/golang/go/issues/26366).\n\n## [Examples:](https://github.com/go-vgo/robotgo/blob/master/examples)\n\n#### [鼠标](https://github.com/go-vgo/robotgo/blob/master/examples/mouse/main.go)\n\n```Go\npackage main\n\nimport (\n\t\"github.com/go-vgo/robotgo\"\n)\n\nfunc main() {\n  // robotgo.ScrollMouse(10, \"up\")\n  robotgo.Scroll(0, -10)\n  robotgo.Scroll(100, 0)\n  robotgo.MilliSleep(100)\n  // robotgo.ScrollRelative(10, -100)\n  robotgo.ScrollSmooth(-10, 6)\n\n  robotgo.MouseSleep = 100\n  robotgo.Move(10, 20)\n  robotgo.MoveRelative(0, -10)\n  robotgo.Drag(10, 10)\n\n  robotgo.Click(\"left\", true)\n  robotgo.MoveSmooth(100, 200, 1.0, 10.0)\n\n  robotgo.Toggle(\"left\")\n  robotgo.Toggle(\"left\", \"up\")\n}\n```\n\n#### [键盘](https://github.com/go-vgo/robotgo/blob/master/examples/key/main.go)\n\n```Go\npackage main\n\nimport (\n  \"fmt\"\n\n  \"github.com/go-vgo/robotgo\"\n)\n\nfunc main() {\n  robotgo.TypeStr(\"Hello World. Winter is coming!\")\n  robotgo.TypeStr(\"だんしゃり\", 1.0)\n  // robotgo.TypeStr(\"テストする\")\n\n  robotgo.TypeStr(\"Hi galaxy. こんにちは世界.\")\n  robotgo.Sleep(1)\n\n  // ustr := uint32(robotgo.CharCodeAt(\"テストする\", 0))\n  // robotgo.UnicodeType(ustr)\n\n  robotgo.KeySleep = 100\n  robotgo.KeyTap(\"enter\")\n  // robotgo.TypeStr(\"en\")\n  robotgo.KeyTap(\"i\", \"alt\", \"command\")\n\n  arr := []string{\"alt\", \"command\"}\n  robotgo.KeyTap(\"i\", arr)\n\n  robotgo.MilliSleep(100)\n  robotgo.KeyToggle(\"a\")\n  robotgo.KeyToggle(\"a\", \"up\")\n\n  robotgo.WriteAll(\"テストする\")\n  text, err := robotgo.ReadAll()\n  if err == nil {\n    fmt.Println(text)\n  }\n}\n```\n\n#### [屏幕](https://github.com/go-vgo/robotgo/blob/master/examples/screen/main.go)\n\n```Go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/go-vgo/robotgo\"\n  \"github.com/vcaesar/imgo\"\n)\n\nfunc main() {\n  x, y := robotgo.GetMousePos()\n  fmt.Println(\"pos: \", x, y)\n\n  color := robotgo.GetPixelColor(100, 200)\n  fmt.Println(\"color----\", color)\n\n  sx, sy := robotgo.GetScreenSize()\n  fmt.Println(\"get screen size: \", sx, sy)\n\n  bit := robotgo.CaptureScreen(10, 10, 30, 30)\n  defer robotgo.FreeBitmap(bit)\n  robotgo.SaveBitmap(bit, \"test_1.png\")\n\n  img := robotgo.ToImage(bit)\n  imgo.Save(\"test.png\", img)\n}\n```\n\n#### [位图](https://github.com/go-vgo/robotgo/blob/master/examples/bitmap/main.go)\n\n```Go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/go-vgo/robotgo\"\n)\n\nfunc main() {\n  bitmap := robotgo.CaptureScreen(10, 20, 30, 40)\n  // use `defer robotgo.FreeBitmap(bit)` to free the bitmap\n  defer robotgo.FreeBitmap(bitmap)\n\n  fmt.Println(\"bitmap...\", bitmap)\n  img := robotgo.ToImage(bitmap)\n  robotgo.SavePng(img, \"test_1.png\")\n\n  bit2 := robotgo.ToCBitmap(robotgo.ImgToBitmap(img))\n  fx, fy := robotgo.FindBitmap(bit2)\n  fmt.Println(\"FindBitmap------ \", fx, fy)\n  robotgo.Move(fx, fy)\n\n  arr := robotgo.FindAllBitmap(bit2)\n  fmt.Println(\"Find all bitmap: \", arr)\n  robotgo.SaveBitmap(bitmap, \"test.png\")\n\n  fx, fy = robotgo.FindBitmap(bitmap)\n  fmt.Println(\"FindBitmap------\", fx, fy)\n\n  robotgo.SaveBitmap(bitmap, \"test.png\")\n}\n```\n\n#### [OpenCV](https://github.com/vcaesar/gcv)\n\n```Go\npackage main\n\nimport (\n  \"fmt\"\n  \"math/rand\"\n\n  \"github.com/go-vgo/robotgo\"\n  \"github.com/vcaesar/gcv\"\n)\n\nfunc main() {\n  opencv()\n}\n\nfunc opencv() {\n  name := \"test.png\"\n  name1 := \"test_001.png\"\n  robotgo.SaveCapture(name1, 10, 10, 30, 30)\n  robotgo.SaveCapture(name)\n\n  fmt.Print(\"gcv find image: \")\n  fmt.Println(gcv.FindImgFile(name1, name))\n  fmt.Println(gcv.FindAllImgFile(name1, name))\n\n  bit := robotgo.OpenBitmap(name1)\n  defer robotgo.FindBitmap(bit)\n  fmt.Print(\"find bitmap: \")\n  fmt.Println(robotgo.FindBitmap(bit))\n\n  // bit0 := robotgo.CaptureScreen()\n  // img := robotgo.ToImage(bit0)\n  // bit1 := robotgo.CaptureScreen(10, 10, 30, 30)\n  // img1 := robotgo.ToImage(bit1)\n  // defer robotgo.FreeBitmapArr(bit0, bit1)\n  img := robotgo.CaptureImg()\n  img1 := robotgo.CaptureImg(10, 10, 30, 30)\n\n  fmt.Print(\"gcv find image: \")\n  fmt.Println(gcv.FindImg(img1, img))\n  fmt.Println()\n\n  res := gcv.FindAllImg(img1, img)\n  fmt.Println(res[0].TopLeft.Y, res[0].Rects.TopLeft.X, res)\n  x, y := res[0].TopLeft.X, res[0].TopLeft.Y\n  robotgo.Move(x, y-rand.Intn(5))\n  robotgo.MilliSleep(100)\n  robotgo.Click()\n\n  res = gcv.FindAll(img1, img) // use find template and sift\n  fmt.Println(\"find all: \", res)\n  res1 := gcv.Find(img1, img)\n  fmt.Println(\"find: \", res1)\n\n  img2, _, _ := robotgo.DecodeImg(\"test_001.png\")\n  x, y = gcv.FindX(img2, img)\n  fmt.Println(x, y)\n}\n```\n\n#### [事件](https://github.com/go-vgo/robotgo/blob/master/examples/gohook/main.go)\n\n```Go\npackage main\n\nimport (\n  \"fmt\"\n\n  \"github.com/go-vgo/robotgo\"\n  hook \"github.com/robotn/gohook\"\n)\n\nfunc main() {\n  add()\n  low()\n  event()\n}\n\nfunc add() {\n  fmt.Println(\"--- Please press ctrl + shift + q to stop hook ---\")\n  robotgo.EventHook(hook.KeyDown, []string{\"q\", \"ctrl\", \"shift\"}, func(e hook.Event) {\n    fmt.Println(\"ctrl-shift-q\")\n    robotgo.EventEnd()\n  })\n\n  fmt.Println(\"--- Please press w---\")\n  robotgo.EventHook(hook.KeyDown, []string{\"w\"}, func(e hook.Event) {\n    fmt.Println(\"w\")\n  })\n\n  s := robotgo.EventStart()\n  <-robotgo.EventProcess(s)\n}\n\nfunc low() {\n\tevChan := hook.Start()\n\tdefer hook.End()\n\n\tfor ev := range evChan {\n\t\tfmt.Println(\"hook: \", ev)\n\t}\n}\n\nfunc event() {\n  ok := robotgo.AddEvents(\"q\", \"ctrl\", \"shift\")\n  if ok {\n    fmt.Println(\"add events...\")\n  }\n\n  keve := robotgo.AddEvent(\"k\")\n  if keve {\n    fmt.Println(\"you press... \", \"k\")\n  }\n\n  mleft := robotgo.AddEvent(\"mleft\")\n  if mleft {\n    fmt.Println(\"you press... \", \"mouse left button\")\n  }\n}\n```\n\n#### [窗口句柄](https://github.com/go-vgo/robotgo/blob/master/examples/window/main.go)\n\n```Go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/go-vgo/robotgo\"\n)\n\nfunc main() {\n  fpid, err := robotgo.FindIds(\"Google\")\n  if err == nil {\n    fmt.Println(\"pids...\", fpid)\n\n    if len(fpid) > 0 {\n      robotgo.ActivePID(fpid[0])\n\n      robotgo.Kill(fpid[0])\n    }\n  }\n\n  robotgo.ActiveName(\"chrome\")\n\n  isExist, err := robotgo.PidExists(100)\n  if err == nil && isExist {\n    fmt.Println(\"pid exists is\", isExist)\n\n    robotgo.Kill(100)\n  }\n\n  abool := robotgo.Alert(\"test\", \"robotgo\")\n  if abool {\n    fmt.Println(\"ok@@@ \", \"ok\")\n  }\n\n  title := robotgo.GetTitle()\n  fmt.Println(\"title@@@ \", title)\n}\n```\n\n## CrossCompiling\n\n##### Windows64 to windows32\n\n```Go\nSET CGO_ENABLED=1\nSET GOARCH=386\ngo build main.go\n```\n\n#### Other to windows\n\nInstall Requirements (Ubuntu):\n\n```bash\nsudo apt install gcc-multilib\nsudo apt install gcc-mingw-w64\nsudo apt install libz-mingw-w64-dev\n```\n\nBuild the binary:\n\n```Go\nGOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ go build -x ./\n```\n\n```\n// CC=mingw-w64\\x86_64-7.2.0-win32-seh-rt_v5-rev1\\mingw64\\bin\\gcc.exe\n// CXX=mingw-w64\\x86_64-7.2.0-win32-seh-rt_v5-rev1\\mingw64\\bin\\g++.exe\n```\n\n## Authors\n\n- [The author is vz](https://github.com/vcaesar)\n- [Maintainers](https://github.com/orgs/go-vgo/people)\n- [Contributors](https://github.com/go-vgo/robotgo/graphs/contributors)\n\n## Plans\n\n- 更新 Find an image on screen, read pixels from an image\n- 更新 Window Handle\n- 尝试支持 Android, 也许支持 IOS\n\n## Contributors\n\n- See [contributors page](https://github.com/go-vgo/robotgo/graphs/contributors) for full list of contributors.\n- See [Contribution Guidelines](https://github.com/go-vgo/robotgo/blob/master/CONTRIBUTING.md).\n\n## License\n\nRobotgo is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0), with portions covered by various BSD-like licenses.\n\nSee [LICENSE-APACHE](http://www.apache.org/licenses/LICENSE-2.0), [LICENSE-MIT](https://github.com/go-vgo/robotgo/blob/master/LICENSE).\n"
  },
  {
    "path": "docs/archive/doc.md",
    "content": "# Methods:\n\n##### [GetVersion](#GetVersion)\n\n## [Keyboard](#Keyboard)\n\n##### [Keys](https://github.com/go-vgo/robotgo/blob/master/docs/keys.md)\n<!-- ##### [SetKeyboardDelay](#SetKeyDelay) (Equivalent to SetKeyDelay, Wno-deprecated) -->\n##### [SetKeyDelay](#SetKeyDelay)\n##### [KeyTap](#KeyTap)\n##### [KeyToggle](#KeyToggle)\n<!-- ##### [TypeString](#TypeString)\n##### [TypeStringDelayed](#TypeStrDelay) (Equivalent to TypeStrDelay, Wno-deprecated) -->\n##### [TypeStr](#TypeStr)\n##### [TypeStrDelay](#TypeStrDelay)\n##### [WriteAll](#WriteAll)\n##### [ReadAll](#ReadAll)\n\n\n## [Mouse](#Mouse)\n\n##### [SetMouseDelay](#SetMouseDelay)\n##### [MoveMouse](#MoveMouse)\n##### [Move](#MoveMouse) (Equivalent to MoveMouse)\n##### [MoveMouseSmooth](#MoveMouseSmooth)\n##### [MoveSmooth](#MoveMouseSmooth) (Equivalent to MoveMouseSmooth)\n##### [MouseClick](#MouseClick)\n##### [Click](#MouseClick) (Equivalent to MouseClick)\n##### [MoveClick](#MoveClick)\n##### [MouseToggle](#MouseToggle)\n##### [DragMouse](#DragMouse)\n##### [Drag](#DragMouse) (Equivalent to DragMouse)\n##### [GetMousePos](#GetMousePos)\n##### [ScrollMouse](#ScrollMouse)\n\n## [Screen](#Screen)\n\n##### [GetPixelColor](#GetPixelColor)\n##### [GetScreenSize](#GetScreenSize)\n##### [CaptureScreen](#CaptureScreen)\n##### [GetXDisplayName(Linux)](#GetXDisplayName)\n##### [SetXDisplayName(Linux)](#SetXDisplayName)\n\n## [Bitmap](#Bitmap)\n    This is a work in progress.\n\n##### [FindBitmap](#FindBitmap)\n##### [OpenBitmap](#OpenBitmap)\n##### [SaveBitmap](#SaveBitmap)\n##### [TostringBitmap](#TostringBitmap)\n##### [GetPortion](#GetPortion)\n##### [Convert](#Convert)\n#### [FreeBitmap](#FreeBitmap)\n#### [ReadBitmap](#ReadBitmap)\n#### [CopyBitpb](#CopyBitpb)\n#### [DeepCopyBit](#DeepCopyBit)\n\n## [Event](#Event)\n\n<!-- ##### [LEvent](#LEvent) (Equivalent to AddEvent, Wno-deprecated) -->\n##### [AddEvent](#AddEvent)\n##### [StopEvent](#StopEvent)\n\n## [Window](#Window)\n    This is a work in progress.\n\n##### [ShowAlert](#ShowAlert)\n##### [CloseWindow](#CloseWindow)\n##### [IsValid](#IsValid)\n##### [SetActive](#SetActive)\n##### [GetActive](#GetActive)\n##### [SetHandle](#SetHandle)\n##### [GetHandle](#GetHandle)\n<!-- ##### [GetBHandle](#GetHandle) -->\n##### [GetTitle](#GetTitle)\n##### [GetPID](#GetPID)\n##### [Pids](#Pids)\n##### [PidExists](#PidExists)\n##### [Process](#Process)\n##### [FindName](#FindName)\n##### [FindNames](#FindNames)\n##### [FindIds](#FindIds)\n#### [ActivePID](#ActivePID)\n\n### <h3 id=\"GetVersion\">.GetVersion()</h3>\n    Get robotgo version\n\n## <h2 id=\"Keyboard\">Keyboard</h2>\n\n### <h3 id=\"SetKeyDelay\">.SetKeyDelay(ms)</h3>\n\n    Sets the delay in milliseconds to sleep after a keyboard event. This is 10ms by default.\n\n#### Arguments:\n\n    ms - Time to sleep in milliseconds.\n\n### <h3 id=\"KeyTap\">.KeyTap(key, modifier)</h3>\n\n    Press a single key.\n\n#### Arguments:\n\nkey - See [keys](https://github.com/go-vgo/robotgo/blob/master/docs/keys.md).  \nmodifier (optional, string or array) - Accepts alt, command (win), control, and shift.\n\n#### Examples:\n\n```Go\nrobotgo.KeyTap(\"h\", \"command\")\nrobotgo.KeyTap(\"i\", \"alt\", \"command\")\narr := []string{\"alt\", \"command\"}\nrobotgo.KeyTap(\"i\", arr)\n```\n\n### <h3 id=\"KeyToggle\">.KeyToggle(key, down, modifier)</h3>\n\n    Hold down or release a key.\n\n#### Arguments:\n\nkey - See [keys](https://github.com/go-vgo/robotgo/blob/master/docs/keys.md).  \ndown - Accepts 'down' or 'up'.  \nmodifier (optional, string or array) - Accepts alt, command (mac), control, and shift.\n\n#### Return:\n    return KeyToggle status\n\n<!-- ### <h3 id=\"TypeString\">.TypeString(string)</h3>\n\n#### Arguments:\n\n    string - The string to send. -->\n\n### <h3 id=\"TypeStr\">.TypeStr(string)</h3>\n\n#### Arguments:\n\n    string - The string to send.\n\n### <h3 id=\"TypeStrDelay\">.TypeStrDelay(string, cpm)</h3>\n\n#### Arguments:\n\n    string - The string to send.\n    cpm - Characters per minute.\n\n### <h3 id=\"WriteAll\">.WriteAll(text string)</h3>\n\n#### Arguments:\n    text string\n#### Return:      \n\n### <h3 id=\"ReadAll\">.ReadAll()</h3>\n\n#### Arguments:\n\n#### Return: \n    text,\n    error \n\n\n## <h2 id=\"Mouse\">Mouse</h2>\n\n### <h3 id=\"SetMouseDelay\">.SetMouseDelay(ms)</h3>\n\n    Sets the delay in milliseconds to sleep after a mouse event. This is 10ms by default.\n\n#### Arguments:\n\n    ms - Time to sleep in milliseconds.\n\n### <h3 id=\"MoveMouse\">.MoveMouse(x, y)</h3>\n\n    Moves mouse to x, y instantly, with the mouse button up.\n\n#### Arguments:\n\n    x, y\n\n#### Examples:\n\n```Go\n// Move the mouse to 100, 100 on the screen. \nrobotgo.MoveMouse(100, 100)\n```\n\n### <h3 id=\"MoveMouseSmooth\">.MoveMouseSmooth(x, y)</h3>\n\n    Moves mouse to x, y human like, with the mouse button up.\n\n#### Arguments:\n\n    x, y\n    lowspeed, highspeed\n\n#### Examples:\n\n```Go\nrobotgo.MoveMouseSmooth(100, 200)\nrobotgo.MoveMouseSmooth(100, 200, 1.0, 100.0)\n```    \n\n### <h3 id=\"MouseClick\">.MouseClick(button, double)</h3>\n\n    Clicks the mouse.\n\n#### Arguments:\n\n    button (optional) - Accepts \"left\", \"right\", or \"center\". Defaults to left.\n    double (optional) - Set to true to perform a double click. Defaults to false.\n\n#### Examples:\n\n```Go\nrobotgo.MouseClick()\nrobotgo.MouseClick(\"left\", true)\n```\n\n### <h3 id=\"MoveClick\">.MoveClick(x, y, button, double)</h3>\n\n    Move and click the mouse.\n\n#### Arguments:\n    x,\n    y,\n\n    button (optional) - Accepts \"left\", \"right\", or \"center\". Defaults to left.\n    double (optional) - Set to true to perform a double click. Defaults to false.\n\n#### Examples:\n\n```Go\nrobotgo.MoveClick(10, 20)\nrobotgo.MoveClick(10, 20, \"left\", true)\n```\n\n### <h3 id=\"MouseToggle\">.MouseToggle(down, button)</h3>\n\n    Toggles mouse button.\n\n#### Arguments:\n\n    down (optional) - Accepts down or up. Defaults to down.\n    button (optional) - Accepts \"left\", \"right\", or \"center\". Defaults to left.\n\n#### Examples:\n\n```Go\nrobotgo.MouseToggle(\"down\")\nrobotgo.MouseToggle(\"down\", \"right\")\n```\n\n### <h3 id=\"DragMouse\">.DragMouse(x, y)</h3>\n\n    Moves mouse to x, y instantly, with the mouse button held down.\n\n#### Arguments:\n\n    x, y\n\n#### Examples:\n\n```Go\n// Mouse down at 0, 0 and then drag to 100, 100 and release. \nrobotgo.MoveMouse(0, 0)\nrobotgo.MouseToggle(\"down\")\nrobotgo.DragMouse(100, 100)\nrobotgo.MouseToggle(\"up\")\n```\n\n### <h3 id=\"GetMousePos\">.GetMousePos()</h3>\n\n    Gets the mouse coordinates.\n\n#### Return:\n\n    Returns an object with keys x and y.\n\n#### Examples:\n\n```Go\nx,y := robotgo.GetMousePos()\nfmt.Println(\"pos:\", x, y)\n```\n\n### <h3 id=\"ScrollMouse\">.ScrollMouse(magnitude, direction)</h3>\n\n    Scrolls the mouse either up or down.\n\n#### Arguments:\n\n    magnitude - The amount to scroll.\n    direction - Accepts down or up.\n\n#### Examples:\n\n```Go\nrobotgo.ScrollMouse(50, \"up\")\n\nrobotgo.ScrollMouse(50, \"down\")\n```\n\n\n## <h2 id=\"Screen\">Screen</h2>\n\n### <h3 id=\"GetPixelColor\">.GetPixelColor(x, y)\n\n    Gets the pixel color at x, y. This function is perfect for getting a pixel or two, \n    but if you'll be reading large portions of the screen use screen.capture.\n\n#### Arguments:\n\n    x, y\n\n#### Return:\n\n    Returns the hex color code of the pixel at x, y.\n\n### <h3 id=\"GetScreenSize\">.GetScreenSize()</h3>\n\n    Gets the screen width and height.\n\n#### Return:\n\n    Returns an object with .width and .height.\n\n### <h3 id=\"CaptureScreen\">.CaptureScreen</h3>\n    // CaptureScreen\n\n    Gets part or all of the screen.\n\n    GoCaptureScreen Returns a go struct\n<!-- Capture_Screen (Drop support) -->\n\n#### Arguments:\n\n    x (optional)\n    y (optional)\n    height (optional)\n    width (optional)\n    If no arguments are provided, capturescreen(screencapture) will get the full screen.\n\n#### Return:\n\n    Returns a bitmap object.\n\n## <h2 id=\"Bitmap\">Bitmap</h2>\n\n    This is a work in progress.\n\n### <h3 id=\"FindBitmap\">.FindBitmap</h3>\n\n    find bitmap.\n\n#### Arguments:\n\n    bitmap;\n    rect(optional): x, y, w, h\n\n#### Return:\n\n    Returns a position x and y\n\n\n### <h3 id=\"OpenBitmap\">.OpenBitmap</h3>\n\n    open bitmap.\n\n#### Arguments:\n\n    bitmap image path,\n    MMImageType (optional) \n\n#### Return:\n\n    Returns a bitmap\n\n### <h3 id=\"SaveBitmap\">.SaveBitmap</h3>\n\n    Save a image with bitmap.\n\n#### Arguments:\n\n    bitmap,\n    path,\n    imagetype (int) \n\n#### Return:\n\n    return save image status\n\n\n### <h3 id=\"TostringBitmap\">.TostringBitmap</h3>\n\n     bitmap to string\n\n#### Arguments:\n\n    bitmap \n\n#### Return:\n\n    Return a sting bitmap\n\n### <h3 id=\"GetPortion\">.GetPortion</h3>\n\n     bitmap from a portion\n\n#### Arguments:\n\n    bitmap,\n    rect: x, y, w, h \n\n#### Return:\n\n    Returns new bitmap object created from a portion of another \n\n### <h3 id=\"Convert\">.Convert(openpath, savepath, MMImageType)</h3>\n\n    Convert the image format\n\n#### Arguments:\n\n    openpath,\n    savepath,\n    MMImageType (optional)\n\n#### Examples:\n\n```Go\nrobotgo.Convert(\"test.png\", \"test.tif\")\n```             \n\n### <h3 id=\"FreeBitmap\">.FreeBitmap(MMBitmapRef)</h3>\n\n    FreeBitmap free and dealloc bitmap\n\n#### Arguments:\n\n    MMBitmapRef\n\n#### Examples:\n\n```Go\nrobotgo.FreeBitmap(bitmap)\n```    \n\n\n### <h3 id=\"ReadBitmap\">.ReadBitmap(MMBitmapRef)</h3>\n\n    ReadBitmap returns false and sets error if |bitmap| is NULL\n\n#### Arguments:\n\n    MMBitmapRef\n\n#### Return:\n\n    bool\n\n#### Examples:\n\n```Go\nrobotgo.ReadBitmap(bitmap)\n```    \n\n\n### <h3 id=\"CopyBitpb\">.CopyBitpb(MMBitmapRef)</h3>\n\n   CopyBitpb copy bitmap to pasteboard\n\n#### Arguments:\n\n    MMBitmapRef\n\n#### Return:\n\n    bool\n\n#### Examples:\n\n```Go\nrobotgo.CopyBitpb(bitmap)\n```    \n\n### <h3 id=\"DeepCopyBit\">.DeepCopyBit(MMBitmapRef)</h3>\n\n   DeepCopyBit deep copy bitmap\n\n#### Arguments:\n\n    MMBitmapRef\n\n#### Return:\n\n    MMBitmapRef\n\n#### Examples:\n\n```Go\nrobotgo.DeepCopyBit(bitmap)\n```  \n\n## <h2 id=\"Event\">Event</h2> \n\n### <h3 id=\"AddEvent\">.AddEvent(string)</h3>\n\n    Listening global event\n\n#### Arguments:\n\n    string\n\n    (mouse arguments: mleft, mright, wheelDown, wheelUp, wheelLeft, wheelRight)\n\n#### Return:\n\n    if listened return 0\n\n#### Examples:\n\n```Go\npackage main\n\nimport (\n    \"fmt\"\n\n    \"github.com/go-vgo/robotgo\"\n)\n\nfunc main() {\n  keve := robotgo.AddEvent(\"k\")\n  if keve {\n    fmt.Println(\"you press...\", \"k\")\n  }\n\n  mleft := robotgo.AddEvent(\"mleft\")\n  if mleft {\n    fmt.Println(\"you press...\", \"mouse left button\")\n  }\n} \n```  \n### <h3 id=\"StopEvent\">.StopEvent()</h3>  \n    stop listen global event\n\n## <h2 id=\"Window\">Window</h2> \n\n### <h3 id=\"ShowAlert\">.ShowAlert(title, msg, defaultButton, cancelButton string)</h3>\n\n    Displays alert with the given attributes. If cancelButton is not given, only the defaultButton is displayed\n\n#### Arguments:\n\n    title (string),\n    msg (string),\n    defaultButton (optional string),\n    cancelButton (optional string)\n           \n\n#### Return:\n\n    Returns 0(True) if the default button was pressed, or 1(False) if cancelled. \n\n### <h3 id=\"CloseWindow\">.CloseWindow()</h3>\n\n    Close the Window\n\n#### Arguments:\n    None     \n\n#### Return:\n    None\n\n### <h3 id=\"IsValid\">.IsValid()</h3>\n\n    Valid the Window\n\n#### Arguments:\n    None     \n\n#### Return:\n    Returns true if a window has been selected\n\n\n### <h3 id=\"SetActive\">.SetActive()</h3>\n\n   Set the Active Window\n\n#### Arguments:\n    hwnd  \n\n#### Return:\n    void\n    \n\n### <h3 id=\"GetActive\">.GetActive()</h3>\n\n    Get the Active Window\n\n#### Arguments:\n    None   \n\n#### Return:\n    Returns hwnd\n\n### <h3 id=\"SetHandle\">.SetHandle()</h3>\n\n    Set the Window Handle\n\n#### Arguments:\n    int \n\n#### Return:\n    bool\n\n### <h3 id=\"GetHandle\">.GetHandle()</h3>\n\n    Get the Window Handle\n\n#### Arguments:\n    None    \n\n#### Return:\n    Returns hwnd  \n\n### <h3 id=\"GetTitle\">.GetTitle()</h3>\n\n    Get the Window Title\n\n#### Arguments:\n    None   \n\n#### Return:\n    Returns Window Title      \n\n### <h3 id=\"GetPID\">.GetPID()</h3>\n\n    Get the process id\n\n#### Arguments:\n    None       \n\n#### Return:\n    Returns the process id         \n     \n### <h3 id=\"Pids\">.Pids()</h3>\n\n    Pids get the all process id\n\n#### Arguments:\n    None   \n\n#### Return:\n    Returns all process id   \n\n### <h3 id=\"PidExists\">.PidExists()</h3>\n\n    PidExists determine whether the process exists\n\n#### Arguments:\n    pid  \n\n#### Return:\n    Returns bool \n\n### <h3 id=\"Process\">.Process()</h3>\n\n  Process get the all process struct\n\n#### Arguments:\n    none  \n\n#### Return:\n    Returns []Nps, error\n\n### <h3 id=\"FindName\">.FindName()</h3>\n\n    FindName find the process name by the process id\n\n#### Arguments:\n    pid  \n\n#### Return:\n    Returns string, error       \n\n### <h3 id=\"FindNames\">.FindNames()</h3>\n\n    FindNames find the all process name\n\n#### Arguments:\n    none  \n\n#### Return:\n    Returns []string, error  \n\n### <h3 id=\"FindIds\">.FindIds()</h3>\n\n    FindIds find the process id by the process name\n\n#### Arguments:\n    name string  \n\n#### Return:\n    Returns []int32, error \n\n\n### <h3 id=\"ActivePID\">.ActivePID()</h3>\n\n    ActivePID window active by PID\n\n#### Arguments:\n    pid int32 \n\n#### Return:\n    none                  "
  },
  {
    "path": "docs/archive/doc_zh.md",
    "content": "# 方法:\n\n##### [GetVersion](#GetVersion)\n\n## [键盘](#Keyboard)\n\n##### [Keys](https://github.com/go-vgo/robotgo/blob/master/docs/keys.md)\n<!-- ##### [SetKeyboardDelay](#SetKeyDelay) (相当于 SetKeyDelay, 废弃 API) -->\n##### [SetKeyDelay](#SetKeyDelay)\n##### [KeyTap](#KeyTap)\n##### [KeyToggle](#KeyToggle)\n<!-- ##### [TypeString](#TypeString)\n##### [TypeStringDelayed](#TypeStrDelay) (相当于 TypeStrDelay, 废弃 API) -->\n##### [TypeStr](#TypeStr)\n##### [TypeStrDelay](#TypeStrDelay)\n##### [WriteAll](#WriteAll)\n##### [ReadAll](#ReadAll)\n\n## [鼠标](#Mouse)\n\n##### [SetMouseDelay](#SetMouseDelay)\n##### [MoveMouse](#MoveMouse)\n##### [Move](#MoveMouse) (相当于 MoveMouse)\n##### [MoveMouseSmooth](#MoveMouseSmooth)\n##### [MoveSmooth](#MoveMouseSmooth) (相当与 MoveMouseSmooth)\n##### [MouseClick](#MouseClick)\n##### [Click](#MouseClick) (相当于 MouseClick)\n##### [MoveClick](#MoveClick)\n##### [MouseToggle](#MouseToggle)\n##### [DragMouse](#DragMouse)\n##### [Drag](#DragMouse) (相当于 DragMouse)\n##### [GetMousePos](#GetMousePos)\n##### [ScrollMouse](#ScrollMouse)\n\n### <h3 id=\"GetVersion\">.GetVersion()</h3>\n    获取 robotgo 版本\n\n## [屏幕](#Screen)\n\n##### [GetPixelColor](#GetPixelColor)\n##### [GetScreenSize](#GetScreenSize)\n##### [CaptureScreen](#CaptureScreen)\n##### [GetXDisplayName(Linux)](#GetXDisplayName)\n##### [SetXDisplayName(Linux)](#SetXDisplayName)\n\n## [位图](#Bitmap)\n    This is a work in progress. (工作正在进行中)\n\n##### [FindBitmap](#FindBitmap)\n##### [OpenBitmap](#OpenBitmap)\n##### [SaveBitmap](#SaveBitmap)\n##### [TostringBitmap](#TostringBitmap)\n##### [GetPortion](#GetPortion)\n##### [Convert](#Convert)\n#### [FreeBitmap](#FreeBitmap)\n#### [ReadBitmap](#ReadBitmap)\n#### [CopyBitpb](#CopyBitpb)\n#### [DeepCopyBit](#DeepCopyBit)\n\n## [事件](#Event)\n\n<!-- ##### [LEvent](#AddEvent) (相当于 AddEvent, 废弃 API) -->\n##### [AddEvent](#AddEvent)\n##### [StopEvent](#StopEvent)\n\n## [窗口](#Window)\n    This is a work in progress.\n\n##### [ShowAlert](#ShowAlert)\n##### [CloseWindow](#CloseWindow)\n##### [IsValid](#IsValid)\n##### [SetActive](#SetActive)\n##### [GetActive](#GetActive)\n##### [SetHandle](#SetHandle)\n##### [GetHandle](#GetHandle)\n<!-- ##### [GetBHandle](#GetHandle) -->\n##### [GetTitle](#GetTitle)\n##### [GetPID](#GetPID)\n##### [Pids](#Pids)\n##### [PidExists](#PidExists)\n##### [Process](#Process)\n##### [FindName](#FindName)\n##### [FindNames](#FindNames)\n##### [FindIds](#FindIds)\n#### [ActivePID](#ActivePID)\n\n\n## <h2 id=\"Keyboard\">键盘</h2>\n\n### <h3 id=\"SetKeyDelay\">.SetKeyDelay(ms)</h3>\n    设置键盘延迟 (在键盘一个事件后), 单位 ms, 默认值 10ms\n\n    Sets the delay in milliseconds to sleep after a keyboard event. This is 10ms by default.\n\n#### 参数:\n    延迟时间,单位 ms\n\n    ms - Time to sleep in milliseconds.\n\n### <h3 id=\"KeyTap\">.KeyTap(key, modifier)</h3>\n    模拟键盘按键\n\n    Press a single key.\n\n#### 参数:\n    键盘值\n    修饰值 (可选类型, 字符串或者数组) - 可选值: alt, command (win), control, and shift.\n\nkey - See [keys](https://github.com/go-vgo/robotgo/blob/master/docs/keys.md).  \nmodifier (optional, string or array) - Accepts alt, command (win), control, and shift.\n#### 示例:\n\n```Go\nrobotgo.KeyTap(\"h\", \"command\")\nrobotgo.KeyTap(\"i\", \"alt\", \"command\")\narr := []string{\"alt\", \"command\"}\nrobotgo.KeyTap(\"i\", arr)\n```\n\n### <h3 id=\"KeyToggle\">.KeyToggle(key, down, modifier)</h3>\n    键盘切换, 按住或释放一个键位\n\n    Hold down or release a key.\n\n#### 参数:\n\nkey - See [keys](https://github.com/go-vgo/robotgo/blob/master/docs/keys.md).  \ndown - Accepts 'down' or 'up'.  \nmodifier (optional, string or array) - Accepts alt, command (mac), control, and shift.\n### 返回值:\n\n    返回 KeyToggle 状态\n\n<!-- ### <h3 id=\"TypeString\">.TypeString(string)</h3>\n\n#### 参数:\n\n    string - The string to send. -->\n\n### <h3 id=\"TypeStr\">.TypeStr(string)</h3>\n\n#### 参数:\n\n    string - The string to send.\n\n\n### <h3 id=\"TypeStrDelay\">.TypeStrDelay(string, cpm)</h3>\n\n#### 参数:\n\n    string - The string to send.\n    cpm - Characters per minute.\n\n### <h3 id=\"WriteAll\">.WriteAll(text string)</h3>\n\n#### 参数:\n    text string\n#### 返回值:      \n\n### <h3 id=\"ReadAll\">.ReadAll()</h3>\n\n#### 参数:\n\n#### 返回值: \n    text,\n    error \n\n## <h2 id=\"Mouse\">鼠标</h2>\n### <h3 id=\"SetMouseDelay\">.SetMouseDelay(ms)</h3>\n    设置鼠标延迟 (在一个鼠标事件后), 单位 ms, 默认值 10 ms\n\n    Sets the delay in milliseconds to sleep after a mouse event. This is 10ms by default.\n\n#### 参数:\n\n    ms - Time to sleep in milliseconds.\n\n### <h3 id=\"MoveMouse\">.MoveMouse(x, y)</h3>\n    移动鼠标\n\n    Moves mouse to x, y instantly, with the mouse button up.\n\n#### 参数:\n\n    x, y\n\n#### 示例:\n\n```Go\n// Move the mouse to 100, 100 on the screen. \nrobotgo.MoveMouse(100, 100)\n```\n\n### <h3 id=\"MoveMouseSmooth\">.MoveMouseSmooth(x, y)</h3>\n    模拟鼠标向 X，Y 平滑移动(像人类一样)，用鼠标按钮向上\n\n    Moves mouse to x, y human like, with the mouse button up.\n\n#### 参数:\n\n    x, y\n    lowspeed, highspeed\n\n#### 示例:\n\n```Go\nrobotgo.MoveMouseSmooth(100, 200)\nrobotgo.MoveMouseSmooth(100, 200, 1.0, 100.0)\n```       \n\n### <h3 id=\"MouseClick\">.MouseClick(button, double)</h3>\n    鼠标点击\n\n    Clicks the mouse.\n\n#### 参数:\n\n    button (optional) - Accepts left, right, or center. Defaults to left.\n    double (optional) - Set to true to perform a double click. Defaults to false.\n\n#### 示例:\n\n```Go\nrobotgo.MouseClick()\nrobotgo.MouseClick(\"left\", true)\n```\n\n### <h3 id=\"MoveClick\">.MoveClick(x, y, button, double)</h3>\n\n    移动并点击鼠标\n\n#### 参数:\n    x,\n    y,\n\n    button (optional) - Accepts \"left\", \"right\", or \"center\". Defaults to left.\n    double (optional) - Set to true to perform a double click. Defaults to false.\n\n#### 示例:\n\n```Go\nrobotgo.MoveClick(10, 20)\nrobotgo.MoveClick(10, 20, \"left\", true)\n```\n\n### <h3 id=\"MouseToggle\">.MouseToggle(down, button)</h3>\n    鼠标切换\n\n    Toggles mouse button.\n\n#### 参数:\n\n    down (optional) - Accepts down or up. Defaults to down.\n    button (optional) - Accepts \"left\", \"right\", or \"center\". Defaults to left.\n\n#### 示例:\n\n```Go\nrobotgo.MouseToggle(\"down\")\nrobotgo.MouseToggle(\"down\", \"right\")\n```\n\n### <h3 id=\"DragMouse\">.DragMouse(x, y)</h3>\n    拖动鼠标\n\n    Moves mouse to x, y instantly, with the mouse button held down.\n\n#### 参数:\n\n    x, y\n\n#### 示例:\n\n```Go\n// Mouse down at 0, 0 and then drag to 100, 100 and release. \nrobotgo.MoveMouse(0, 0)\nrobotgo.MouseToggle(\"down\")\nrobotgo.DragMouse(100, 100)\nrobotgo.MouseToggle(\"up\")\n```\n\n### <h3 id=\"GetMousePos\">.GetMousePos()</h3>\n    获取鼠标的位置\n\n    Gets the mouse coordinates.\n\n#### 返回值:\n\n    Returns an object with keys x and y.\n\n#### 示例:\n\n```Go\nx, y := robotgo.GetMousePos()\nfmt.Println(\"pos:\", x, y)\n```\n\n### <h3 id=\"ScrollMouse\">.ScrollMouse(magnitude, direction)</h3>\n    滚动鼠标\n\n    Scrolls the mouse either up or down.\n\n#### 参数:\n    滚动位置的大小\n    滚动方向: up (向上滚动)  down (向下滚动)\n\n    magnitude - The amount to scroll.\n    direction - Accepts down or up.\n\n#### 示例:\n\n```Go\nrobotgo.ScrollMouse(50, \"up\")\n\nrobotgo.ScrollMouse(50, \"down\")\n```\n\n\n## <h2 id=\"Screen\">屏幕</h2>\n### <h3 id=\"GetPixelColor\">.GetPixelColor(x, y)\n    获取坐标为 x, y 位置处的颜色\n\n    Gets the pixel color at x, y. This function is perfect for getting a pixel or two,  \n    but if you'll be reading large portions of the screen use screen.capture.\n\n#### 参数:\n\n    x, y\n\n#### 返回值:\n\n    Returns the hex color code of the pixel at x, y.\n\n### <h3 id=\"GetScreenSize\">.GetScreenSize()</h3>\n    获取屏幕大小\n\n    Gets the screen width and height.\n\n#### 返回值:\n\n    Returns an object with .width and .height.\n\n### <h3 id=\"CaptureScreen\">.CaptureScreen</h3>\n    // CaptureScreen\n    获取部分或者全部屏幕\n    Gets part or all of the screen.\n\n    GoCaptureScreen Returns a go struct\n<!-- Capture_Screen (废弃) -->\n\n#### 参数:\n\n    x (optional)\n    y (optional)\n    height (optional)\n    width (optional)\n    If no arguments are provided, capturescreen(screencapture) will get the full screen.\n\n#### 返回值:\n\n    返回一个 bitmap object.\n\n## <h2 id=\"Bitmap\">位图</h2>\n\n    This is a work in progress.\n\n### <h3 id=\"FindBitmap\">.FindBitmap</h3>\n\n    查找 bitmap.\n\n#### 参数:\n\n    bitmap;\n    rect (可选参数): x, y, w, h\n\n#### Return:\n\n    查找到, 返回 bitmap 的 x 和y 坐标; 没有返回 nil\n\n\n### <h3 id=\"OpenBitmap\">.OpenBitmap</h3>\n\n    打开 bitmap 图片.\n\n#### 参数:\n\n    bitmap 图片路径,\n    MMImageType (可选)\n\n#### 返回值:\n\n     返回一个 bitmap 对象\n\n### <h3 id=\"SaveBitmap\">.SaveBitmap</h3>\n\n    保存一个 bitmap 图片.\n\n#### 参数:\n\n    bitmap 对象,\n    保存路径,\n    imagetype (int) \n\n#### 返回值:\n\n    保存图片, 返回保存状态\n\n\n### <h3 id=\"TostringBitmap\">.TostringBitmap</h3>\n\n     将一个 bitmap 对象转换为字符串对象.\n\n#### 参数:\n\n    bitmap 对象 \n\n#### Return:\n\n    返回一个 bitmap 字符串 \n\n### <h3 id=\"GetPortion\">.GetPortion</h3>\n\n     bitmap from a portion\n\n#### 参数:\n\n    bitmap,\n    rect: x, y, w, h \n\n#### 返回值:\n\n    Returns new bitmap object created from a portion of another    \n\n### <h3 id=\"Convert\">.Convert(openpath, savepath, MMImageType)</h3>\n\n    转换 bitmap 图片格式\n\n#### 参数:\n\n    openpath,\n    savepath,\n    MMImageType (可选)\n\n#### 示例:\n\n```Go\nrobotgo.Convert(\"test.png\", \"test.tif\")\n```  \n\n### <h3 id=\"FreeBitmap\">.FreeBitmap(MMBitmapRef)</h3>\n\n    FreeBitmap free and dealloc bitmap\n\n#### 参数:\n\n    MMBitmapRef\n\n#### 示例:\n\n```Go\nrobotgo.FreeBitmap(bitmap)\n```    \n\n\n### <h3 id=\"ReadBitmap\">.ReadBitmap(MMBitmapRef)</h3>\n\n    ReadBitmap returns false and sets error if |bitmap| is NULL\n\n#### 参数:\n\n    MMBitmapRef\n\n#### 返回值:\n\n    bool\n    \n#### 示例:\n\n```Go\nrobotgo.ReadBitmap(bitmap)\n```    \n\n\n### <h3 id=\"CopyBitpb\">.CopyBitpb(MMBitmapRef)</h3>\n\n   CopyBitpb copy bitmap to pasteboard\n\n#### 参数:\n\n    MMBitmapRef\n\n#### 返回值:\n\n    bool\n\n#### 示例:\n\n```Go\nrobotgo.CopyBitpb(bitmap)\n```    \n\n### <h3 id=\"DeepCopyBit\">.DeepCopyBit(MMBitmapRef)</h3>\n\n   DeepCopyBit deep copy bitmap\n\n#### 参数:\n\n    MMBitmapRef\n\n#### 返回值:\n\n    MMBitmapRef\n\n#### 示例:\n\n```Go\nrobotgo.DeepCopyBit(bitmap)\n```  \n\n## <h2 id=\"Event\">事件</h2> \n\n### <h3 id=\"AddEvent\">.AddEvent(string)</h3>\n\n    监听全局事件\n\n#### 参数:\n\n    string\n\n    (鼠标参数: mleft, mright, wheelDown, wheelUp, wheelLeft, wheelRight)\n \n#### 返回值:\n\n    监听成功返回 0\n\n#### 示例:\n\n```Go\npackage main\n\nimport (\n    \"fmt\"\n\n    \"github.com/go-vgo/robotgo\"\n)\n\nfunc main() {\n  keve := robotgo.AddEvent(\"k\")\n  if keve {\n    fmt.Println(\"you press...\", \"k\")\n  }\n\n  mleft := robotgo.AddEvent(\"mleft\")\n  if mleft {\n    fmt.Println(\"you press...\", \"mouse left button\")\n  }\n} \n```\n\n### <h3 id=\"StopEvent\">.StopEvent()</h3>  \n    停止事件监听\n\n## <h2 id=\"Window\">窗口</h2> \n\n### <h3 id=\"ShowAlert\">.ShowAlert(title, msg, defaultButton, cancelButton string)</h3>\n\n    Displays alert with the given attributes. If cancelButton is not given, only the defaultButton is displayed\n\n#### 参数:\n\n    title (string),\n    msg (string),\n    defaultButton (optional string),\n    cancelButton (optional string)\n           \n\n#### 返回值:\n\n    Returns 0 (True) if the default button was pressed, or 1 (False) if cancelled.\n   \n### <h3 id=\"CloseWindow\">.CloseWindow()</h3>\n\n    关闭窗口\n\n#### 参数:\n    无    \n\n#### 返回值:\n    无\n\n### <h3 id=\"IsValid\">.IsValid()</h3>\n\n    Valid the Window\n\n#### 参数:\n    无      \n\n#### 返回值:\n    如果窗口 selected 返回 true \n\n\n### <h3 id=\"SetActive\">.SetActive()</h3>\n\n    设为当前窗口\n\n#### 参数:\n    hwnd  \n\n#### 返回值:\n    void\n\n\n### <h3 id=\"GetActive\">.GetActive()</h3>\n\n    获取当前窗口\n\n#### 参数:\n    无       \n\n#### 返回值:\n    Returns hwnd\n\n### <h3 id=\"SetHandle\">.SetHandle()</h3>\n\n    Set the Window Handle\n\n#### 参数:\n    int \n\n#### 返回值:\n    bool    \n\n### <h3 id=\"GetHandle\">.GetHandle()</h3>\n\n    获取窗口 Handle\n\n#### 参数:\n    无    \n\n#### 返回值:\n    Returns hwnd  \n\n### <h3 id=\"GetTitle\">.GetTitle()</h3>\n\n    获取窗口标题\n\n#### 参数:\n           \n\n#### 返回值:\n    返回窗口标题  \n\n### <h3 id=\"GetPID\">.GetPID()</h3>\n\n    获取进程 id\n\n#### 参数:\n    无   \n\n#### 返回值:\n    返回进程 id    \n\n### <h3 id=\"Pids\">.Pids()</h3>\n\n    获取所有进程 id\n\n#### 参数:\n    无   \n\n#### 返回值:\n    返回进程 id   \n\n### <h3 id=\"PidExists\">.PidExists()</h3>\n\n    判断进程 id 是否存在\n\n#### 参数:\n    pid  \n\n#### 返回值:\n    返回 bool \n\n### <h3 id=\"Process\">.Process()</h3>\n\n  Process get the all process struct\n\n#### 参数:\n    无  \n\n#### 返回值:\n    Returns []Nps, error\n\n### <h3 id=\"FindName\">.FindName()</h3>\n\n    FindName find the process name by the process id\n\n#### 参数:\n    pid  \n\n#### 返回值:\n    Returns string, error \n\n### <h3 id=\"FindNames\">.FindNames()</h3>\n\n    FindNames find the all process name\n\n#### Arguments:\n    none  \n\n#### Return:\n    Returns []string, error  \n\n### <h3 id=\"FindIds\">.FindIds()</h3>\n\n    FindIds find the process id by the process name\n\n#### Arguments:\n    name string  \n\n#### Return:\n    Returns []int32, error  \n\n### <h3 id=\"ActivePID\">.ActivePID()</h3>\n\n    ActivePID window active by PID\n\n#### Arguments:\n    pid int32 \n\n#### Return:\n    none                        "
  },
  {
    "path": "docs/install.md",
    "content": "## CrossCompiling\n\n##### Windows64 to windows32\n\n```Go\nSET CGO_ENABLED=1\nSET GOARCH=386\ngo build main.go\n```\n\n#### Other to windows\n\nInstall Requirements (Ubuntu):\n\n```bash\nsudo apt install gcc-multilib\nsudo apt install gcc-mingw-w64\n# fix err: zlib.h: No such file or directory, Just used by bitmap.\nsudo apt install libz-mingw-w64-dev\n```\n\nBuild the binary:\n\n```Go\nGOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ go build -x ./\n```\n\n```\n// CC=mingw-w64\\x86_64-7.2.0-win32-seh-rt_v5-rev1\\mingw64\\bin\\gcc.exe\n// CXX=mingw-w64\\x86_64-7.2.0-win32-seh-rt_v5-rev1\\mingw64\\bin\\g++.exe\n```\n\nSome discussions and questions, please see [issues/228](https://github.com/go-vgo/robotgo/issues/228), [issues/143](https://github.com/go-vgo/robotgo/issues/143).\n"
  },
  {
    "path": "docs/keys.md",
    "content": "## Type Conversion\n\n|     | type conversion                   | func                    |\n| --- | --------------------------------- | ----------------------- |\n| \\*  | robotgo.Bitmap -> robotgo.CBitmap | robotgo.ToCBitmap()     |\n|     | robotgo.Bitmap -> \\*image.RGBA    | robotgo.ToRGBAGo()      |\n| \\*  | robotgo.CBitmap -> C.MMBitmapRef  | robotgo.ToMMBitmapRef() |\n|     | robotgo.CBitmap -> robotgo.Bitmap | robotgo.ToBitmap()      |\n|     | robotgo.CBitmap -> image.Image    | robotgo.ToImage()       |\n|     | robotgo.CBitmap -> \\*image.RGBA   | robotgo.ToRGBA()        |\n| \\*  | C.MMBitmapRef -> robotgo.CBitmap  | robotgo.CBitmap()       |\n| \\*  | image.Image -> robotgo.Bitmap     | robotgo.ImgToBitmap()   |\n|     | image.Image -> robotgo.CBitmap    | robotgo.ImgToCBitmap()  |\n|     | image.Image -> []byte             | robotgo.ToByteImg()     |\n|     | image.Image -> string             | robotgo.ToStringImg()   |\n| \\*  | \\*image.RGBA -> robotgo.Bitmap    | robotgo.RGBAToBitmap()  |\n| \\*  | []byte -> image.Image             | robotgo.ByteToImg()     |\n|     | []byte-> robotgo.CBitmap          | robotgo.ByteToCBitmap() |\n|     | []byte -> string                  | string()                |\n| \\*  | string -> image.Image             | robotgo.StrToImg()      |\n|     | string -> byte                    | []byte()                |\n\n# Keys\n\n```Go\n\t\"A-Z a-z 0-9\"\n\n\t\"backspace\"\n\t\"delete\"\n\t\"enter\"\n\t\"tab\"\n\t\"esc\"\n\t\"escape\"\n\t\"up\"\t\tUp arrow key\n\t\"down\"\t\tDown arrow key\n\t\"right\"\t\tRight arrow key\n\t\"left\"\t\tLeft arrow key\n\t\"home\"\n\t\"end\"\n\t\"pageup\"\n\t\"pagedown\"\n\n\t\"f1\"\n\t\"f2\"\n\t\"f3\"\n\t\"f4\"\n\t\"f5\"\n\t\"f6\"\n\t\"f7\"\n\t\"f8\"\n\t\"f9\"\n\t\"f10\"\n\t\"f11\"\n\t\"f12\"\n\t\"f13\"\n\t\"f14\"\n\t\"f15\"\n\t\"f16\"\n\t\"f17\"\n\t\"f18\"\n\t\"f19\"\n\t\"f20\"\n\t\"f21\"\n\t\"f22\"\n\t\"f23\"\n\t\"f24\"\n\n\t\"cmd\"\t\tis the \"win\" key for windows\n\t\"lcmd\"\t\tleft command\n\t\"rcmd\"\t\tright command\n\t// \"command\"\n\t\"alt\"\n\t\"lalt\"\t\tleft alt\n\t\"ralt\"\t\tright alt\n\t\"ctrl\"\n\t\"lctrl\"\t\tleft ctrl\n\t\"rctrl\"\t\tright ctrl\n\t\"control\"\n\t\"shift\"\n\t\"lshift\"\tleft shift\n\t\"rshift\"\tright shift\n\t// \"right_shift\"\n\t\"capslock\"\n\t\"space\"\n\t\"print\"\n\t\"printscreen\"      // No Mac support\n\t\"insert\"\n\t\"menu\"\t\t\t\tWindows only\n\n\t\"audio_mute\"\t\tMute the volume\n\t\"audio_vol_down\"\tLower the volume\n\t\"audio_vol_up\"\t\tIncrease the volume\n\t\"audio_play\"\n\t\"audio_stop\"\n\t\"audio_pause\"\n\t\"audio_prev\"\t\tPrevious Track\n\t\"audio_next\"\t\tNext Track\n\t\"audio_rewind\"      Linux only\n\t\"audio_forward\"     Linux only\n\t\"audio_repeat\"      Linux only\n\t\"audio_random\"      Linux only\n\n\n\t\"num0\"\n\t\"num1\"\n\t\"num2\"\n\t\"num3\"\n\t\"num4\"\n\t\"num5\"\n\t\"num6\"\n\t\"num7\"\n\t\"num8\"\n\t\"num9\"\n\t\"num_lock\"\n\n\t\"num.\"\n\t\"num+\"\n\t\"num-\"\n\t\"num*\"\n\t\"num/\"\n\t\"num_clear\"\n\t\"num_enter\"\n\t\"num_equal\"\n\n\t// // \"numpad_0\"\t\tNo Linux support\n\t// \"numpad_0\"\n\t// \"numpad_1\"\n\t// \"numpad_2\"\n\t// \"numpad_3\"\n\t// \"numpad_4\"\n\t// \"numpad_5\"\n\t// \"numpad_6\"\n\t// \"numpad_7\"\n\t// \"numpad_8\"\n\t// \"numpad_9\"\n\t// \"numpad_lock\"\n\n\t\"lights_mon_up\"\t\t Turn up monitor brightness\t\t\t\t\tNo Windows support\n\t\"lights_mon_down\"\t Turn down monitor brightness\t\t\t\tNo Windows support\n\t\"lights_kbd_toggle\"\t Toggle keyboard backlight on/off\t\t\tNo Windows support\n\t\"lights_kbd_up\"\t\t Turn up keyboard backlight brightness\t\tNo Windows support\n\t\"lights_kbd_down\"\t Turn down keyboard backlight brightness\tNo Windows support\n```\n"
  },
  {
    "path": "event/android/event_c.h",
    "content": "#include <linux/input.h>\n#include <string.h>\n"
  },
  {
    "path": "event/ios/event_c.h",
    "content": "#include <AppKit/NSEvent.h>\n#include <string.h>\n"
  },
  {
    "path": "examples/README.md",
    "content": "# Robotgo examples\n\n## Install:\n```\ngo get -u github.com/go-vgo/robotgo  \n```\n\n## [Examples:](https://github.com/go-vgo/robotgo/blob/master/examples)\n\n#### [Mouse](https://github.com/go-vgo/robotgo/blob/master/examples/mouse/main.go)\n\n```Go\npackage main\n\nimport (\n\t\"github.com/go-vgo/robotgo\"\n)\n\nfunc main() {\n  // robotgo.ScrollMouse(10, \"up\")\n  robotgo.Scroll(0, 10)\n  robotgo.MouseClick(\"left\", true)\n  robotgo.MoveSmooth(100, 200, 1.0, 100.0)\n} \n``` \n\n#### [Keyboard](https://github.com/go-vgo/robotgo/blob/master/examples/key/main.go)\n\n```Go\npackage main\n\nimport (\n  \"fmt\"\n\n  \"github.com/go-vgo/robotgo\"\n)\n\nfunc main() {\n  robotgo.TypeStr(\"Hello World\")\n  // robotgo.TypeStr(\"だんしゃり\")\n  robotgo.TypeStr(\"だんしゃり\")\n  // ustr := uint32(robotgo.CharCodeAt(\"だんしゃり\", 0))\n  // robotgo.UnicodeType(ustr)\n\n  robotgo.KeyTap(\"enter\")\n  robotgo.TypeStr(\"en\")\n  robotgo.KeyTap(\"i\", \"alt\", \"command\")\n  arr := []string{\"alt\", \"command\"}\n  robotgo.KeyTap(\"i\", arr)\n\n  robotgo.WriteAll(\"Test\")\n  text, err := robotgo.ReadAll()\n  if err == nil {\n    fmt.Println(text)\n  }\n} \n```\n\n#### [Screen](https://github.com/go-vgo/robotgo/blob/master/examples/screen/main.go)\n\n```Go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/go-vgo/robotgo\"\n)\n\nfunc main() {\n  x, y := robotgo.Location()\n  fmt.Println(\"pos:\", x, y)\n  color := robotgo.GetPixelColor(100, 200)\n  fmt.Println(\"color----\", color)\n} \n```\n\n#### [Bitmap](https://github.com/go-vgo/robotgo/blob/master/examples/bitmap/main.go)\n\n```Go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/go-vgo/robotgo\"\n)\n\nfunc main() {\n  bitmap := robotgo.CaptureScreen(10, 20, 30, 40)\n  // use `defer robotgo.FreeBitmap(bit)` to free the bitmap\n  defer robotgo.FreeBitmap(bitmap)\n  fmt.Println(\"...\", bitmap)\n\n  fx, fy := robotgo.FindBitmap(bitmap)\n  fmt.Println(\"FindBitmap------\", fx, fy)\n\n  robotgo.SaveBitmap(bitmap, \"test.png\")\n} \n```\n\n#### [Event](https://github.com/go-vgo/robotgo/blob/master/examples/event/main.go)\n\n```Go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/go-vgo/robotgo\"\n)\n\nfunc main() {\n  keve := robotgo.AddEvent(\"k\")\n  if keve {\n    fmt.Println(\"you press...\", \"k\")\n  }\n\n  mleft := robotgo.AddEvent(\"mleft\")\n  if mleft {\n    fmt.Println(\"you press...\", \"mouse left button\")\n  }\n} \n```\n\n#### [Window](https://github.com/go-vgo/robotgo/blob/master/examples/window/main.go)\n\n```Go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/go-vgo/robotgo\"\n)\n\nfunc main() {\n  fpid, err := robotgo.FindIds(\"Google\")\n  if err == nil {\n    fmt.Println(\"pids...\", fpid)\n\n    if len(fpid) > 0 {\n      robotgo.ActivePID(fpid[0])\n\n      robotgo.Kill(fpid[0])\n    }\n  }\n\n  robotgo.ActiveName(\"chrome\")\n\n  isExist, err := robotgo.PidExists(100)\n  if err == nil && isExist {\n    fmt.Println(\"pid exists is\", isExist)\n\n    robotgo.Kill(100)\n  }\n\n  abool := robotgo.ShowAlert(\"test\", \"robotgo\")\n  if abool == 0 {\n \t  fmt.Println(\"ok@@@\", \"ok\")\n  }\n\n  title := robotgo.GetTitle()\n  fmt.Println(\"title@@@\", title)\n} \n```"
  },
  {
    "path": "examples/key/main.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/go-vgo/robotgo\"\n\t// \"go-vgo/robotgo\"\n)\n\nfunc typeStr() {\n\t// typing \"Hello World\"\n\trobotgo.Type(\"Hello World!\", 0, 1)\n\trobotgo.KeySleep = 100\n\trobotgo.Type(\"だんしゃり\")\n\n\trobotgo.Type(\"Hi galaxy, hi stars, hi MT.Rainier, hi sea. こんにちは世界.\")\n\trobotgo.Type(\"So, hi, bye! 你好, 再见!\")\n\trobotgo.Sleep(1)\n\n\trobotgo.Type(\"Hi, Seattle space needle, Golden gate bridge, One world trade center.\")\n\trobotgo.MilliSleep(100)\n\n\tustr := uint32(robotgo.CharCodeAt(\"So, hi, bye!\", 0))\n\trobotgo.UnicodeType(ustr)\n\n\terr := robotgo.Paste(\"paste string\")\n\tfmt.Println(\"PasteStr: \", err)\n}\n\nfunc keyTap() {\n\t// press \"enter\"\n\trobotgo.KeyTap(\"enter\")\n\trobotgo.KeyTap(robotgo.Enter)\n\trobotgo.KeySleep = 200\n\trobotgo.KeyTap(\"a\")\n\trobotgo.MilliSleep(100)\n\trobotgo.KeyTap(\"a\", \"ctrl\")\n\n\t// hide window\n\terr := robotgo.KeyTap(\"h\", \"cmd\")\n\tif err != nil {\n\t\tfmt.Println(\"robotgo.KeyTap run error is: \", err)\n\t}\n\n\trobotgo.KeyTap(\"h\", \"cmd\")\n\n\t// press \"i\", \"alt\", \"command\" Key combination\n\trobotgo.KeyTap(robotgo.KeyI, robotgo.Alt, robotgo.Cmd)\n\trobotgo.KeyTap(\"i\", \"alt\", \"cmd\")\n\n\tarr := []string{\"alt\", \"cmd\"}\n\trobotgo.KeyTap(\"i\", arr)\n\trobotgo.KeyTap(\"i\", arr)\n\n\trobotgo.KeyTap(\"i\", \"cmd\", \" alt\", \"shift\")\n\n\t// close window\n\trobotgo.KeyTap(\"w\", \"cmd\")\n\n\t// minimize window\n\trobotgo.KeyTap(\"m\", \"cmd\")\n\n\trobotgo.KeyTap(\"f1\", \"ctrl\")\n\trobotgo.KeyTap(\"a\", \"control\")\n}\n\nfunc special() {\n\trobotgo.Type(\"{}\")\n\trobotgo.KeyTap(\"[\", \"]\")\n\n\trobotgo.KeyToggle(\"(\")\n\trobotgo.KeyToggle(\"(\", \"up\")\n}\n\nfunc keyToggle() {\n\t// robotgo.KeySleep = 150\n\trobotgo.KeyToggle(robotgo.KeyA)\n\trobotgo.KeyToggle(\"a\", \"down\", \"alt\")\n\trobotgo.Sleep(1)\n\n\trobotgo.KeyToggle(\"a\", \"up\", \"alt\", \"cmd\")\n\trobotgo.MilliSleep(100)\n\trobotgo.KeyToggle(\"q\", \"up\", \"alt\", \"cmd\", \"shift\")\n\n\terr := robotgo.KeyToggle(robotgo.Enter)\n\tif err != nil {\n\t\tfmt.Println(\"robotgo.KeyToggle run error is: \", err)\n\t}\n}\n\nfunc cilp() {\n\t// robotgo.TypeStr(\"en\")\n\n\t// write string to clipboard\n\te := robotgo.WriteAll(\"テストする\")\n\tif e != nil {\n\t\tfmt.Println(\"robotgo.WriteAll err is: \", e)\n\t}\n\n\t// read string from clipboard\n\ttext, err := robotgo.ReadAll()\n\tif err != nil {\n\t\tfmt.Println(\"robotgo.ReadAll err is: \", err)\n\t}\n\tfmt.Println(\"text: \", text)\n}\n\nfunc key() {\n\t////////////////////////////////////////////////////////////////////////////////\n\t// Control the keyboard\n\t////////////////////////////////////////////////////////////////////////////////\n\n\ttypeStr()\n\tspecial()\n\n\tkeyTap()\n\tkeyToggle()\n\n\tcilp()\n}\n\nfunc main() {\n\tkey()\n}\n"
  },
  {
    "path": "examples/main.go",
    "content": "// Copyright (c) 2016-2025 AtomAI go-vgo, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/go-vgo/robotgo\"\n\t// \"go-vgo/robotgo\"\n)\n\nfunc main() {\n\tver := robotgo.GetVersion()\n\tfmt.Println(\"robotgo version is: \", ver)\n\n\t// Control the keyboard\n\t// key()\n\n\t// Control the mouse\n\t// mouse()\n\n\t// Read the screen\n\t// screen()\n\n\t// Bitmap and image processing\n\t// bitmap()\n\n\t// Global event listener\n\t// event()\n\n\t// Window Handle and progress\n\t// window()\n}\n"
  },
  {
    "path": "examples/mouse/main.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/go-vgo/robotgo\"\n\t// \"go-vgo/robotgo\"\n)\n\nfunc move() {\n\trobotgo.MouseSleep = 100\n\trobotgo.Move(100, 200)\n\trobotgo.MoveRelative(10, -200)\n\n\t// move the mouse to 100, 200\n\trobotgo.Move(100, 200)\n\n\t// drag mouse with smooth\n\trobotgo.DragSmooth(10, 10)\n\trobotgo.DragSmooth(100, 200, 1.0, 100.0)\n\n\t// smooth move the mouse to 100, 200\n\trobotgo.MoveSmooth(100, 200)\n\trobotgo.MoveSmooth(100, 200, 1.0, 100.0)\n\trobotgo.MoveSmoothRelative(10, -100, 1.0, 30.0)\n\n\tfor i := 0; i < 1080; i += 1000 {\n\t\tfmt.Println(\"i: \", i)\n\t\t// MoveMouse(800, i)\n\t\trobotgo.Move(800, i)\n\t}\n}\n\nfunc click() {\n\n\t// click the left mouse button\n\trobotgo.Click()\n\n\t// click the right mouse button\n\trobotgo.Click(\"right\", false)\n\n\t// double click the left mouse button\n\trobotgo.Click(\"left\", true)\n}\n\nfunc get() {\n\t// gets the mouse coordinates\n\tx, y := robotgo.Location()\n\tfmt.Println(\"pos:\", x, y)\n\tif x == 456 && y == 586 {\n\t\tfmt.Println(\"mouse...\", \"586\")\n\t}\n\n\trobotgo.Move(x, y)\n}\n\nfunc toggleAndScroll() {\n\t// scrolls the mouse either up\n\trobotgo.ScrollDir(10, \"up\")\n\trobotgo.ScrollDir(10, \"right\")\n\n\trobotgo.Scroll(100, 10)\n\trobotgo.Scroll(0, -10)\n\n\trobotgo.Toggle(\"left\")\n\trobotgo.Toggle(\"left\", \"up\")\n\n\t// toggles the right mouse button\n\trobotgo.Toggle(\"right\")\n\trobotgo.Toggle(\"right\", \"up\")\n}\n\nfunc mouse() {\n\t////////////////////////////////////////////////////////////////////////////////\n\t// Control the mouse\n\t////////////////////////////////////////////////////////////////////////////////\n\n\tmove()\n\n\tclick()\n\n\tget()\n\n\ttoggleAndScroll()\n}\n\nfunc main() {\n\tmouse()\n}\n"
  },
  {
    "path": "examples/scale/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/go-vgo/robotgo\"\n)\n\nfunc main() {\n\t// syscall.NewLazyDLL(\"user32.dll\").NewProc(\"SetProcessDPIAware\").Call()\n\n\twidth, height := robotgo.GetScaleSize()\n\tfmt.Println(\"get scale screen size: \", width, height)\n\n\tbitmap := robotgo.CaptureScreen(0, 0, width, height)\n\tdefer robotgo.FreeBitmap(bitmap)\n\t// bitmap.Save(bitmap, \"test.png\")\n\trobotgo.Save(robotgo.ToImage(bitmap), \"test.png\")\n\n\trobotgo.Scale = true\n\trobotgo.Move(10, 10)\n\trobotgo.MoveSmooth(100, 100)\n\n\tfmt.Println(robotgo.Location())\n\n\tnum := robotgo.DisplaysNum()\n\tfor i := 0; i < num; i++ {\n\t\trect := robotgo.GetScreenRect(i)\n\t\tfmt.Println(\"rect: \", rect)\n\t}\n}\n\nfunc old() {\n\tsx := robotgo.ScaleX() // Deprecated\n\ts := robotgo.Scale1()  // Deprecated, use the ScaleF() function\n\trobotx, roboty := 35*s/100, 25*s/100\n\tfmt.Println(\"scale: \", sx, s, \" pos: \", robotx, roboty)\n\n\tmx, my := robotgo.Location()\n\tsx, sy := mx*s/100, my*s/100\n\n\trx, ry, rw, rh := sx, sy, robotx, roboty\n\t// bit1 := robotgo.CaptureScreen(10, 20, robotw, roboth)\n\tbit1 := robotgo.CaptureScreen(rx, ry, rw, rh)\n\tdefer robotgo.FreeBitmap(bit1)\n\t// bitmap.Save(bit1, \"test2.png\")\n\trobotgo.Save(robotgo.ToImage(bit1), \"test2.png\")\n\n\tclo := robotgo.GetPixelColor(robotx, roboty)\n\tfmt.Println(\"GetPixelColor...\", clo)\n}\n"
  },
  {
    "path": "examples/screen/main.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\n\t\"github.com/go-vgo/robotgo\"\n\t// \"go-vgo/robotgo\"\n)\n\nfunc bitmap() {\n\tbit := robotgo.CaptureScreen()\n\tdefer robotgo.FreeBitmap(bit)\n\tfmt.Println(\"abitMap...\", bit)\n\n\tgbit := robotgo.ToBitmap(bit)\n\tfmt.Println(\"bitmap...\", gbit.Width)\n\n\tgbitMap := robotgo.CaptureGo()\n\tfmt.Println(\"Go CaptureScreen...\", gbitMap.Width)\n\t// fmt.Println(\"...\", gbitmap.Width, gbitmap.BytesPerPixel)\n\trobotgo.SaveCapture(\"saveCapture.png\", 10, 20, 100, 100)\n\n\timg, err := robotgo.CaptureImg()\n\tfmt.Println(\"error: \", err)\n\trobotgo.Save(img, \"save.png\")\n\n\tnum := robotgo.DisplaysNum()\n\tfor i := 0; i < num; i++ {\n\t\trobotgo.DisplayID = i\n\t\timg1, _ := robotgo.CaptureImg()\n\t\tpath1 := \"save_\" + strconv.Itoa(i)\n\t\trobotgo.Save(img1, path1+\".png\")\n\t\trobotgo.SaveJpeg(img1, path1+\".jpeg\", 50)\n\n\t\timg2, _ := robotgo.CaptureImg(10, 10, 20, 20)\n\t\tpath2 := \"test_\" + strconv.Itoa(i)\n\t\trobotgo.Save(img2, path2+\".png\")\n\t\trobotgo.SaveJpeg(img2, path2+\".jpeg\", 50)\n\n\t\tx, y, w, h := robotgo.GetDisplayBounds(i)\n\t\timg3, err := robotgo.CaptureImg(x, y, w, h)\n\t\tfmt.Println(\"Capture error: \", err)\n\t\trobotgo.Save(img3, path2+\"_1.png\")\n\t}\n}\n\nfunc color() {\n\t// gets the pixel color at 100, 200.\n\tcolor := robotgo.GetPixelColor(100, 200)\n\tfmt.Println(\"color----\", color, \"-----------------\")\n\n\tclo := robotgo.GetPxColor(100, 200)\n\tfmt.Println(\"color...\", clo)\n\tclostr := robotgo.PadHex(clo)\n\tfmt.Println(\"color...\", clostr)\n\n\trgb := robotgo.RgbToHex(255, 100, 200)\n\trgbstr := robotgo.PadHex(robotgo.U32ToHex(rgb))\n\tfmt.Println(\"rgb...\", rgbstr)\n\n\thex := robotgo.HexToRgb(uint32(rgb))\n\tfmt.Println(\"hex...\", hex)\n\thexh := robotgo.PadHex(robotgo.U8ToHex(hex))\n\tfmt.Println(\"HexToRgb...\", hexh)\n\n\t// gets the pixel color at 10, 20.\n\tcolor2 := robotgo.GetPixelColor(10, 20)\n\tfmt.Println(\"color---\", color2)\n}\n\nfunc screen() {\n\t////////////////////////////////////////////////////////////////////////////////\n\t// Read the screen\n\t////////////////////////////////////////////////////////////////////////////////\n\n\tbitmap()\n\n\t// gets the screen width and height\n\tsx, sy := robotgo.GetScreenSize()\n\tfmt.Println(\"get screen size: \", sx, sy)\n\tfor i := 0; i < robotgo.DisplaysNum(); i++ {\n\t\ts1 := robotgo.ScaleF(i)\n\t\tfmt.Println(\"ScaleF: \", s1)\n\t}\n\tsx, sy = robotgo.GetScaleSize()\n\tfmt.Println(\"get screen scale size: \", sx, sy)\n\n\tcolor()\n}\n\nfunc main() {\n\tscreen()\n}\n"
  },
  {
    "path": "examples/window/main.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/go-vgo/robotgo\"\n\t// \"go-vgo/robotgo\"\n)\n\nfunc alert() {\n\t// show Alert Window\n\tabool := robotgo.Alert(\"hello\", \"robotgo\")\n\tif abool {\n\t\tfmt.Println(\"ok@@@\", \"ok\")\n\t}\n\trobotgo.Alert(\"hello\", \"robotgo\", \"Ok\", \"Cancel\")\n}\n\nfunc get() {\n\t// get the current process id\n\tpid := robotgo.GetPid()\n\tfmt.Println(\"pid----\", pid)\n\n\t// get current Window Active\n\tmdata := robotgo.GetActive()\n\n\t// get current Window Handle\n\thwnd := robotgo.GetHandle()\n\tfmt.Println(\"hwnd---\", hwnd)\n\n\t// get current Window title\n\ttitle := robotgo.GetTitle()\n\tfmt.Println(\"title-----\", title)\n\n\t// set Window Active\n\trobotgo.SetActive(mdata)\n}\n\nfunc findIds() {\n\t// find the process id by the process name\n\tfpid, err := robotgo.FindIds(\"Google\")\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\treturn\n\t}\n\n\tif len(fpid) > 0 {\n\t\trobotgo.KeyTap(\"a\", fpid[0])\n\t\trobotgo.TypeStr(\"Hi galaxy!\", fpid[0])\n\n\t\trobotgo.KeyToggle(\"a\", fpid[0], \"cmd\")\n\t\trobotgo.KeyToggle(\"a\", fpid[0], \"cmd\", \"up\")\n\t}\n\n\tfmt.Println(\"pids...\", fpid)\n\tif len(fpid) > 0 {\n\t\terr = robotgo.ActivePid(fpid[0])\n\t\tif err != nil {\n\t\t\tfmt.Println(err)\n\t\t}\n\n\t\ttl := robotgo.GetTitle(fpid[0])\n\t\tfmt.Println(\"pid[0] title is: \", tl)\n\n\t\tx, y, w, h := robotgo.GetBounds(fpid[0])\n\t\tfmt.Println(\"GetBounds is: \", x, y, w, h)\n\n\t\t// Windows\n\t\t// hwnd := robotgo.FindWindow(\"google\")\n\t\t// hwnd := robotgo.GetHWND()\n\t\trobotgo.MinWindow(fpid[0])\n\t\trobotgo.MaxWindow(fpid[0])\n\t\trobotgo.CloseWindow(fpid[0])\n\n\t\trobotgo.Kill(fpid[0])\n\t}\n}\n\nfunc active() {\n\trobotgo.ActivePid(100)\n\t// robotgo.Sleep(2)\n\trobotgo.ActiveName(\"code\")\n\trobotgo.Sleep(1)\n\trobotgo.ActiveName(\"chrome\")\n}\n\nfunc findName() {\n\t// find the process name by the process id\n\tname, err := robotgo.FindName(100)\n\tif err == nil {\n\t\tfmt.Println(\"name: \", name)\n\t}\n\n\t// find the all process name\n\tnames, err := robotgo.FindNames()\n\tif err == nil {\n\t\tfmt.Println(\"name: \", names)\n\t}\n\n\tp, err := robotgo.FindPath(100)\n\tif err == nil {\n\t\tfmt.Println(\"path: \", p)\n\t}\n}\n\nfunc ps() {\n\t// determine whether the process exists\n\tisExist, err := robotgo.PidExists(100)\n\tif err == nil && isExist {\n\t\tfmt.Println(\"pid exists is\", isExist)\n\n\t\trobotgo.Kill(100)\n\t}\n\n\t// get the all process id\n\tpids, err := robotgo.Pids()\n\tif err == nil {\n\t\tfmt.Println(\"pids: \", pids)\n\t}\n\n\t// get the all process struct\n\tps, err := robotgo.Process()\n\tif err == nil {\n\t\tfmt.Println(\"process: \", ps)\n\t}\n}\n\nfunc window() {\n\t////////////////////////////////////////////////////////////////////////////////\n\t// Window Handle\n\t////////////////////////////////////////////////////////////////////////////////\n\n\talert()\n\t//\n\tget()\n\n\tfindIds()\n\tactive()\n\n\tfindName()\n\t//\n\tps()\n\n\t// close current Window\n\trobotgo.CloseWindow()\n}\n\nfunc main() {\n\twindow()\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/go-vgo/robotgo\n\ngo 1.24.0\n\nrequire (\n\tgithub.com/otiai10/gosseract/v2 v2.4.1\n\t// github.com/robotn/gohook v0.31.3\n\tgithub.com/robotn/xgb v0.10.0\n\tgithub.com/robotn/xgbutil v0.10.0\n\tgithub.com/tailscale/win v0.0.0-20250627215312-f4da2b8ee071\n\tgithub.com/vcaesar/gops v0.41.0\n\tgithub.com/vcaesar/imgo v0.41.0\n\tgithub.com/vcaesar/keycode v0.10.1\n\tgithub.com/vcaesar/screenshot v0.11.1\n\tgithub.com/vcaesar/tt v0.20.1\n)\n\nrequire (\n\tgithub.com/dblohm7/wingoes v0.0.0-20250822163801-6d8e6105c62d // indirect\n\tgithub.com/ebitengine/purego v0.9.1 // indirect\n\tgithub.com/gen2brain/shm v0.1.1 // indirect\n\tgithub.com/go-ole/go-ole v1.3.0 // indirect\n\tgithub.com/godbus/dbus/v5 v5.2.0 // indirect\n\tgithub.com/jezek/xgb v1.2.0 // indirect\n\tgithub.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect\n\tgithub.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect\n\tgithub.com/shirou/gopsutil/v4 v4.25.10 // indirect\n\tgithub.com/tklauser/go-sysconf v0.3.16 // indirect\n\tgithub.com/tklauser/numcpus v0.11.0 // indirect\n\tgithub.com/yusufpapurcu/wmi v1.2.4 // indirect\n\tgolang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 // indirect\n\tgolang.org/x/image v0.33.0 // indirect\n\tgolang.org/x/sys v0.38.0 // indirect\n)\n\n// replace golang.org/x/sys => github.com/golang/sys v0.0.0-20190109145017-48ac38b7c8cb\n\n// go 1.13\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ=\ngithub.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/dblohm7/wingoes v0.0.0-20250822163801-6d8e6105c62d h1:QRKpU+9ZBDs62LyBfwhZkJdB5DJX2Sm3p4kUh7l1aA0=\ngithub.com/dblohm7/wingoes v0.0.0-20250822163801-6d8e6105c62d/go.mod h1:SUxUaAK/0UG5lYyZR1L1nC4AaYYvSSYTWQSH3FPcxKU=\ngithub.com/ebitengine/purego v0.9.1 h1:a/k2f2HQU3Pi399RPW1MOaZyhKJL9w/xFpKAg4q1s0A=\ngithub.com/ebitengine/purego v0.9.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=\ngithub.com/gen2brain/shm v0.1.1 h1:1cTVA5qcsUFixnDHl14TmRoxgfWEEZlTezpUj1vm5uQ=\ngithub.com/gen2brain/shm v0.1.1/go.mod h1:UgIcVtvmOu+aCJpqJX7GOtiN7X2ct+TKLg4RTxwPIUA=\ngithub.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=\ngithub.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=\ngithub.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=\ngithub.com/godbus/dbus/v5 v5.2.0 h1:3WexO+U+yg9T70v9FdHr9kCxYlazaAXUhx2VMkbfax8=\ngithub.com/godbus/dbus/v5 v5.2.0/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=\ngithub.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=\ngithub.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=\ngithub.com/jezek/xgb v1.2.0 h1:LzgkD11wOrPnxXEqo588cnjUt4NwMHrFh/tgajo50Q0=\ngithub.com/jezek/xgb v1.2.0/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=\ngithub.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 h1:PwQumkgq4/acIiZhtifTV5OUqqiP82UAl0h87xj/l9k=\ngithub.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=\ngithub.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=\ngithub.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=\ngithub.com/otiai10/gosseract/v2 v2.4.1 h1:G8AyBpXEeSlcq8TI85LH/pM5SXk8Djy2GEXisgyblRw=\ngithub.com/otiai10/gosseract/v2 v2.4.1/go.mod h1:1gNWP4Hgr2o7yqWfs6r5bZxAatjOIdqWxJLWsTsembk=\ngithub.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs=\ngithub.com/otiai10/mint v1.6.3/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=\ngithub.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=\ngithub.com/robotn/xgb v0.0.0-20190912153532-2cb92d044934/go.mod h1:SxQhJskUJ4rleVU44YvnrdvxQr0tKy5SRSigBrCgyyQ=\ngithub.com/robotn/xgb v0.10.0 h1:O3kFbIwtwZ3pgLbp1h5slCQ4OpY8BdwugJLrUe6GPIM=\ngithub.com/robotn/xgb v0.10.0/go.mod h1:SxQhJskUJ4rleVU44YvnrdvxQr0tKy5SRSigBrCgyyQ=\ngithub.com/robotn/xgbutil v0.10.0 h1:gvf7mGQqCWQ68aHRtCxgdewRk+/KAJui6l3MJQQRCKw=\ngithub.com/robotn/xgbutil v0.10.0/go.mod h1:svkDXUDQjUiWzLrA0OZgHc4lbOts3C+uRfP6/yjwYnU=\ngithub.com/shirou/gopsutil/v4 v4.25.10 h1:at8lk/5T1OgtuCp+AwrDofFRjnvosn0nkN2OLQ6g8tA=\ngithub.com/shirou/gopsutil/v4 v4.25.10/go.mod h1:+kSwyC8DRUD9XXEHCAFjK+0nuArFJM0lva+StQAcskM=\ngithub.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=\ngithub.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=\ngithub.com/tailscale/win v0.0.0-20250627215312-f4da2b8ee071 h1:qo7kOhoN5DHioXNlFytBzIoA5glW6lsb8YqV0lP3IyE=\ngithub.com/tailscale/win v0.0.0-20250627215312-f4da2b8ee071/go.mod h1:aMd4yDHLjbOuYP6fMxj1d9ACDQlSWwYztcpybGHCQc8=\ngithub.com/tc-hib/winres v0.2.1 h1:YDE0FiP0VmtRaDn7+aaChp1KiF4owBiJa5l964l5ujA=\ngithub.com/tc-hib/winres v0.2.1/go.mod h1:C/JaNhH3KBvhNKVbvdlDWkbMDO9H4fKKDaN7/07SSuk=\ngithub.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA=\ngithub.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI=\ngithub.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw=\ngithub.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ=\ngithub.com/vcaesar/gops v0.41.0 h1:FG748Jyw3FOuZnbzSgB+CQSx2e5LbLCPWV2JU1brFdc=\ngithub.com/vcaesar/gops v0.41.0/go.mod h1:/3048L7Rj7QjQKTSB+kKc7hDm63YhTWy5QJ10TCP37A=\ngithub.com/vcaesar/imgo v0.41.0 h1:kNLYGrThXhB9Dd6IwFmfPnxq9P6yat2g7dpPjr7OWO8=\ngithub.com/vcaesar/imgo v0.41.0/go.mod h1:/LGOge8etlzaVu/7l+UfhJxR6QqaoX5yeuzGIMfWb4I=\ngithub.com/vcaesar/keycode v0.10.1 h1:0DesGmMAPWpYTCYddOFiCMKCDKgNnwiQa2QXindVUHw=\ngithub.com/vcaesar/keycode v0.10.1/go.mod h1:JNlY7xbKsh+LAGfY2j4M3znVrGEm5W1R8s/Uv6BJcfQ=\ngithub.com/vcaesar/screenshot v0.11.1 h1:GgPuN89XC4Yh38dLx4quPlSo3YiWWhwIria/j3LtrqU=\ngithub.com/vcaesar/screenshot v0.11.1/go.mod h1:gJNwHBiP1v1v7i8TQ4yV1XJtcyn2I/OJL7OziVQkwjs=\ngithub.com/vcaesar/tt v0.20.1 h1:D/jUeeVCNbq3ad8M7hhtB3J9x5RZ6I1n1eZ0BJp7M+4=\ngithub.com/vcaesar/tt v0.20.1/go.mod h1:cH2+AwGAJm19Wa6xvEa+0r+sXDJBT0QgNQey6mwqLeU=\ngithub.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=\ngithub.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=\ngolang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 h1:DHNhtq3sNNzrvduZZIiFyXWOL9IWaDPHqTnLJp+rCBY=\ngolang.org/x/exp v0.0.0-20251125195548-87e1e737ad39/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0=\ngolang.org/x/image v0.33.0 h1:LXRZRnv1+zGd5XBUVRFmYEphyyKJjQjCRiOuAP3sZfQ=\ngolang.org/x/image v0.33.0/go.mod h1:DD3OsTYT9chzuzTQt+zMcOlBHgfoKQb1gry8p76Y1sc=\ngolang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=\ngolang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\n"
  },
  {
    "path": "img.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\npackage robotgo\n\nimport (\n\t\"image\"\n\t\"os/exec\"\n\t\"unsafe\"\n\n\t\"github.com/vcaesar/imgo\"\n)\n\n// DecodeImg decode the image to image.Image and return\nfunc DecodeImg(path string) (image.Image, string, error) {\n\treturn imgo.DecodeFile(path)\n}\n\n// OpenImg open the image return []byte\nfunc OpenImg(path string) ([]byte, error) {\n\treturn imgo.ImgToBytes(path)\n}\n\n// Read read the file return image.Image\nfunc Read(path string) (image.Image, error) {\n\treturn imgo.Read(path)\n}\n\n// Save create a image file with the image.Image\nfunc Save(img image.Image, path string, quality ...int) error {\n\treturn imgo.Save(path, img, quality...)\n}\n\n// SaveImg save the image by []byte\nfunc SaveImg(b []byte, path string) error {\n\treturn imgo.SaveByte(path, b)\n}\n\n// SavePng save the image by image.Image\nfunc SavePng(img image.Image, path string) error {\n\treturn imgo.SaveToPNG(path, img)\n}\n\n// SaveJpeg save the image by image.Image\nfunc SaveJpeg(img image.Image, path string, quality ...int) error {\n\treturn imgo.SaveToJpeg(path, img, quality...)\n}\n\n// ToByteImg convert image.Image to []byte\nfunc ToByteImg(img image.Image, fm ...string) []byte {\n\treturn imgo.ToByte(img, fm...)\n}\n\n// ToStringImg convert image.Image to string\nfunc ToStringImg(img image.Image, fm ...string) string {\n\treturn string(ToByteImg(img, fm...))\n}\n\n// StrToImg convert base64 string to image.Image\nfunc StrToImg(data string) (image.Image, error) {\n\treturn imgo.StrToImg(data)\n}\n\n// ByteToImg convert []byte to image.Image\nfunc ByteToImg(b []byte) (image.Image, error) {\n\treturn imgo.ByteToImg(b)\n}\n\n// ImgSize get the file image size\nfunc ImgSize(path string) (int, int, error) {\n\treturn imgo.GetSize(path)\n}\n\n// Width return the image.Image width\nfunc Width(img image.Image) int {\n\treturn img.Bounds().Max.X\n}\n\n// Height return the image.Image height\nfunc Height(img image.Image) int {\n\treturn img.Bounds().Max.Y\n}\n\n// RGBAToBitmap convert the standard image.RGBA to Bitmap\nfunc RGBAToBitmap(r1 *image.RGBA) (bit Bitmap) {\n\tbit.Width = r1.Bounds().Size().X\n\tbit.Height = r1.Bounds().Size().Y\n\tbit.Bytewidth = r1.Stride\n\n\tsrc := ToUint8p(r1.Pix)\n\tbit.ImgBuf = src\n\n\tbit.BitsPixel = 32\n\tbit.BytesPerPixel = 32 / 8\n\n\treturn\n}\n\n// ImgToBitmap convert the standard image.Image to Bitmap\nfunc ImgToBitmap(m image.Image) (bit Bitmap) {\n\tbit.Width = m.Bounds().Size().X\n\tbit.Height = m.Bounds().Size().Y\n\n\tpix, stride, _ := imgo.EncodeImg(m)\n\tbit.Bytewidth = stride\n\n\tsrc := ToUint8p(pix)\n\tbit.ImgBuf = src\n\t//\n\tbit.BitsPixel = 32\n\tbit.BytesPerPixel = 32 / 8\n\treturn\n}\n\n// ToUint8p convert the []uint8 to uint8 pointer\nfunc ToUint8p(dst []uint8) *uint8 {\n\tsrc := make([]uint8, len(dst)+10)\n\tfor i := 0; i <= len(dst)-4; i += 4 {\n\t\tsrc[i+3] = dst[i+3]\n\t\tsrc[i] = dst[i+2]\n\t\tsrc[i+1] = dst[i+1]\n\t\tsrc[i+2] = dst[i]\n\t}\n\n\tptr := unsafe.Pointer(&src[0])\n\treturn (*uint8)(ptr)\n}\n\n// ToRGBAGo convert Bitmap to standard image.RGBA\nfunc ToRGBAGo(bmp1 Bitmap) *image.RGBA {\n\timg1 := image.NewRGBA(image.Rect(0, 0, bmp1.Width, bmp1.Height))\n\timg1.Pix = make([]uint8, bmp1.Bytewidth*bmp1.Height)\n\n\tcopyToVUint8A(img1.Pix, bmp1.ImgBuf)\n\timg1.Stride = bmp1.Bytewidth\n\treturn img1\n}\n\nfunc val(p *uint8, n int) uint8 {\n\taddr := uintptr(unsafe.Pointer(p))\n\taddr += uintptr(n)\n\tp1 := (*uint8)(unsafe.Pointer(addr))\n\treturn *p1\n}\n\nfunc copyToVUint8A(dst []uint8, src *uint8) {\n\tfor i := 0; i <= len(dst)-4; i += 4 {\n\t\tdst[i] = val(src, i+2)\n\t\tdst[i+1] = val(src, i+1)\n\t\tdst[i+2] = val(src, i)\n\t\tdst[i+3] = val(src, i+3)\n\t}\n}\n\n// GetText get the image text by tesseract ocr\n//\n// robotgo.GetText(imgPath, lang string)\nfunc GetText(imgPath string, args ...string) (string, error) {\n\tvar lang = \"eng\"\n\n\tif len(args) > 0 {\n\t\tlang = args[0]\n\t\tif lang == \"zh\" {\n\t\t\tlang = \"chi_sim\"\n\t\t}\n\t}\n\n\tbody, err := exec.Command(\"tesseract\", imgPath,\n\t\t\"stdout\", \"-l\", lang).Output()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn string(body), nil\n}\n"
  },
  {
    "path": "key/key.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\npackage key\n"
  },
  {
    "path": "key/key_windows.go",
    "content": "//go:build windows\n// +build windows\n\npackage key\n"
  },
  {
    "path": "key/keycode.h",
    "content": "#pragma once\n#ifndef KEYCODE_H\n#define KEYCODE_H\n\n#include \"../base/os.h\"\n\n#if defined(IS_MACOSX)\n\n#include <Carbon/Carbon.h> /* Really only need <HIToolbox/Events.h> */\n#include <ApplicationServices/ApplicationServices.h>\n#import <IOKit/hidsystem/ev_keymap.h>\n\nenum _MMKeyCode {\n\t// a-z, 0-9\n\tK_NOT_A_KEY = 9999,\n\tK_BACKSPACE = kVK_Delete,\n\tK_DELETE = kVK_ForwardDelete,\n\tK_RETURN = kVK_Return,\n\tK_TAB = kVK_Tab,\n\tK_ESCAPE = kVK_Escape,\n\tK_UP = kVK_UpArrow,\n\tK_DOWN = kVK_DownArrow,\n\tK_RIGHT = kVK_RightArrow,\n\tK_LEFT = kVK_LeftArrow,\n\tK_HOME = kVK_Home,\n\tK_END = kVK_End,\n\tK_PAGEUP = kVK_PageUp,\n\tK_PAGEDOWN = kVK_PageDown,\n\n\tK_F1 = kVK_F1,\n\tK_F2 = kVK_F2,\n\tK_F3 = kVK_F3,\n\tK_F4 = kVK_F4,\n\tK_F5 = kVK_F5,\n\tK_F6 = kVK_F6,\n\tK_F7 = kVK_F7,\n\tK_F8 = kVK_F8,\n\tK_F9 = kVK_F9,\n\tK_F10 = kVK_F10,\n\tK_F11 = kVK_F11,\n\tK_F12 = kVK_F12,\n\tK_F13 = kVK_F13,\n\tK_F14 = kVK_F14,\n\tK_F15 = kVK_F15,\n\tK_F16 = kVK_F16,\n\tK_F17 = kVK_F17,\n\tK_F18 = kVK_F18,\n\tK_F19 = kVK_F19,\n\tK_F20 = kVK_F20,\n\tK_F21 = K_NOT_A_KEY,\n\tK_F22 = K_NOT_A_KEY,\n\tK_F23 = K_NOT_A_KEY,\n\tK_F24 = K_NOT_A_KEY,\n\n\tK_META = kVK_Command,\n\tK_LMETA = kVK_Command,\n\tK_RMETA = kVK_RightCommand,\n\tK_ALT = kVK_Option,\n\tK_LALT = kVK_Option,\n\tK_RALT = kVK_RightOption,\n\tK_CONTROL = kVK_Control,\n\tK_LCONTROL = kVK_Control,\n\tK_RCONTROL = kVK_RightControl,\n\tK_SHIFT = kVK_Shift,\n\tK_LSHIFT = kVK_Shift,\n\tK_RSHIFT = kVK_RightShift,\n\tK_CAPSLOCK = kVK_CapsLock,\n\tK_SPACE = kVK_Space,\n\tK_INSERT = kVK_Help,\n\t// K_PRINTSCREEN = K_NOT_A_KEY,\n\tK_PRINTSCREEN = kVK_F13,\n\tK_MENU = K_NOT_A_KEY,\n\n\tK_NUMPAD_0 = kVK_ANSI_Keypad0,\n\tK_NUMPAD_1 = kVK_ANSI_Keypad1,\n\tK_NUMPAD_2 = kVK_ANSI_Keypad2,\n\tK_NUMPAD_3 = kVK_ANSI_Keypad3,\n\tK_NUMPAD_4 = kVK_ANSI_Keypad4,\n\tK_NUMPAD_5 = kVK_ANSI_Keypad5,\n\tK_NUMPAD_6 = kVK_ANSI_Keypad6,\n\tK_NUMPAD_7 = kVK_ANSI_Keypad7,\n\tK_NUMPAD_8 = kVK_ANSI_Keypad8,\n\tK_NUMPAD_9 = kVK_ANSI_Keypad9,\n\tK_NUMPAD_LOCK = kVK_ANSI_KeypadClear,\n\t//\n\tK_NUMPAD_DECIMAL = kVK_ANSI_KeypadDecimal,\n\tK_NUMPAD_PLUS    = kVK_ANSI_KeypadPlus,\n\tK_NUMPAD_MINUS   = kVK_ANSI_KeypadMinus,\n\tK_NUMPAD_MUL     = kVK_ANSI_KeypadMultiply,\n\tK_NUMPAD_DIV     = kVK_ANSI_KeypadDivide,\n\tK_NUMPAD_CLEAR   = kVK_ANSI_KeypadClear,\n\tK_NUMPAD_ENTER   = kVK_ANSI_KeypadEnter,\n\tK_NUMPAD_EQUAL   = kVK_ANSI_KeypadEquals,\n\tK_NUMPAD_LB \t = kVK_ANSI_LeftBracket,\n\tK_NUMPAD_RB \t = kVK_ANSI_RightBracket,\n\tK_Backslash\t \t = kVK_ANSI_Backslash,\n\tK_Semicolon\t\t = kVK_ANSI_Semicolon,\n\tK_Quote\t\t\t = kVK_ANSI_Quote,\n\tK_Slash\t\t\t = kVK_ANSI_Slash,\n\tK_Grave\t\t\t = kVK_ANSI_Grave,\n\n\tK_AUDIO_VOLUME_MUTE = 1007,\n\tK_AUDIO_VOLUME_DOWN = 1001,\n\tK_AUDIO_VOLUME_UP = 1000,\n\tK_AUDIO_PLAY = 1016,\n\tK_AUDIO_STOP = K_NOT_A_KEY,\n\tK_AUDIO_PAUSE = 1016,\n\tK_AUDIO_PREV = 1018,\n\tK_AUDIO_NEXT = 1017,\n\tK_AUDIO_REWIND = K_NOT_A_KEY,\n\tK_AUDIO_FORWARD = K_NOT_A_KEY,\n\tK_AUDIO_REPEAT = K_NOT_A_KEY,\n\tK_AUDIO_RANDOM = K_NOT_A_KEY,\n\n\tK_LIGHTS_MON_UP = 1002,\n\tK_LIGHTS_MON_DOWN = 1003,\n\tK_LIGHTS_KBD_TOGGLE = 1023,\n\tK_LIGHTS_KBD_UP = 1021,\n\tK_LIGHTS_KBD_DOWN = 1022\n};\n\ntypedef CGKeyCode MMKeyCode;\n\n#elif defined(USE_X11)\n\n#include <X11/Xutil.h>\n#include <X11/XF86keysym.h>\n\nenum _MMKeyCode {\n\tK_NOT_A_KEY = 9999,\n\tK_BACKSPACE = XK_BackSpace,\n\tK_DELETE = XK_Delete,\n\tK_RETURN = XK_Return,\n\tK_TAB = XK_Tab,\n\tK_ESCAPE = XK_Escape,\n\tK_UP = XK_Up,\n\tK_DOWN = XK_Down,\n\tK_RIGHT = XK_Right,\n\tK_LEFT = XK_Left,\n\tK_HOME = XK_Home,\n\tK_END = XK_End,\n\tK_PAGEUP = XK_Page_Up,\n\tK_PAGEDOWN = XK_Page_Down,\n\n\tK_F1 = XK_F1,\n\tK_F2 = XK_F2,\n\tK_F3 = XK_F3,\n\tK_F4 = XK_F4,\n\tK_F5 = XK_F5,\n\tK_F6 = XK_F6,\n\tK_F7 = XK_F7,\n\tK_F8 = XK_F8,\n\tK_F9 = XK_F9,\n\tK_F10 = XK_F10,\n\tK_F11 = XK_F11,\n\tK_F12 = XK_F12,\n\tK_F13 = XK_F13,\n\tK_F14 = XK_F14,\n\tK_F15 = XK_F15,\n\tK_F16 = XK_F16,\n\tK_F17 = XK_F17,\n\tK_F18 = XK_F18,\n\tK_F19 = XK_F19,\n\tK_F20 = XK_F20,\n\tK_F21 = XK_F21,\n\tK_F22 = XK_F22,\n\tK_F23 = XK_F23,\n\tK_F24 = XK_F24,\n\n\tK_META = XK_Super_L,\n\tK_LMETA = XK_Super_L,\n\tK_RMETA = XK_Super_R,\n\tK_ALT = XK_Alt_L,\n\tK_LALT = XK_Alt_L,\n\tK_RALT = XK_Alt_R,\n\tK_CONTROL = XK_Control_L,\n\tK_LCONTROL = XK_Control_L,\n\tK_RCONTROL = XK_Control_R,\n\tK_SHIFT = XK_Shift_L,\n\tK_LSHIFT = XK_Shift_L,\n\tK_RSHIFT = XK_Shift_R,\n\tK_CAPSLOCK = XK_Caps_Lock,\n\tK_SPACE = XK_space,\n\tK_INSERT = XK_Insert,\n\tK_PRINTSCREEN = XK_Print,\n\tK_MENU = K_NOT_A_KEY,\n\n\t// K_NUMPAD_0 = K_NOT_A_KEY,\n\tK_NUMPAD_0 = XK_KP_0,\n\tK_NUMPAD_1 = XK_KP_1,\n\tK_NUMPAD_2 = XK_KP_2,\n\tK_NUMPAD_3 = XK_KP_3,\n\tK_NUMPAD_4 = XK_KP_4,\n\tK_NUMPAD_5 = XK_KP_5,\n\tK_NUMPAD_6 = XK_KP_6,\n\tK_NUMPAD_7 = XK_KP_7,\n\tK_NUMPAD_8 = XK_KP_8,\n\tK_NUMPAD_9 = XK_KP_9,\n\tK_NUMPAD_LOCK = XK_Num_Lock,\n\t//\n\tK_NUMPAD_DECIMAL = XK_KP_Decimal,\n\tK_NUMPAD_PLUS    = 78,  // XK_KP_Add\n\tK_NUMPAD_MINUS   = 74,  // XK_KP_Subtract\n\tK_NUMPAD_MUL     = 55,\t// XK_KP_Multiply\n\tK_NUMPAD_DIV     = 98,\t// XK_KP_Divide\n\tK_NUMPAD_CLEAR   = K_NOT_A_KEY,\n\tK_NUMPAD_ENTER   = 96,\t// XK_KP_Enter\n\tK_NUMPAD_EQUAL   = XK_equal,\n\tK_NUMPAD_LB \t = XK_bracketleft,\n\tK_NUMPAD_RB \t = XK_bracketright,\n\tK_Backslash \t = XK_backslash,\n\tK_Semicolon \t = XK_semicolon,\n\tK_Quote\t\t\t = XK_apostrophe,\n\tK_Slash\t\t\t = XK_slash,\n\tK_Grave\t\t\t = XK_grave,\n\n\tK_AUDIO_VOLUME_MUTE = XF86XK_AudioMute,\n\tK_AUDIO_VOLUME_DOWN = XF86XK_AudioLowerVolume,\n\tK_AUDIO_VOLUME_UP = XF86XK_AudioRaiseVolume,\n\tK_AUDIO_PLAY = XF86XK_AudioPlay,\n\tK_AUDIO_STOP = XF86XK_AudioStop,\n\tK_AUDIO_PAUSE = XF86XK_AudioPause,\n\tK_AUDIO_PREV = XF86XK_AudioPrev,\n\tK_AUDIO_NEXT = XF86XK_AudioNext,\n\tK_AUDIO_REWIND = XF86XK_AudioRewind,\n\tK_AUDIO_FORWARD = XF86XK_AudioForward,\n\tK_AUDIO_REPEAT = XF86XK_AudioRepeat,\n\tK_AUDIO_RANDOM = XF86XK_AudioRandomPlay,\n\n\tK_LIGHTS_MON_UP = XF86XK_MonBrightnessUp,\n\tK_LIGHTS_MON_DOWN = XF86XK_MonBrightnessDown,\n\tK_LIGHTS_KBD_TOGGLE = XF86XK_KbdLightOnOff,\n\tK_LIGHTS_KBD_UP = XF86XK_KbdBrightnessUp,\n\tK_LIGHTS_KBD_DOWN = XF86XK_KbdBrightnessDown\n};\n\ntypedef KeySym MMKeyCode;\n\n/*\n * Structs to store key mappings not handled by XStringToKeysym() on some\n * Linux systems.\n */\nstruct XSpecialCharacterMapping {\n\tchar name;\n\tMMKeyCode code;\n};\n\nstruct XSpecialCharacterMapping XSpecialCharacterTable[] = {\n\t{'~', XK_asciitilde},\n  \t{'_', XK_underscore},\n  \t{'[', XK_bracketleft},\n  \t{']', XK_bracketright},\n  \t{'!', XK_exclam},\n  \t{'#', XK_numbersign},\n  \t{'$', XK_dollar},\n  \t{'%', XK_percent},\n  \t{'&', XK_ampersand},\n  \t{'*', XK_asterisk},\n  \t{'+', XK_plus},\n  \t{',', XK_comma},\n  \t{'-', XK_minus},\n  \t{'.', XK_period},\n  \t{'?', XK_question},\n  \t{'<', XK_less},\n  \t{'>', XK_greater},\n  \t{'=', XK_equal},\n  \t{'@', XK_at},\n  \t{':', XK_colon},\n  \t{';', XK_semicolon},\n  \t{'{', XK_braceleft},\n  \t{'}', XK_braceright},\n  \t{'|', XK_bar},\n  \t{'^', XK_asciicircum},\n  \t{'(', XK_parenleft},\n  \t{')', XK_parenright},\n  \t{' ', XK_space},\n  \t{'/', XK_slash},\n\t{'\\\\', XK_backslash},\n\t{'`', XK_grave},\n\t{'\"', XK_quoteright},\n  \t{'\\'', XK_quotedbl},\n  \t{'\\t', XK_Tab},\n  \t{'\\n', XK_Return}\n};\n\n#elif defined(IS_WINDOWS)\n\nenum _MMKeyCode {\n\tK_NOT_A_KEY = 9999,\n\tK_BACKSPACE = VK_BACK,\n\tK_DELETE = VK_DELETE,\n\tK_RETURN = VK_RETURN,\n\tK_TAB = VK_TAB,\n\tK_ESCAPE = VK_ESCAPE,\n\tK_UP = VK_UP,\n\tK_DOWN = VK_DOWN,\n\tK_RIGHT = VK_RIGHT,\n\tK_LEFT = VK_LEFT,\n\tK_HOME = VK_HOME,\n\tK_END = VK_END,\n\tK_PAGEUP = VK_PRIOR,\n\tK_PAGEDOWN = VK_NEXT,\n\n\tK_F1 = VK_F1,\n\tK_F2 = VK_F2,\n\tK_F3 = VK_F3,\n\tK_F4 = VK_F4,\n\tK_F5 = VK_F5,\n\tK_F6 = VK_F6,\n\tK_F7 = VK_F7,\n\tK_F8 = VK_F8,\n\tK_F9 = VK_F9,\n\tK_F10 = VK_F10,\n\tK_F11 = VK_F11,\n\tK_F12 = VK_F12,\n\tK_F13 = VK_F13,\n\tK_F14 = VK_F14,\n\tK_F15 = VK_F15,\n\tK_F16 = VK_F16,\n\tK_F17 = VK_F17,\n\tK_F18 = VK_F18,\n\tK_F19 = VK_F19,\n\tK_F20 = VK_F20,\n\tK_F21 = VK_F21,\n\tK_F22 = VK_F22,\n\tK_F23 = VK_F23,\n\tK_F24 = VK_F24,\n\n\tK_META = VK_LWIN,\n\tK_LMETA = VK_LWIN,\n\tK_RMETA = VK_RWIN,\n\tK_ALT = VK_MENU,\n\tK_LALT = VK_LMENU,\n\tK_RALT = VK_RMENU,\n\tK_CONTROL = VK_CONTROL,\n\tK_LCONTROL  = VK_LCONTROL,\n\tK_RCONTROL  = VK_RCONTROL,\n\tK_SHIFT = VK_SHIFT,\n\tK_LSHIFT = VK_LSHIFT,\n\tK_RSHIFT = VK_RSHIFT,\n\tK_CAPSLOCK = VK_CAPITAL,\n\tK_SPACE = VK_SPACE,\n\tK_PRINTSCREEN = VK_SNAPSHOT,\n\tK_INSERT = VK_INSERT,\n\tK_MENU = VK_APPS,\n\n\tK_NUMPAD_0 = VK_NUMPAD0,\n\tK_NUMPAD_1 = VK_NUMPAD1,\n\tK_NUMPAD_2 = VK_NUMPAD2,\n\tK_NUMPAD_3 = VK_NUMPAD3,\n\tK_NUMPAD_4 = VK_NUMPAD4,\n\tK_NUMPAD_5 = VK_NUMPAD5,\n\tK_NUMPAD_6 = VK_NUMPAD6,\n\tK_NUMPAD_7 = VK_NUMPAD7,\n\tK_NUMPAD_8 = VK_NUMPAD8,\n\tK_NUMPAD_9 = VK_NUMPAD9,\n\tK_NUMPAD_LOCK = VK_NUMLOCK,\n\t// VK_NUMPAD_\n\tK_NUMPAD_DECIMAL = VK_DECIMAL,\n\tK_NUMPAD_PLUS    = VK_ADD,\n\tK_NUMPAD_MINUS   = VK_SUBTRACT,\n\tK_NUMPAD_MUL     = VK_MULTIPLY,\n\tK_NUMPAD_DIV     = VK_DIVIDE,\n\tK_NUMPAD_CLEAR   = K_NOT_A_KEY,\n\tK_NUMPAD_ENTER   = VK_RETURN,\n\tK_NUMPAD_EQUAL   = VK_OEM_PLUS,\n\tK_NUMPAD_LB\t\t = VK_OEM_4,\n\tK_NUMPAD_RB\t\t = VK_OEM_6,\n\tK_Backslash\t\t = VK_OEM_5,\n\tK_Semicolon\t\t = VK_OEM_1,\n\tK_Quote\t\t \t = VK_OEM_7,\n\tK_Slash\t\t\t = VK_OEM_2,\n\tK_Grave\t\t\t = VK_OEM_3,\n\n\tK_AUDIO_VOLUME_MUTE = VK_VOLUME_MUTE,\n\tK_AUDIO_VOLUME_DOWN = VK_VOLUME_DOWN,\n\tK_AUDIO_VOLUME_UP = VK_VOLUME_UP,\n\tK_AUDIO_PLAY = VK_MEDIA_PLAY_PAUSE,\n\tK_AUDIO_STOP = VK_MEDIA_STOP,\n\tK_AUDIO_PAUSE = VK_MEDIA_PLAY_PAUSE,\n\tK_AUDIO_PREV = VK_MEDIA_PREV_TRACK,\n\tK_AUDIO_NEXT = VK_MEDIA_NEXT_TRACK,\n\tK_AUDIO_REWIND = K_NOT_A_KEY,\n\tK_AUDIO_FORWARD = K_NOT_A_KEY,\n\tK_AUDIO_REPEAT = K_NOT_A_KEY,\n\tK_AUDIO_RANDOM = K_NOT_A_KEY,\n\n\tK_LIGHTS_MON_UP = K_NOT_A_KEY,\n\tK_LIGHTS_MON_DOWN = K_NOT_A_KEY,\n\tK_LIGHTS_KBD_TOGGLE = K_NOT_A_KEY,\n\tK_LIGHTS_KBD_UP = K_NOT_A_KEY,\n\tK_LIGHTS_KBD_DOWN = K_NOT_A_KEY\n};\n\ntypedef int MMKeyCode;\n\n#endif\n\n/* Returns the keyCode corresponding to the current keyboard layout for the\n * given ASCII character. */\nMMKeyCode keyCodeForChar(const char c);\n\n#endif /* KEYCODE_H */\n"
  },
  {
    "path": "key/keycode_c.h",
    "content": "#include \"keycode.h\"\n\n#if defined(IS_MACOSX)\n\t#include <CoreFoundation/CoreFoundation.h>\n\t#include <Carbon/Carbon.h> /* For kVK_ constants, and TIS functions. */\n\n\t/* Returns string representation of key, if it is printable. \n\tOwnership follows the Create Rule; \n\tit is the caller's responsibility to release the returned object. */\n\tCFStringRef createStringForKey(CGKeyCode keyCode);\n#endif\n\nMMKeyCode keyCodeForChar(const char c) {\n\t#if defined(IS_MACOSX)\n\t\t/* OS X does not appear to have a built-in function for this, \n\t\tso instead it to write our own. */\n\t\tstatic CFMutableDictionaryRef charToCodeDict = NULL;\n\t\tCGKeyCode code;\n\t\tUniChar character = c;\n\t\tCFStringRef charStr = NULL;\n\n\t\t/* Generate table of keycodes and characters. */\n\t\tif (charToCodeDict == NULL) {\n\t\t\tsize_t i;\n\t\t\tcharToCodeDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 128,\n\t\t\t\t&kCFCopyStringDictionaryKeyCallBacks, NULL);\n\t\t\tif (charToCodeDict == NULL) { return K_NOT_A_KEY; }\n\n\t\t\t/* Loop through every keycode (0 - 127) to find its current mapping. */\n\t\t\tfor (i = 0; i < 128; ++i) {\n\t\t\t\tCFStringRef string = createStringForKey((CGKeyCode)i);\n\t\t\t\tif (string != NULL) {\n\t\t\t\t\tCFDictionaryAddValue(charToCodeDict, string, (const void *)i);\n\t\t\t\t\tCFRelease(string);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tcharStr = CFStringCreateWithCharacters(kCFAllocatorDefault, &character, 1);\n\t\t/* Our values may be NULL (0), so we need to use this function. */\n\t\t/* Use pointer-sized variable to avoid stack overflow on 64-bit systems */\n\t\tconst void *codePtr = NULL;\n\t\tif (!CFDictionaryGetValueIfPresent(charToCodeDict, charStr, &codePtr)) {\n\t\t\tcode = UINT16_MAX; /* Error */\n\t\t} else {\n\t\t\tcode = (CGKeyCode)(uintptr_t)codePtr;\n\t\t}\n\t\tCFRelease(charStr);\n\n\t\t// TISGetInputSourceProperty may return nil so we need fallback\n\t\tif (code == UINT16_MAX) {\n\t\t\treturn K_NOT_A_KEY;\n\t\t}\n\n\t\treturn (MMKeyCode)code;\n\t#elif defined(IS_WINDOWS)\n\t\tMMKeyCode code;\n\t\tcode = VkKeyScan(c);\n\t\tif (code == 0xFFFF) {\n\t\t\treturn K_NOT_A_KEY;\n\t\t}\n\n\t\treturn code;\n\t#elif defined(USE_X11)\n\t\tchar buf[2];\n\t\tbuf[0] = c;\n\t\tbuf[1] = '\\0';\n\n\t\tMMKeyCode code = XStringToKeysym(buf);\n\t\tif (code == NoSymbol) {\n\t\t\t/* Some special keys are apparently not handled properly */\n\t\t\tstruct XSpecialCharacterMapping* xs = XSpecialCharacterTable;\n\t\t\twhile (xs->name) {\n\t\t\t\tif (c == xs->name) {\n\t\t\t\t\tcode = xs->code;\n\t\t\t\t\t// \n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\txs++;\n\t\t\t}\n\t\t}\n\n\t\tif (code == NoSymbol) {\n\t\t\treturn K_NOT_A_KEY;\n\t\t}\n\n\t\t// x11 key bug\n\t\tif (c == 60) {\n\t\t\tcode = 44;\n\t\t}\n\t\treturn code;\n\t#endif\n}\n\n#if defined(IS_MACOSX)\n\tCFStringRef createStringForKey(CGKeyCode keyCode){\n\t\t// TISInputSourceRef currentKeyboard = TISCopyCurrentASCIICapableKeyboardInputSource();\n\t\tTISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardLayoutInputSource();\n\n\t\t/* Check if currentKeyboard is NULL to avoid crash */\n\t\tif (currentKeyboard == NULL) { return NULL; }\n\n\t\tCFDataRef layoutData = (CFDataRef) TISGetInputSourceProperty(\n\t\t\tcurrentKeyboard, kTISPropertyUnicodeKeyLayoutData);\n\n\t\tif (layoutData == nil) {\n\t\t\tCFRelease(currentKeyboard);  /* Fix memory leak */\n\t\t\treturn NULL;\n\t\t}\n\n\t\tconst UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *) CFDataGetBytePtr(layoutData);\n\t\tUInt32 keysDown = 0;\n\t\tUniChar chars[4];\n\t\tUniCharCount realLength;\n\n\t\tUCKeyTranslate(keyboardLayout, keyCode, kUCKeyActionDisplay, 0, LMGetKbdType(),\n\t\t\t\t\tkUCKeyTranslateNoDeadKeysBit, &keysDown,\n\t\t\t\t\tsizeof(chars) / sizeof(chars[0]), &realLength, chars);\n\t\tCFRelease(currentKeyboard);\n\n\t\treturn CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1);\n\t}\n#endif\n"
  },
  {
    "path": "key/keypress.h",
    "content": "#pragma once\n#ifndef KEYPRESS_H\n#define KEYPRESS_H\n\n#include <stdlib.h>\n#include \"../base/os.h\"\n#include \"../base/types.h\"\n\n#include \"keycode.h\"\n#include <stdbool.h>\n\n#if defined(IS_MACOSX)\n\ttypedef enum {\n\t\tMOD_NONE = 0,\n\t\tMOD_META = kCGEventFlagMaskCommand,\n\t\tMOD_ALT = kCGEventFlagMaskAlternate,\n\t\tMOD_CONTROL = kCGEventFlagMaskControl,\n\t\tMOD_SHIFT = kCGEventFlagMaskShift\n\t} MMKeyFlags;\n#elif defined(USE_X11)\n\tenum _MMKeyFlags {\n\t\tMOD_NONE = 0,\n\t\tMOD_META = Mod4Mask,\n\t\tMOD_ALT = Mod1Mask,\n\t\tMOD_CONTROL = ControlMask,\n\t\tMOD_SHIFT = ShiftMask\n\t};\n\ttypedef unsigned int MMKeyFlags;\n#elif defined(IS_WINDOWS)\n\tenum _MMKeyFlags {\n\t\tMOD_NONE = 0,\n\t\t/* These are already defined by the Win32 API */\n\t\t/* MOD_ALT = 0,\n\t\tMOD_CONTROL = 0,\n\t\tMOD_SHIFT = 0, */\n\t\tMOD_META = MOD_WIN\n\t};\n\ttypedef unsigned int MMKeyFlags;\n#endif\n\n#if defined(IS_WINDOWS)\n\t/* Send win32 key event for given key. */\n\tvoid win32KeyEvent(int key, MMKeyFlags flags, uintptr pid, int8_t isPid);\n#endif\n\n#endif /* KEYPRESS_H */\n"
  },
  {
    "path": "key/keypress_c.h",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n// \n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0> \n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\n#include \"../base/deadbeef_rand_c.h\"\n#include \"../base/microsleep.h\"\n#include \"keypress.h\"\n#include \"keycode_c.h\"\n\n#include <ctype.h> /* For isupper() */\n#if defined(IS_MACOSX)\n\t#include <ApplicationServices/ApplicationServices.h>\n\t#import <IOKit/hidsystem/IOHIDLib.h>\n\t#import <IOKit/hidsystem/ev_keymap.h>\n#elif defined(USE_X11)\n\t#include <X11/extensions/XTest.h>\n\t// #include \"../base/xdisplay_c.h\"\n#endif\n\n/* Convenience wrappers around ugly APIs. */\n#if defined(IS_WINDOWS)\n\tHWND GetHwndByPid(DWORD dwProcessId);\n\n\tHWND getHwnd(uintptr pid, int8_t isPid) { \n\t\tHWND hwnd = (HWND) pid;\n\t\tif (isPid == 0) { \n\t\t\thwnd = GetHwndByPid(pid);\n\t\t}\n\t\treturn hwnd;\t\n\t}\n\n\tvoid WIN32_KEY_EVENT_WAIT(MMKeyCode key, DWORD flags, uintptr pid) {\n\t\twin32KeyEvent(key, flags, pid, 0); \n\t\tSleep(DEADBEEF_RANDRANGE(0, 1));\n\t}\n#elif defined(USE_X11)\n\tDisplay *XGetMainDisplay(void);\n\n\tvoid X_KEY_EVENT(Display *display, MMKeyCode key, bool is_press) {\n\t\tXTestFakeKeyEvent(display, XKeysymToKeycode(display, key), is_press, CurrentTime); \n\t\tXSync(display, false);\n\t}\n\n\tvoid X_KEY_EVENT_WAIT(Display *display, MMKeyCode key, bool is_press) {\n\t\tX_KEY_EVENT(display, key, is_press);\n\t\tmicrosleep(DEADBEEF_UNIFORM(0.0, 0.5));\n\t}\n#endif\n\n#if defined(IS_MACOSX)\n\tint SendTo(uintptr pid, CGEventRef event) {\n\t\tif (pid != 0) {\n\t\t\tCGEventPostToPid(pid, event);\n\t\t} else {\n\t\t\tCGEventPost(kCGHIDEventTap, event);\n\t\t}\n\t\t\n\t\tCFRelease(event);\n\t\treturn 0;\n\t}\n\n\tstatic io_connect_t _getAuxiliaryKeyDriver(void) {\n\t\tstatic mach_port_t sEventDrvrRef = 0;\n\t\tmach_port_t masterPort, service, iter;\n\t\tkern_return_t kr;\n\n\t\tif (!sEventDrvrRef) {\n\t\t\tkr = IOMasterPort(bootstrap_port, &masterPort);\n\t\t\tassert(KERN_SUCCESS == kr);\n\t\t\tkr = IOServiceGetMatchingServices(masterPort, IOServiceMatching(kIOHIDSystemClass), &iter);\n\t\t\tassert(KERN_SUCCESS == kr);\n\n\t\t\tservice = IOIteratorNext(iter);\n\t\t\tassert(service);\n\n\t\t\tkr = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType, &sEventDrvrRef);\n\t\t\tassert(KERN_SUCCESS == kr);\n\n\t\t\tIOObjectRelease(service);\n\t\t\tIOObjectRelease(iter);\n\t\t}\n\t\treturn sEventDrvrRef;\n\t}\n#elif defined(IS_WINDOWS)\n\n\tvoid win32KeyEvent(int key, MMKeyFlags flags, uintptr pid, int8_t isPid) {\n\t\tint scan = MapVirtualKey(key & 0xff, MAPVK_VK_TO_VSC);\n\n\t\t/* Set the scan code for extended keys */\n\t\tswitch (key){\n\t\t\tcase VK_RCONTROL:\n\t\t\tcase VK_SNAPSHOT: /* Print Screen */\n\t\t\tcase VK_RMENU: /* Right Alt / Alt Gr */\n\t\t\tcase VK_PAUSE: /* Pause / Break */\n\t\t\tcase VK_HOME:\n\t\t\tcase VK_UP:\n\t\t\tcase VK_PRIOR: /* Page up */\n\t\t\tcase VK_LEFT:\n\t\t\tcase VK_RIGHT:\n\t\t\tcase VK_END:\n\t\t\tcase VK_DOWN:\n\t\t\tcase VK_NEXT: /* 'Page Down' */\n\t\t\tcase VK_INSERT:\n\t\t\tcase VK_DELETE:\n\t\t\tcase VK_LWIN:\n\t\t\tcase VK_RWIN:\n\t\t\tcase VK_APPS: /* Application */\n\t\t\tcase VK_VOLUME_MUTE:\n\t\t\tcase VK_VOLUME_DOWN:\n\t\t\tcase VK_VOLUME_UP:\n\t\t\tcase VK_MEDIA_NEXT_TRACK:\n\t\t\tcase VK_MEDIA_PREV_TRACK:\n\t\t\tcase VK_MEDIA_STOP:\n\t\t\tcase VK_MEDIA_PLAY_PAUSE:\n\t\t\tcase VK_BROWSER_BACK:\n\t\t\tcase VK_BROWSER_FORWARD:\n\t\t\tcase VK_BROWSER_REFRESH:\n\t\t\tcase VK_BROWSER_STOP:\n\t\t\tcase VK_BROWSER_SEARCH:\n\t\t\tcase VK_BROWSER_FAVORITES:\n\t\t\tcase VK_BROWSER_HOME:\n\t\t\tcase VK_LAUNCH_MAIL:\n\t\t\t{\n\t\t\t\tflags |= KEYEVENTF_EXTENDEDKEY;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// todo: test this\n\t\tif (pid != 0) {\n\t\t\tHWND hwnd = getHwnd(pid, isPid);\n\n\t\t\tint down = (flags == 0 ? WM_KEYDOWN : WM_KEYUP);\n\t\t\t// SendMessage(hwnd, down, key, 0);\n\t\t\tPostMessageW(hwnd, down, key, 0);\n\t\t\treturn;\n\t\t}\n\n\t\t/* Set the scan code for keyup */\n\t\t// if ( flags & KEYEVENTF_KEYUP ) {\n\t\t// \tscan |= 0x80;\n\t\t// }\n\t\t// keybd_event(key, scan, flags, 0);\n\t\t\n\t\tINPUT keyInput;\n\n\t\tkeyInput.type = INPUT_KEYBOARD;\n\t\tkeyInput.ki.wVk = key;\n\t\tkeyInput.ki.wScan = scan;\n\t\tkeyInput.ki.dwFlags = flags;\n\t\tkeyInput.ki.time = 0;\n\t\tkeyInput.ki.dwExtraInfo = 0;\n\t\tSendInput(1, &keyInput, sizeof(keyInput));\n\t}\n#endif\n\nvoid toggleKeyCode(MMKeyCode code, const bool down, MMKeyFlags flags, uintptr pid) {\n#if defined(IS_MACOSX)\n\t/* The media keys all have 1000 added to them to help us detect them. */\n\tif (code >= 1000) {\n\t\tcode = code - 1000; /* Get the real keycode. */\n\t\tNXEventData event;\n\t\tkern_return_t kr;\n\n\t\tIOGPoint loc = { 0, 0 };\n\t\tUInt32 evtInfo = code << 16 | (down?NX_KEYDOWN:NX_KEYUP) << 8;\n\n\t\tbzero(&event, sizeof(NXEventData));\n\t\tevent.compound.subType = NX_SUBTYPE_AUX_CONTROL_BUTTONS;\n\t\tevent.compound.misc.L[0] = evtInfo;\n\n\t\tkr = IOHIDPostEvent(_getAuxiliaryKeyDriver(), \n\t\t\t\t\t\t\t\tNX_SYSDEFINED, loc, &event, kNXEventDataVersion, 0, FALSE);\n\t\tassert(KERN_SUCCESS == kr);\n\t} else {\n\t\tCGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);\n\t\tCGEventRef keyEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode)code, down);\n\t\tassert(keyEvent != NULL);\n\n\t\tCGEventSetType(keyEvent, down ? kCGEventKeyDown : kCGEventKeyUp);\n\t\tif (flags != 0) {\n\t\t\tCGEventSetFlags(keyEvent, (CGEventFlags) flags);\n\t\t}\n\t\t\n\t\tSendTo(pid, keyEvent);\n\t\tCFRelease(source);\n\t}\n#elif defined(IS_WINDOWS)\n\tconst DWORD dwFlags = down ? 0 : KEYEVENTF_KEYUP;\n\n\t/* Parse modifier keys. */\n\tif (flags & MOD_META) { WIN32_KEY_EVENT_WAIT(K_META, dwFlags, pid); }\n\tif (flags & MOD_ALT) { WIN32_KEY_EVENT_WAIT(K_ALT, dwFlags, pid); }\n\tif (flags & MOD_CONTROL) { WIN32_KEY_EVENT_WAIT(K_CONTROL, dwFlags, pid); }\n\tif (flags & MOD_SHIFT) { WIN32_KEY_EVENT_WAIT(K_SHIFT, dwFlags, pid); }\n\n\twin32KeyEvent(code, dwFlags, pid, 0);\n#elif defined(USE_X11)\n\tDisplay *display = XGetMainDisplay();\n\tconst Bool is_press = down ? True : False; /* Just to be safe. */\n\n\t/* Parse modifier keys. */\n\tif (flags & MOD_META) { X_KEY_EVENT_WAIT(display, K_META, is_press); }\n\tif (flags & MOD_ALT) { X_KEY_EVENT_WAIT(display, K_ALT, is_press); }\n\tif (flags & MOD_CONTROL) { X_KEY_EVENT_WAIT(display, K_CONTROL, is_press); }\n\tif (flags & MOD_SHIFT) { X_KEY_EVENT_WAIT(display, K_SHIFT, is_press); }\n\n\tX_KEY_EVENT(display, code, is_press);\n#endif\n}\n\n// void tapKeyCode(MMKeyCode code, MMKeyFlags flags){\n// \ttoggleKeyCode(code, true, flags);\n// \tmicrosleep(5.0);\n// \ttoggleKeyCode(code, false, flags);\n// }\n\n#if defined(USE_X11)\n\tbool toUpper(char c) {\n\t\tif (isupper(c)) {\n\t\t\treturn true;\n\t\t}\n\n\t\tchar *special = \"~!@#$%^&*()_+{}|:\\\"<>?\";\n\t\twhile (*special) {\n\t\t\tif (*special == c) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tspecial++;\n\t\t}\n\t\treturn false;\n\t}\n#endif\n\nvoid toggleKey(char c, const bool down, MMKeyFlags flags, uintptr pid) {\n\tMMKeyCode keyCode = keyCodeForChar(c);\n\n\t#if defined(USE_X11)\n\t\tif (toUpper(c) && !(flags & MOD_SHIFT)) {\n\t\t\tflags |= MOD_SHIFT; /* Not sure if this is safe for all layouts. */\n\t\t}\n\t#else\n\t\tif (isupper(c) && !(flags & MOD_SHIFT)) {\n\t\t\tflags |= MOD_SHIFT; /* Not sure if this is safe for all layouts. */\n\t\t}\n\t#endif\n\n\t#if defined(IS_WINDOWS)\n\t\tint modifiers = keyCode >> 8; // Pull out modifers.\n\n\t\tif ((modifiers & 1) != 0) { flags |= MOD_SHIFT; } // Uptdate flags from keycode modifiers.\n\t\tif ((modifiers & 2) != 0) { flags |= MOD_CONTROL; }\n\t\tif ((modifiers & 4) != 0) { flags |= MOD_ALT; }\n\t\tkeyCode = keyCode & 0xff; // Mask out modifiers.\n\t#endif\n\n\ttoggleKeyCode(keyCode, down, flags, pid);\n}\n\n// void tapKey(char c, MMKeyFlags flags){\n// \ttoggleKey(c, true, flags);\n// \tmicrosleep(5.0);\n// \ttoggleKey(c, false, flags);\n// }\n\n#if defined(IS_MACOSX)\n\tvoid toggleUnicode(UniChar ch, const bool down, uintptr pid) {\n\t\t/* This function relies on the convenient CGEventKeyboardSetUnicodeString(), \n\t\tconvert characters to a keycode, but does not support adding modifier flags. \n\t\tIt is only used in typeString().\n\t\t-- if you need modifier keys, use the above functions instead. */\n\t\tCGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);\n\t\tCGEventRef keyEvent = CGEventCreateKeyboardEvent(source, 0, down);\n\t\tif (keyEvent == NULL) {\n\t\t\tfputs(\"Could not create keyboard event.\\n\", stderr);\n\t\t\treturn;\n\t\t}\n\n\t\tCGEventKeyboardSetUnicodeString(keyEvent, 1, &ch);\n\n\t\tSendTo(pid, keyEvent);\n\t\tCFRelease(source);\n\t}\n#else\n\t#define toggleUniKey(c, down) toggleKey(c, down, MOD_NONE, 0)\n#endif\n\n// unicode type\nvoid unicodeType(const unsigned value, uintptr pid, int8_t isPid) {\n\t#if defined(IS_MACOSX)\n\t\tUniChar ch = (UniChar)value; // Convert to unsigned char\n\n\t\ttoggleUnicode(ch, true, pid);\n\t\tmicrosleep(5.0);\n\t\ttoggleUnicode(ch, false, pid);\n\t#elif defined(IS_WINDOWS)\n\t\tif (pid != 0) {\n\t\t\tHWND hwnd = getHwnd(pid, isPid);\n\n\t\t\t// SendMessage(hwnd, down, value, 0);\n\t\t\tPostMessageW(hwnd, WM_CHAR, value, 0);\n\t\t\treturn;\n\t\t}\n\n\t\tINPUT input[2];\n        memset(input, 0, sizeof(input));\n\n        input[0].type = INPUT_KEYBOARD;\n  \t\tinput[0].ki.wVk = 0;\n  \t\tinput[0].ki.wScan = value;\n  \t\tinput[0].ki.dwFlags = 0x4; // KEYEVENTF_UNICODE;\n\n  \t\tinput[1].type = INPUT_KEYBOARD;\n  \t\tinput[1].ki.wVk = 0;\n  \t\tinput[1].ki.wScan = value;\n  \t\tinput[1].ki.dwFlags = KEYEVENTF_KEYUP | 0x4; // KEYEVENTF_UNICODE;\n\n  \t\tSendInput(2, input, sizeof(INPUT));\n\t#elif defined(USE_X11)\n\t\ttoggleUniKey(value, true);\n\t\tmicrosleep(5.0);\n\t\ttoggleUniKey(value, false);\t\n\t#endif\n}\n\n#if defined(USE_X11)\n\tint input_utf(const char *utf) {\n\t\tDisplay *dpy = XOpenDisplay(NULL);\n\t\tKeySym sym = XStringToKeysym(utf);\n\t\t// KeySym sym = XKeycodeToKeysym(dpy, utf);\n\n\t\tint min, max, numcodes;\n\t\tXDisplayKeycodes(dpy, &min, &max);\n\t\tKeySym *keysym;\n\t\tkeysym = XGetKeyboardMapping(dpy, min, max-min+1, &numcodes);\n\t\tkeysym[(max-min-1)*numcodes] = sym;\n\t\tXChangeKeyboardMapping(dpy, min, numcodes, keysym, (max-min));\n\t\tXFree(keysym);\n\t\tXFlush(dpy);\n\n\t\tKeyCode code = XKeysymToKeycode(dpy, sym);\n\t\tXTestFakeKeyEvent(dpy, code, True, 1);\n\t\tXTestFakeKeyEvent(dpy, code, False, 1);\n\n\t\tXFlush(dpy);\n\t\tXCloseDisplay(dpy);\n\t\treturn 0;\n\t}\n#else\n\tint input_utf(const char *utf){\n\t\treturn 0;\n\t}\n#endif"
  },
  {
    "path": "key.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\npackage robotgo\n\n/*\n// #include \"key/keycode.h\"\n#include \"key/keypress_c.h\"\n*/\nimport \"C\"\n\nimport (\n\t\"errors\"\n\t\"math/rand\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode\"\n\t\"unsafe\"\n\n\t\"github.com/go-vgo/robotgo/clipboard\"\n)\n\n// Defining a bunch of constants.\nconst (\n\t// KeyA define key \"a\"\n\tKeyA = \"a\"\n\tKeyB = \"b\"\n\tKeyC = \"c\"\n\tKeyD = \"d\"\n\tKeyE = \"e\"\n\tKeyF = \"f\"\n\tKeyG = \"g\"\n\tKeyH = \"h\"\n\tKeyI = \"i\"\n\tKeyJ = \"j\"\n\tKeyK = \"k\"\n\tKeyL = \"l\"\n\tKeyM = \"m\"\n\tKeyN = \"n\"\n\tKeyO = \"o\"\n\tKeyP = \"p\"\n\tKeyQ = \"q\"\n\tKeyR = \"r\"\n\tKeyS = \"s\"\n\tKeyT = \"t\"\n\tKeyU = \"u\"\n\tKeyV = \"v\"\n\tKeyW = \"w\"\n\tKeyX = \"x\"\n\tKeyY = \"y\"\n\tKeyZ = \"z\"\n\t//\n\tCapA = \"A\"\n\tCapB = \"B\"\n\tCapC = \"C\"\n\tCapD = \"D\"\n\tCapE = \"E\"\n\tCapF = \"F\"\n\tCapG = \"G\"\n\tCapH = \"H\"\n\tCapI = \"I\"\n\tCapJ = \"J\"\n\tCapK = \"K\"\n\tCapL = \"L\"\n\tCapM = \"M\"\n\tCapN = \"N\"\n\tCapO = \"O\"\n\tCapP = \"P\"\n\tCapQ = \"Q\"\n\tCapR = \"R\"\n\tCapS = \"S\"\n\tCapT = \"T\"\n\tCapU = \"U\"\n\tCapV = \"V\"\n\tCapW = \"W\"\n\tCapX = \"X\"\n\tCapY = \"Y\"\n\tCapZ = \"Z\"\n\t//\n\tKey0      = \"0\"\n\tKey1      = \"1\"\n\tKey2      = \"2\"\n\tKey3      = \"3\"\n\tKey4      = \"4\"\n\tKey5      = \"5\"\n\tKey6      = \"6\"\n\tKey7      = \"7\"\n\tKey8      = \"8\"\n\tKey9      = \"9\"\n\tKeyGrave  = \"`\"\n\tKeyQuoter = '\"'\n\tKeyQuote  = \"'\"\n\n\t// Backspace backspace key string\n\tBackspace = \"backspace\"\n\tDelete    = \"delete\"\n\tEnter     = \"enter\"\n\tTab       = \"tab\"\n\tEsc       = \"esc\"\n\tEscape    = \"escape\"\n\tUp        = \"up\"    // Up arrow key\n\tDown      = \"down\"  // Down arrow key\n\tRight     = \"right\" // Right arrow key\n\tLeft      = \"left\"  // Left arrow key\n\tHome      = \"home\"\n\tEnd       = \"end\"\n\tPageup    = \"pageup\"\n\tPagedown  = \"pagedown\"\n\n\tF1  = \"f1\"\n\tF2  = \"f2\"\n\tF3  = \"f3\"\n\tF4  = \"f4\"\n\tF5  = \"f5\"\n\tF6  = \"f6\"\n\tF7  = \"f7\"\n\tF8  = \"f8\"\n\tF9  = \"f9\"\n\tF10 = \"f10\"\n\tF11 = \"f11\"\n\tF12 = \"f12\"\n\tF13 = \"f13\"\n\tF14 = \"f14\"\n\tF15 = \"f15\"\n\tF16 = \"f16\"\n\tF17 = \"f17\"\n\tF18 = \"f18\"\n\tF19 = \"f19\"\n\tF20 = \"f20\"\n\tF21 = \"f21\"\n\tF22 = \"f22\"\n\tF23 = \"f23\"\n\tF24 = \"f24\"\n\n\tCmd  = \"cmd\"  // is the \"win\" key for windows\n\tLcmd = \"lcmd\" // left command\n\tRcmd = \"rcmd\" // right command\n\t// \"command\"\n\tAlt     = \"alt\"\n\tLalt    = \"lalt\" // left alt\n\tRalt    = \"ralt\" // right alt\n\tCtrl    = \"ctrl\"\n\tLctrl   = \"lctrl\" // left ctrl\n\tRctrl   = \"rctrl\" // right ctrl\n\tControl = \"control\"\n\tShift   = \"shift\"\n\tLshift  = \"lshift\" // left shift\n\tRshift  = \"rshift\" // right shift\n\t// \"right_shift\"\n\tCapslock    = \"capslock\"\n\tSpace       = \"space\"\n\tPrint       = \"print\"\n\tPrintscreen = \"printscreen\" // No Mac support\n\tInsert      = \"insert\"\n\tMenu        = \"menu\" // Windows only\n\n\tAudioMute    = \"audio_mute\"     // Mute the volume\n\tAudioVolDown = \"audio_vol_down\" // Lower the volume\n\tAudioVolUp   = \"audio_vol_up\"   // Increase the volume\n\tAudioPlay    = \"audio_play\"\n\tAudioStop    = \"audio_stop\"\n\tAudioPause   = \"audio_pause\"\n\tAudioPrev    = \"audio_prev\"    // Previous Track\n\tAudioNext    = \"audio_next\"    // Next Track\n\tAudioRewind  = \"audio_rewind\"  // Linux only\n\tAudioForward = \"audio_forward\" // Linux only\n\tAudioRepeat  = \"audio_repeat\"  //  Linux only\n\tAudioRandom  = \"audio_random\"  //  Linux only\n\n\tNum0    = \"num0\" // numpad 0\n\tNum1    = \"num1\"\n\tNum2    = \"num2\"\n\tNum3    = \"num3\"\n\tNum4    = \"num4\"\n\tNum5    = \"num5\"\n\tNum6    = \"num6\"\n\tNum7    = \"num7\"\n\tNum8    = \"num8\"\n\tNum9    = \"num9\"\n\tNumLock = \"num_lock\"\n\n\tNumDecimal = \"num.\"\n\tNumPlus    = \"num+\"\n\tNumMinus   = \"num-\"\n\tNumMul     = \"num*\"\n\tNumDiv     = \"num/\"\n\tNumClear   = \"num_clear\"\n\tNumEnter   = \"num_enter\"\n\tNumEqual   = \"num_equal\"\n\n\tLightsMonUp     = \"lights_mon_up\"     // Turn up monitor brightness\t\t\tNo Windows support\n\tLightsMonDown   = \"lights_mon_down\"   // Turn down monitor brightness\t\tNo Windows support\n\tLightsKbdToggle = \"lights_kbd_toggle\" // Toggle keyboard backlight on/off\t\tNo Windows support\n\tLightsKbdUp     = \"lights_kbd_up\"     // Turn up keyboard backlight brightness\tNo Windows support\n\tLightsKbdDown   = \"lights_kbd_down\"\n)\n\n// keyNames define a map of key names to MMKeyCode\nvar keyNames = map[string]C.MMKeyCode{\n\t\"backspace\": C.K_BACKSPACE,\n\t\"delete\":    C.K_DELETE,\n\t\"enter\":     C.K_RETURN,\n\t\"tab\":       C.K_TAB,\n\t\"esc\":       C.K_ESCAPE,\n\t\"escape\":    C.K_ESCAPE,\n\t\"up\":        C.K_UP,\n\t\"down\":      C.K_DOWN,\n\t\"right\":     C.K_RIGHT,\n\t\"left\":      C.K_LEFT,\n\t\"home\":      C.K_HOME,\n\t\"end\":       C.K_END,\n\t\"pageup\":    C.K_PAGEUP,\n\t\"pagedown\":  C.K_PAGEDOWN,\n\t//\n\t\"f1\":  C.K_F1,\n\t\"f2\":  C.K_F2,\n\t\"f3\":  C.K_F3,\n\t\"f4\":  C.K_F4,\n\t\"f5\":  C.K_F5,\n\t\"f6\":  C.K_F6,\n\t\"f7\":  C.K_F7,\n\t\"f8\":  C.K_F8,\n\t\"f9\":  C.K_F9,\n\t\"f10\": C.K_F10,\n\t\"f11\": C.K_F11,\n\t\"f12\": C.K_F12,\n\t\"f13\": C.K_F13,\n\t\"f14\": C.K_F14,\n\t\"f15\": C.K_F15,\n\t\"f16\": C.K_F16,\n\t\"f17\": C.K_F17,\n\t\"f18\": C.K_F18,\n\t\"f19\": C.K_F19,\n\t\"f20\": C.K_F20,\n\t\"f21\": C.K_F21,\n\t\"f22\": C.K_F22,\n\t\"f23\": C.K_F23,\n\t\"f24\": C.K_F24,\n\t//\n\t\"cmd\":         C.K_META,\n\t\"lcmd\":        C.K_LMETA,\n\t\"rcmd\":        C.K_RMETA,\n\t\"command\":     C.K_META,\n\t\"alt\":         C.K_ALT,\n\t\"lalt\":        C.K_LALT,\n\t\"ralt\":        C.K_RALT,\n\t\"ctrl\":        C.K_CONTROL,\n\t\"lctrl\":       C.K_LCONTROL,\n\t\"rctrl\":       C.K_RCONTROL,\n\t\"control\":     C.K_CONTROL,\n\t\"shift\":       C.K_SHIFT,\n\t\"lshift\":      C.K_LSHIFT,\n\t\"rshift\":      C.K_RSHIFT,\n\t\"right_shift\": C.K_RSHIFT,\n\t\"capslock\":    C.K_CAPSLOCK,\n\t\"space\":       C.K_SPACE,\n\t\"print\":       C.K_PRINTSCREEN,\n\t\"printscreen\": C.K_PRINTSCREEN,\n\t\"insert\":      C.K_INSERT,\n\t\"menu\":        C.K_MENU,\n\n\t\"audio_mute\":     C.K_AUDIO_VOLUME_MUTE,\n\t\"audio_vol_down\": C.K_AUDIO_VOLUME_DOWN,\n\t\"audio_vol_up\":   C.K_AUDIO_VOLUME_UP,\n\t\"audio_play\":     C.K_AUDIO_PLAY,\n\t\"audio_stop\":     C.K_AUDIO_STOP,\n\t\"audio_pause\":    C.K_AUDIO_PAUSE,\n\t\"audio_prev\":     C.K_AUDIO_PREV,\n\t\"audio_next\":     C.K_AUDIO_NEXT,\n\t\"audio_rewind\":   C.K_AUDIO_REWIND,\n\t\"audio_forward\":  C.K_AUDIO_FORWARD,\n\t\"audio_repeat\":   C.K_AUDIO_REPEAT,\n\t\"audio_random\":   C.K_AUDIO_RANDOM,\n\n\t\"num0\":     C.K_NUMPAD_0,\n\t\"num1\":     C.K_NUMPAD_1,\n\t\"num2\":     C.K_NUMPAD_2,\n\t\"num3\":     C.K_NUMPAD_3,\n\t\"num4\":     C.K_NUMPAD_4,\n\t\"num5\":     C.K_NUMPAD_5,\n\t\"num6\":     C.K_NUMPAD_6,\n\t\"num7\":     C.K_NUMPAD_7,\n\t\"num8\":     C.K_NUMPAD_8,\n\t\"num9\":     C.K_NUMPAD_9,\n\t\"num_lock\": C.K_NUMPAD_LOCK,\n\n\t// todo: removed\n\t\"numpad_0\":    C.K_NUMPAD_0,\n\t\"numpad_1\":    C.K_NUMPAD_1,\n\t\"numpad_2\":    C.K_NUMPAD_2,\n\t\"numpad_3\":    C.K_NUMPAD_3,\n\t\"numpad_4\":    C.K_NUMPAD_4,\n\t\"numpad_5\":    C.K_NUMPAD_5,\n\t\"numpad_6\":    C.K_NUMPAD_6,\n\t\"numpad_7\":    C.K_NUMPAD_7,\n\t\"numpad_8\":    C.K_NUMPAD_8,\n\t\"numpad_9\":    C.K_NUMPAD_9,\n\t\"numpad_lock\": C.K_NUMPAD_LOCK,\n\n\t\"num.\":      C.K_NUMPAD_DECIMAL,\n\t\"num+\":      C.K_NUMPAD_PLUS,\n\t\"num-\":      C.K_NUMPAD_MINUS,\n\t\"num*\":      C.K_NUMPAD_MUL,\n\t\"num/\":      C.K_NUMPAD_DIV,\n\t\"num_clear\": C.K_NUMPAD_CLEAR,\n\t\"num_enter\": C.K_NUMPAD_ENTER,\n\t\"num_equal\": C.K_NUMPAD_EQUAL,\n\n\t\"lights_mon_up\":     C.K_LIGHTS_MON_UP,\n\t\"lights_mon_down\":   C.K_LIGHTS_MON_DOWN,\n\t\"lights_kbd_toggle\": C.K_LIGHTS_KBD_TOGGLE,\n\t\"lights_kbd_up\":     C.K_LIGHTS_KBD_UP,\n\t\"lights_kbd_down\":   C.K_LIGHTS_KBD_DOWN,\n\n\t// { NULL:              C.K_NOT_A_KEY }\n}\n\n// CmdCtrl If the operating system is macOS, return the key string \"cmd\",\n// otherwise return the key string \"ctrl\nfunc CmdCtrl() string {\n\tif runtime.GOOS == \"darwin\" {\n\t\treturn \"cmd\"\n\t}\n\treturn \"ctrl\"\n}\n\n// It sends a key press and release to the active application\nfunc tapKeyCode(code C.MMKeyCode, flags C.MMKeyFlags, pid C.uintptr) {\n\tC.toggleKeyCode(code, true, flags, pid)\n\tMilliSleep(3)\n\tC.toggleKeyCode(code, false, flags, pid)\n}\n\nvar keyErr = errors.New(\"Invalid key flag specified.\")\n\nfunc checkKeyCodes(k string) (key C.MMKeyCode, err error) {\n\tif k == \"\" {\n\t\treturn\n\t}\n\n\tif len(k) == 1 {\n\t\tval1 := C.CString(k)\n\t\tdefer C.free(unsafe.Pointer(val1))\n\n\t\tkey = C.keyCodeForChar(*val1)\n\t\tif key == C.K_NOT_A_KEY {\n\t\t\terr = keyErr\n\t\t\treturn\n\t\t}\n\t\treturn\n\t}\n\n\tif v, ok := keyNames[k]; ok {\n\t\tkey = v\n\t\tif key == C.K_NOT_A_KEY {\n\t\t\terr = keyErr\n\t\t\treturn\n\t\t}\n\t}\n\treturn\n}\n\nfunc checkKeyFlags(f string) (flags C.MMKeyFlags) {\n\tm := map[string]C.MMKeyFlags{\n\t\t\"alt\":    C.MOD_ALT,\n\t\t\"ralt\":   C.MOD_ALT,\n\t\t\"lalt\":   C.MOD_ALT,\n\t\t\"cmd\":    C.MOD_META,\n\t\t\"rcmd\":   C.MOD_META,\n\t\t\"lcmd\":   C.MOD_META,\n\t\t\"ctrl\":   C.MOD_CONTROL,\n\t\t\"rctrl\":  C.MOD_CONTROL,\n\t\t\"lctrl\":  C.MOD_CONTROL,\n\t\t\"shift\":  C.MOD_SHIFT,\n\t\t\"rshift\": C.MOD_SHIFT,\n\t\t\"lshift\": C.MOD_SHIFT,\n\t\t\"none\":   C.MOD_NONE,\n\t}\n\n\tif v, ok := m[f]; ok {\n\t\treturn v\n\t}\n\treturn\n}\n\nfunc getFlagsFromValue(value []string) (flags C.MMKeyFlags) {\n\tif len(value) <= 0 {\n\t\treturn\n\t}\n\n\tfor i := 0; i < len(value); i++ {\n\t\tvar f C.MMKeyFlags = C.MOD_NONE\n\n\t\tf = checkKeyFlags(value[i])\n\t\tflags = (C.MMKeyFlags)(flags | f)\n\t}\n\n\treturn\n}\n\nfunc upKeyArr(keyArr []string, pid int) {\n\tfor i := 0; i < len(keyArr); i++ {\n\t\tkey1, _ := checkKeyCodes(keyArr[i])\n\t\tC.toggleKeyCode(key1, false, C.MOD_NONE, C.uintptr(pid))\n\t}\n}\n\nfunc keyTaps(k string, keyArr []string, pid int) error {\n\tflags := getFlagsFromValue(keyArr)\n\tkey, err := checkKeyCodes(k)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\ttapKeyCode(key, flags, C.uintptr(pid))\n\tMilliSleep(KeySleep)\n\tupKeyArr(keyArr, pid)\n\treturn nil\n}\n\nfunc getKeyDown(keyArr []string) (bool, []string) {\n\tif len(keyArr) <= 0 {\n\t\tkeyArr = append(keyArr, \"down\")\n\t}\n\n\tdown := true\n\tif keyArr[0] == \"up\" {\n\t\tdown = false\n\t}\n\n\tif keyArr[0] == \"up\" || keyArr[0] == \"down\" {\n\t\tkeyArr = keyArr[1:]\n\t}\n\treturn down, keyArr\n}\n\nfunc keyTogglesB(k string, down bool, keyArr []string, pid int) error {\n\tflags := getFlagsFromValue(keyArr)\n\tkey, err := checkKeyCodes(k)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tC.toggleKeyCode(key, C.bool(down), flags, C.uintptr(pid))\n\tMilliSleep(KeySleep)\n\tif !down {\n\t\tupKeyArr(keyArr, pid)\n\t}\n\treturn nil\n}\n\nfunc keyToggles(k string, keyArr []string, pid int) error {\n\tdown, keyArr1 := getKeyDown(keyArr)\n\treturn keyTogglesB(k, down, keyArr1, pid)\n}\n\n/*\n __  ___  ___________    ____ .______     ______        ___      .______       _______\n|  |/  / |   ____\\   \\  /   / |   _  \\   /  __  \\      /   \\     |   _  \\     |       \\\n|  '  /  |  |__   \\   \\/   /  |  |_)  | |  |  |  |    /  ^  \\    |  |_)  |    |  .--.  |\n|    <   |   __|   \\_    _/   |   _  <  |  |  |  |   /  /_\\  \\   |      /     |  |  |  |\n|  .  \\  |  |____    |  |     |  |_)  | |  `--'  |  /  _____  \\  |  |\\  \\----.|  '--'  |\n|__|\\__\\ |_______|   |__|     |______/   \\______/  /__/     \\__\\ | _| `._____||_______/\n\n*/\n\n// ToInterfaces convert []string to []interface{}\nfunc ToInterfaces(fields []string) []interface{} {\n\tres := make([]interface{}, 0, len(fields))\n\tfor _, s := range fields {\n\t\tres = append(res, s)\n\t}\n\treturn res\n}\n\n// ToStrings convert []interface{} to []string\nfunc ToStrings(fields []interface{}) []string {\n\tres := make([]string, 0, len(fields))\n\tfor _, s := range fields {\n\t\tres = append(res, s.(string))\n\t}\n\treturn res\n}\n\n// toErr it converts a C string to a Go error\nfunc toErr(str *C.char) error {\n\tgstr := C.GoString(str)\n\tif gstr == \"\" {\n\t\treturn nil\n\t}\n\treturn errors.New(gstr)\n}\n\nfunc appendShift(key string, len1 int, args ...interface{}) (string, []interface{}) {\n\tif len(key) > 0 && unicode.IsUpper([]rune(key)[0]) {\n\t\targs = append(args, \"shift\")\n\t}\n\n\tkey = strings.ToLower(key)\n\tif _, ok := Special[key]; ok {\n\t\tkey = Special[key]\n\t\tif len(args) <= len1 {\n\t\t\targs = append(args, \"shift\")\n\t\t}\n\t}\n\n\treturn key, args\n}\n\n// KeyTap taps the keyboard code;\n//\n// See keys supported:\n//\n//\thttps://github.com/go-vgo/robotgo/blob/master/docs/keys.md#keys\n//\n// Examples:\n//\n//\trobotgo.KeySleep = 100 // 100 millisecond\n//\trobotgo.KeyTap(\"a\")\n//\trobotgo.KeyTap(\"i\", \"alt\", \"command\")\n//\n//\tarr := []string{\"alt\", \"command\"}\n//\trobotgo.KeyTap(\"i\", arr)\n//\n//\trobotgo.KeyTap(\"k\", pid int)\nfunc KeyTap(key string, args ...interface{}) error {\n\tvar keyArr []string\n\tkey, args = appendShift(key, 0, args...)\n\n\tpid := 0\n\tif len(args) > 0 {\n\t\tif reflect.TypeOf(args[0]) == reflect.TypeOf(keyArr) {\n\t\t\tkeyArr = args[0].([]string)\n\t\t} else {\n\t\t\tif reflect.TypeOf(args[0]) == reflect.TypeOf(pid) {\n\t\t\t\tpid = args[0].(int)\n\t\t\t\tkeyArr = ToStrings(args[1:])\n\t\t\t} else {\n\t\t\t\tkeyArr = ToStrings(args)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn keyTaps(key, keyArr, pid)\n}\n\nfunc getToggleArgs(args ...interface{}) (pid int, keyArr []string) {\n\tif len(args) > 0 && reflect.TypeOf(args[0]) == reflect.TypeOf(pid) {\n\t\tpid = args[0].(int)\n\t\tkeyArr = ToStrings(args[1:])\n\t} else {\n\t\tkeyArr = ToStrings(args)\n\t}\n\treturn\n}\n\n// KeyToggle toggles the keyboard, if there not have args default is \"down\"\n//\n// See keys:\n//\n//\thttps://github.com/go-vgo/robotgo/blob/master/docs/keys.md#keys\n//\n// Examples:\n//\n//\trobotgo.KeyToggle(\"a\")\n//\trobotgo.KeyToggle(\"a\", \"up\")\n//\n//\trobotgo.KeyToggle(\"a\", \"up\", \"alt\", \"cmd\")\n//\trobotgo.KeyToggle(\"k\", pid int)\nfunc KeyToggle(key string, args ...interface{}) error {\n\tkey, args = appendShift(key, 1, args...)\n\tpid, keyArr := getToggleArgs(args...)\n\treturn keyToggles(key, keyArr, pid)\n}\n\n// KeyPress press key string\nfunc KeyPress(key string, args ...interface{}) error {\n\terr := KeyDown(key, args...)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tMilliSleep(1 + rand.Intn(3))\n\treturn KeyUp(key, args...)\n}\n\n// KeyDown press down a key\nfunc KeyDown(key string, args ...interface{}) error {\n\treturn KeyToggle(key, args...)\n}\n\n// KeyUp press up a key\nfunc KeyUp(key string, args ...interface{}) error {\n\tarr := []interface{}{\"up\"}\n\tarr = append(arr, args...)\n\treturn KeyToggle(key, arr...)\n}\n\n// ReadAll read string from clipboard\nfunc ReadAll() (string, error) {\n\treturn clipboard.ReadAll()\n}\n\n// WriteAll write string to clipboard\nfunc WriteAll(text string) error {\n\treturn clipboard.WriteAll(text)\n}\n\n// CharCodeAt char code at utf-8\nfunc CharCodeAt(s string, n int) rune {\n\ti := 0\n\tfor _, r := range s {\n\t\tif i == n {\n\t\t\treturn r\n\t\t}\n\t\ti++\n\t}\n\n\treturn 0\n}\n\n// UnicodeType tap the uint32 unicode\nfunc UnicodeType(str uint32, args ...int) {\n\tcstr := C.uint(str)\n\tpid := 0\n\tif len(args) > 0 {\n\t\tpid = args[0]\n\t}\n\n\tisPid := 0\n\tif len(args) > 1 {\n\t\tisPid = args[1]\n\t}\n\n\tC.unicodeType(cstr, C.uintptr(pid), C.int8_t(isPid))\n}\n\n// ToUC trans string to unicode []string\nfunc ToUC(text string) []string {\n\tvar uc []string\n\n\tfor _, r := range text {\n\t\ttextQ := strconv.QuoteToASCII(string(r))\n\t\ttextUnQ := textQ[1 : len(textQ)-1]\n\n\t\tst := strings.Replace(textUnQ, \"\\\\u\", \"U\", -1)\n\t\tif st == \"\\\\\\\\\" {\n\t\t\tst = \"\\\\\"\n\t\t}\n\t\tif st == `\\\"` {\n\t\t\tst = `\"`\n\t\t}\n\t\tuc = append(uc, st)\n\t}\n\n\treturn uc\n}\n\nfunc inputUTF(str string) {\n\tcstr := C.CString(str)\n\tC.input_utf(cstr)\n\n\tC.free(unsafe.Pointer(cstr))\n}\n\n// TypeStr tap a string\n//\n// Deprecated: use the Type()\nfunc TypeStr(str string, args ...int) {\n\tType(str, args...)\n}\n\n// Type type a string (supported UTF-8)\n//\n// robotgo.Type(string: \"The string to send\", int: pid, \"milli_sleep time\", \"x11 option\")\n//\n// Examples:\n//\n//\trobotgo.Type(\"abc@123, Hi galaxy, こんにちは\")\n//\trobotgo.Type(\"To be or not to be, this is questions.\", pid int)\nfunc Type(str string, args ...int) {\n\tvar tm, tm1 = 0, 7\n\n\tif len(args) > 1 {\n\t\ttm = args[1]\n\t}\n\tif len(args) > 2 {\n\t\ttm1 = args[2]\n\t}\n\tpid := 0\n\tif len(args) > 0 {\n\t\tpid = args[0]\n\t}\n\n\tif runtime.GOOS == \"linux\" {\n\t\tstrUc := ToUC(str)\n\t\tfor i := 0; i < len(strUc); i++ {\n\t\t\tru := []rune(strUc[i])\n\t\t\tif len(ru) <= 1 {\n\t\t\t\tustr := uint32(CharCodeAt(strUc[i], 0))\n\t\t\t\tUnicodeType(ustr, pid)\n\t\t\t} else {\n\t\t\t\tinputUTF(strUc[i])\n\t\t\t\tMilliSleep(tm1)\n\t\t\t}\n\n\t\t\tMilliSleep(tm)\n\t\t}\n\t\treturn\n\t}\n\n\tfor i := 0; i < len([]rune(str)); i++ {\n\t\tustr := uint32(CharCodeAt(str, i))\n\t\tUnicodeType(ustr, pid)\n\t\t// if len(args) > 0 {\n\t\tMilliSleep(tm)\n\t\t// }\n\t}\n\tMilliSleep(KeySleep)\n}\n\n// PasteStr paste a string\n//\n// Deprecated: use the Paste()\nfunc PasteStr(str string) error {\n\treturn Paste(str)\n}\n\n// Paste paste a string (supported UTF-8),\n// write the string to clipboard and tap `cmd + v`\nfunc Paste(str string) error {\n\terr := clipboard.WriteAll(str)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn CmdV()\n}\n\n// CmdV tap key command + v or control + v\nfunc CmdV() error {\n\tif runtime.GOOS == \"darwin\" {\n\t\treturn KeyTap(\"v\", \"command\")\n\t}\n\n\treturn KeyTap(\"v\", \"control\")\n}\n\n// TypeStrDelay type string width delay\n//\n// Deprecated: use the TypeDelay()\nfunc TypeStrDelay(str string, delay int) {\n\tTypeDelay(str, delay)\n}\n\n// TypeDelay type string with delayed\n// And you can use robotgo.KeySleep = 100 to delayed not this function\nfunc TypeDelay(str string, delay int) {\n\tTypeStr(str)\n\tMilliSleep(delay)\n}\n\n// SetDelay sets the key and mouse delay\n// robotgo.SetDelay(100) option the robotgo.KeySleep and robotgo.MouseSleep = d\nfunc SetDelay(d ...int) {\n\tv := 10\n\tif len(d) > 0 {\n\t\tv = d[0]\n\t}\n\n\tKeySleep = v\n\tMouseSleep = v\n}\n"
  },
  {
    "path": "keycode.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\npackage robotgo\n\nimport (\n\t\"github.com/vcaesar/keycode\"\n)\n\ntype uMap map[string]uint16\n\n// MouseMap robotgo hook mouse's code map\nvar MouseMap = keycode.MouseMap\n\nconst (\n\t// Mleft mouse left button\n\tMleft      = \"left\"\n\tMright     = \"right\"\n\tCenter     = \"center\"\n\tWheelDown  = \"wheelDown\"\n\tWheelUp    = \"wheelUp\"\n\tWheelLeft  = \"wheelLeft\"\n\tWheelRight = \"wheelRight\"\n)\n\n// Keycode robotgo hook key's code map\nvar Keycode = keycode.Keycode\n\n// Special is the special key map\nvar Special = keycode.Special\n"
  },
  {
    "path": "mouse/mouse.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\npackage mouse\n"
  },
  {
    "path": "mouse/mouse.h",
    "content": "#pragma once\n#ifndef MOUSE_H\n#define MOUSE_H\n\n#include \"../base/os.h\"\n#include \"../base/types.h\"\n#include <stdbool.h>\n\n#if defined(IS_MACOSX)\n\t#include <ApplicationServices/ApplicationServices.h>\n\n\ttypedef enum {\n\t\tLEFT_BUTTON = kCGMouseButtonLeft,\n\t\tRIGHT_BUTTON = kCGMouseButtonRight,\n\t\tCENTER_BUTTON = kCGMouseButtonCenter,\n\t\tWheelDown  =  4,\n\t\tWheelUp    = 5,\n\t\tWheelLeft  =  6,\n\t\tWheelRight = 7,\n\t} MMMouseButton;\n#elif defined(USE_X11)\n\tenum _MMMouseButton {\n\t\tLEFT_BUTTON = 1,\n\t\tCENTER_BUTTON = 2,\n\t\tRIGHT_BUTTON = 3,\n\t\tWheelDown =  4,\n\t\tWheelUp  =  5,\n\t\tWheelLeft =  6,\n\t\tWheelRight = 7,\n\t};\n\ttypedef unsigned int MMMouseButton;\n#elif defined(IS_WINDOWS)\n\tenum _MMMouseButton {\n\t\tLEFT_BUTTON = 1,\n\t\tCENTER_BUTTON = 2,\n\t\tRIGHT_BUTTON = 3,\n\t\tWheelDown =  4,\n\t\tWheelUp  =  5,\n\t\tWheelLeft =  6,\n\t\tWheelRight = 7,\n\t};\n\ttypedef unsigned int MMMouseButton;\n#else\n\t#error \"No mouse button constants set for platform\"\n#endif\n\n#endif /* MOUSE_H */"
  },
  {
    "path": "mouse/mouse_c.h",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\n#include \"mouse.h\"\n#include \"../base/deadbeef_rand.h\"\n#include \"../base/microsleep.h\"\n\n#include <math.h> /* For floor() */\n#if defined(IS_MACOSX)\n\t// #include </System/Library/Frameworks/ApplicationServices.framework/Headers/ApplicationServices.h>\n\t#include <ApplicationServices/ApplicationServices.h>\n\t// #include </System/Library/Frameworks/ApplicationServices.framework/Versions/A/Headers/ApplicationServices.h>\n#elif defined(USE_X11)\n\t#include <X11/Xlib.h>\n\t#include <X11/extensions/XTest.h>\n\t#include <stdlib.h>\n#endif\n\n/* Some convenience macros for converting our enums to the system API types. */\n#if defined(IS_MACOSX)\n\tCGEventType MMMouseDownToCGEventType(MMMouseButton button) {\n\t\tif (button == LEFT_BUTTON) {\n\t\t\treturn kCGEventLeftMouseDown;\n\t\t}\n\t\tif (button == RIGHT_BUTTON) { \n\t\t\treturn kCGEventRightMouseDown;\n\t\t}\n\t\treturn kCGEventOtherMouseDown;\n\t}\n\n\tCGEventType MMMouseUpToCGEventType(MMMouseButton button) {\n\t\tif (button == LEFT_BUTTON) { return kCGEventLeftMouseUp; }\n\t\tif (button == RIGHT_BUTTON) { return kCGEventRightMouseUp; }\t\t\n\t\treturn kCGEventOtherMouseUp;\n\t}\n\n\tCGEventType MMMouseDragToCGEventType(MMMouseButton button) {\n\t\tif (button == LEFT_BUTTON) { return kCGEventLeftMouseDragged; }\n\t\tif (button == RIGHT_BUTTON) { return kCGEventRightMouseDragged; }\n\t\treturn kCGEventOtherMouseDragged;\n\t}\n\n\tCGEventType MMMouseToCGEventType(bool down, MMMouseButton button) {\n\t\tif (down) { return MMMouseDownToCGEventType(button); }\n\t\treturn MMMouseUpToCGEventType(button);\n\t}\n\n#elif defined(IS_WINDOWS)\n\tDWORD MMMouseUpToMEventF(MMMouseButton button) {\n\t\tif (button == LEFT_BUTTON) { return MOUSEEVENTF_LEFTUP; }\n\t\tif (button == RIGHT_BUTTON) { return MOUSEEVENTF_RIGHTUP; } \n\t\treturn MOUSEEVENTF_MIDDLEUP;\n\t}\n\n\tDWORD MMMouseDownToMEventF(MMMouseButton button) {\n\t\tif (button == LEFT_BUTTON) { return MOUSEEVENTF_LEFTDOWN; }\n\t\tif (button == RIGHT_BUTTON) { return MOUSEEVENTF_RIGHTDOWN; } \n\t\treturn MOUSEEVENTF_MIDDLEDOWN;\n\t}\n\n\tDWORD MMMouseToMEventF(bool down, MMMouseButton button) {\n\t\tif (down) { return MMMouseDownToMEventF(button); }\n\t\treturn MMMouseUpToMEventF(button);\n\t}\n#endif\n\n#if defined(IS_MACOSX)\n\t/* Calculate the delta for a mouse move and add them to the event. */\n\tvoid calculateDeltas(CGEventRef *event, MMPointInt32 point) {\n\t\t/* The next few lines are a workaround for games not detecting mouse moves. */\n\t\tCGEventRef get = CGEventCreate(NULL);\n\t\tCGPoint mouse = CGEventGetLocation(get);\n\n\t\t// Calculate the deltas.\n\t\tint64_t deltaX = point.x - mouse.x;\n\t\tint64_t deltaY = point.y - mouse.y;\n\n\t\tCGEventSetIntegerValueField(*event, kCGMouseEventDeltaX, deltaX);\n\t\tCGEventSetIntegerValueField(*event, kCGMouseEventDeltaY, deltaY);\n\n\t\tCFRelease(get);\n\t}\n#endif\n\n/* Move the mouse to a specific point. */\nvoid moveMouse(MMPointInt32 point){\n\t#if defined(IS_MACOSX)\n\t\tCGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);\n\t\tCGEventRef move = CGEventCreateMouseEvent(source, kCGEventMouseMoved, \n\t\t\t\t\t\t\t\tCGPointFromMMPointInt32(point), kCGMouseButtonLeft);\n\n\t\tcalculateDeltas(&move, point);\n\t\tCGEventPost(kCGHIDEventTap, move);\n\t\tCFRelease(move);\n\t\tCFRelease(source);\n\t#elif defined(USE_X11)\n\t\tDisplay *display = XGetMainDisplay();\n\t\tXWarpPointer(display, None, DefaultRootWindow(display), 0, 0, 0, 0, point.x, point.y);\n\n\t\tXSync(display, false);\n\t#elif defined(IS_WINDOWS)\n\t\tSetCursorPos(point.x, point.y);\n\t#endif\n}\n\nvoid dragMouse(MMPointInt32 point, const MMMouseButton button){\n\t#if defined(IS_MACOSX)\n\t\tconst CGEventType dragType = MMMouseDragToCGEventType(button);\n\t\tCGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);\n\t\tCGEventRef drag = CGEventCreateMouseEvent(source, dragType, \n\t\t\t\t\t\t\t\tCGPointFromMMPointInt32(point), (CGMouseButton)button);\n\n\t\tcalculateDeltas(&drag, point);\n\n\t\tCGEventPost(kCGHIDEventTap, drag);\n\t\tCFRelease(drag);\n\t\tCFRelease(source);\n\t#else\n\t\tmoveMouse(point);\n\t#endif\n}\n\nMMPointInt32 location() {\n\t#if defined(IS_MACOSX)\n\t\tCGEventRef event = CGEventCreate(NULL);\n\t\tCGPoint point = CGEventGetLocation(event);\n\t\tCFRelease(event);\n\n\t\treturn MMPointInt32FromCGPoint(point);\n\t#elif defined(USE_X11)\n\t\tint x, y; \t/* This is all we care about. Seriously. */\n\t\tWindow garb1, garb2; \t/* Why you can't specify NULL as a parameter */\n\t\tint garb_x, garb_y;  \t/* is beyond me. */\n\t\tunsigned int more_garbage;\n\n\t\tDisplay *display = XGetMainDisplay();\n\t\tXQueryPointer(display, XDefaultRootWindow(display), &garb1, &garb2, &x, &y, \n\t\t\t\t\t\t&garb_x, &garb_y, &more_garbage);\n\n\t\treturn MMPointInt32Make(x, y);\n\t#elif defined(IS_WINDOWS)\n\t\tPOINT point;\n\t\tGetCursorPos(&point);\n\t\treturn MMPointInt32FromPOINT(point);\n\t#endif\n}\n\n/* Press down a button, or release it. */\nint toggleMouse(bool down, MMMouseButton button) {\n\t#if defined(IS_MACOSX)\n\t\tconst CGPoint currentPos = CGPointFromMMPointInt32(location());\n\t\tconst CGEventType mouseType = MMMouseToCGEventType(down, button);\n\t\tCGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);\n\t\tCGEventRef event = CGEventCreateMouseEvent(source, mouseType, currentPos, (CGMouseButton)button);\n\n\t\tif (event == NULL) {\n\t\t\tCFRelease(source);\n\t\t\treturn (int)kCGErrorCannotComplete;\n\t\t}\n\t\n\t\tCGEventPost(kCGHIDEventTap, event);\n\t\tCFRelease(event);\n\t\tCFRelease(source);\n\t\treturn 0;\n\t#elif defined(USE_X11)\n\t\tDisplay *display = XGetMainDisplay();\n\t\tStatus status = XTestFakeButtonEvent(display, button, down ? True : False, CurrentTime);\n\t\tXSync(display, false);\n\t\treturn status ? 0 : 1;\n\t#elif defined(IS_WINDOWS)\n\t\tINPUT mouseInput;\n\n\t\tmouseInput.type = INPUT_MOUSE;\n\t\tmouseInput.mi.dx = 0;\n\t\tmouseInput.mi.dy = 0;\n\t\tmouseInput.mi.dwFlags = MMMouseToMEventF(down, button);\n\t\tmouseInput.mi.time = 0;\n\t\tmouseInput.mi.dwExtraInfo = 0;\n\t\tmouseInput.mi.mouseData = 0;\n\t\tUINT sent = SendInput(1, &mouseInput, sizeof(mouseInput));\n\t\treturn sent == 1 ? 0 : (int)GetLastError();\n\t#endif\n}\n\nint clickMouse(MMMouseButton button){\n\tint err = toggleMouse(true, button);\n\tif (err != 0) {\n\t\treturn err;\n\t}\n\n\tmicrosleep(5.0);\n\treturn toggleMouse(false, button);\n}\n\n/* Special function for sending double clicks, needed for MacOS. */\nint doubleClick(MMMouseButton button, int count){\n\t#if defined(IS_MACOSX)\n\t\t/* Double click for Mac. */\n\t\tconst CGPoint currentPos = CGPointFromMMPointInt32(location());\n\t\tconst CGEventType mouseTypeDown = MMMouseToCGEventType(true, button);\n\t\tconst CGEventType mouseTypeUP = MMMouseToCGEventType(false, button);\n\n\t\tCGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);\n\t\tCGEventRef event = CGEventCreateMouseEvent(source, mouseTypeDown, currentPos, kCGMouseButtonLeft);\n\t\tif (event == NULL) {\n\t\t\tCFRelease(source);\n\t\t\treturn (int)kCGErrorCannotComplete;\n\t\t}\n\n\t\t/* Set event to double click. */\n\t\tCGEventSetIntegerValueField(event, kCGMouseEventClickState, count);\n\t\tCGEventPost(kCGHIDEventTap, event);\n\n\t\tCGEventSetType(event, mouseTypeUP);\n\t\tCGEventPost(kCGHIDEventTap, event);\n\n\t\tCFRelease(event);\n\t\tCFRelease(source);\n\t\treturn 0;\n\t#else\n\t\t/* Double click for everything else. */\n\t\tint err = clickMouse(button);\n\t\tif (err != 0) {\n\t\t\treturn err;\n\t\t}\n\t\tmicrosleep(200);\n\t\treturn clickMouse(button);\n\t#endif\n}\n\n/* Function used to scroll the screen in the required direction. */\nvoid scrollMouseXY(int x, int y) {\n\t#if defined(IS_WINDOWS)\n\t\t// Fix for #97, C89 needs variables declared on top of functions (mouseScrollInput)\n\t\tINPUT mouseScrollInputH;\n\t\tINPUT mouseScrollInputV;\n\t#endif\n\n\t#if defined(IS_MACOSX)\n\t\tCGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);\n\t\tCGEventRef event = CGEventCreateScrollWheelEvent(source, kCGScrollEventUnitPixel, 2, y, x);\t\n\t\tCGEventPost(kCGHIDEventTap, event);\n\n\t\tCFRelease(event);\n\t\tCFRelease(source);\n\t#elif defined(USE_X11)\n\t\tint ydir = 4; /* Button 4 is up, 5 is down. */\n\t\tint xdir = 6;\n\t\tDisplay *display = XGetMainDisplay();\n\n\t\tif (y < 0) { ydir = 5; }\n\t\tif (x < 0) { xdir = 7; }\n\n\t\tint xi; int yi;\n\t\tfor (xi = 0; xi < abs(x); xi++) {\n\t\t\tXTestFakeButtonEvent(display, xdir, 1, CurrentTime);\n\t\t\tXTestFakeButtonEvent(display, xdir, 0, CurrentTime);\n\t\t}\n\t\tfor (yi = 0; yi < abs(y); yi++) {\n\t\t\tXTestFakeButtonEvent(display, ydir, 1, CurrentTime);\n\t\t\tXTestFakeButtonEvent(display, ydir, 0, CurrentTime);\n\t\t}\n\n\t\tXSync(display, false);\n\t#elif defined(IS_WINDOWS)\n\t\tmouseScrollInputH.type = INPUT_MOUSE;\n\t\tmouseScrollInputH.mi.dx = 0;\n\t\tmouseScrollInputH.mi.dy = 0;\n\t\tmouseScrollInputH.mi.dwFlags = MOUSEEVENTF_WHEEL;\n\t\tmouseScrollInputH.mi.time = 0;\n\t\tmouseScrollInputH.mi.dwExtraInfo = 0;\n\t\tmouseScrollInputH.mi.mouseData = WHEEL_DELTA * x;\n\n\t\tmouseScrollInputV.type = INPUT_MOUSE;\n\t\tmouseScrollInputV.mi.dx = 0;\n\t\tmouseScrollInputV.mi.dy = 0;\n\t\tmouseScrollInputV.mi.dwFlags = MOUSEEVENTF_WHEEL;\n\t\tmouseScrollInputV.mi.time = 0;\n\t\tmouseScrollInputV.mi.dwExtraInfo = 0;\n\t\tmouseScrollInputV.mi.mouseData = WHEEL_DELTA * y;\n\n\t\tSendInput(1, &mouseScrollInputH, sizeof(mouseScrollInputH));\n\t\tSendInput(1, &mouseScrollInputV, sizeof(mouseScrollInputV));\n\t#endif\n}\n\n/* A crude, fast hypot() approximation to get around the fact that hypot() is not a standard ANSI C function. */\n#if !defined(M_SQRT2)\n\t#define M_SQRT2 1.4142135623730950488016887 /* Fix for MSVC. */\n#endif\n\nstatic double crude_hypot(double x, double y){\n\tdouble big = fabs(x); /* max(|x|, |y|) */\n\tdouble small = fabs(y); /* min(|x|, |y|) */\n\n\tif (big > small) {\n\t\tdouble temp = big;\n\t\tbig = small;\n\t\tsmall = temp;\n\t}\n\n\treturn ((M_SQRT2 - 1.0) * small) + big;\n}\n\nstatic bool smoothlyMoveMouseImpl(MMPointInt32 endPoint, double lowSpeed, double highSpeed,\n\t\tbool drag, MMMouseButton button){\n\tMMPointInt32 pos = location();\n\t// MMSizeInt32 screenSize = getMainDisplaySize();\n\tdouble velo_x = 0.0, velo_y = 0.0;\n\tdouble distance;\n\n\twhile ((distance =crude_hypot((double)pos.x - endPoint.x, (double)pos.y - endPoint.y)) > 1.0) {\n\t\tdouble gravity = DEADBEEF_UNIFORM(5.0, 500.0);\n\t\t// double gravity = DEADBEEF_UNIFORM(lowSpeed, highSpeed);\n\t\tdouble veloDistance;\n\t\tvelo_x += (gravity * ((double)endPoint.x - pos.x)) / distance;\n\t\tvelo_y += (gravity * ((double)endPoint.y - pos.y)) / distance;\n\n\t\t/* Normalize velocity to get a unit vector of length 1. */\n\t\tveloDistance = crude_hypot(velo_x, velo_y);\n\t\tvelo_x /= veloDistance;\n\t\tvelo_y /= veloDistance;\n\n\t\tpos.x += floor(velo_x + 0.5);\n\t\tpos.y += floor(velo_y + 0.5); \n\n\t\t/* Make sure we are in the screen boundaries! */\n\t\t// if (pos.x >= screenSize.w || pos.y >= screenSize.h) { \n\t\t// \treturn false;\n\t\t// }\n\t\tif (drag) {\n\t\t\tdragMouse(pos, button);\n\t\t} else {\n\t\t\tmoveMouse(pos);\n\t\t}\n\n\t\t/* Wait 1 - 3 milliseconds. */\n\t\tmicrosleep(DEADBEEF_UNIFORM(lowSpeed, highSpeed));\n\t\t// microsleep(DEADBEEF_UNIFORM(1.0, 3.0));\n\t}\n\treturn true;\n}\n\nbool smoothlyMoveMouse(MMPointInt32 endPoint, double lowSpeed, double highSpeed){\n\treturn smoothlyMoveMouseImpl(endPoint, lowSpeed, highSpeed, false, LEFT_BUTTON);\n}\n\nbool smoothlyDragMouse(MMPointInt32 endPoint, double lowSpeed, double highSpeed,\n\t\tMMMouseButton button){\n\treturn smoothlyMoveMouseImpl(endPoint, lowSpeed, highSpeed, true, button);\n}\n"
  },
  {
    "path": "mouse/mouse_darwin.go",
    "content": "//go:build darwin\n// +build darwin\n\npackage mouse\n"
  },
  {
    "path": "mouse/mouse_windows.go",
    "content": "//go:build windows\n// +build windows\n\npackage mouse\n"
  },
  {
    "path": "mouse/mouse_x11.go",
    "content": "//go:build !darwin && !windows\n// +build !darwin,!windows\n\npackage mouse\n"
  },
  {
    "path": "ps.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\npackage robotgo\n\nimport ps \"github.com/vcaesar/gops\"\n\n// Nps process struct\ntype Nps struct {\n\tPid  int\n\tName string\n}\n\n// Pids get the all process id\nfunc Pids() ([]int, error) {\n\treturn ps.Pids()\n}\n\n// PidExists determine whether the process exists\nfunc PidExists(pid int) (bool, error) {\n\treturn ps.PidExists(pid)\n}\n\n// Process get the all process struct\nfunc Process() ([]Nps, error) {\n\tvar npsArr []Nps\n\tnps, err := ps.Process()\n\tfor i := 0; i < len(nps); i++ {\n\t\tnp := Nps{\n\t\t\tnps[i].Pid,\n\t\t\tnps[i].Name,\n\t\t}\n\n\t\tnpsArr = append(npsArr, np)\n\t}\n\n\treturn npsArr, err\n}\n\n// FindName find the process name by the process id\nfunc FindName(pid int) (string, error) {\n\treturn ps.FindName(pid)\n}\n\n// FindNames find the all process name\nfunc FindNames() ([]string, error) {\n\treturn ps.FindNames()\n}\n\n// FindIds finds the all processes named with a subset\n// of \"name\" (case insensitive),\n// return matched IDs.\nfunc FindIds(name string) ([]int, error) {\n\treturn ps.FindIds(name)\n}\n\n// FindPath find the process path by the process pid\nfunc FindPath(pid int) (string, error) {\n\treturn ps.FindPath(pid)\n}\n\n// Run run a cmd shell\nfunc Run(path string) ([]byte, error) {\n\treturn ps.Run(path)\n}\n\n// Kill kill the process by PID\nfunc Kill(pid int) error {\n\treturn ps.Kill(pid)\n}\n"
  },
  {
    "path": "robot_info_test.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\npackage robotgo_test\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/go-vgo/robotgo\"\n\t\"github.com/vcaesar/tt\"\n)\n\nfunc TestGetVer(t *testing.T) {\n\tfmt.Println(\"go version: \", runtime.Version())\n\tver := robotgo.GetVersion()\n\n\ttt.Expect(t, robotgo.Version, ver)\n}\n\nfunc TestGetScreenSize(t *testing.T) {\n\tx, y := robotgo.GetScreenSize()\n\tlog.Println(\"Get screen size: \", x, y)\n\n\trect := robotgo.GetScreenRect()\n\tfmt.Println(\"Get screen rect: \", rect)\n\n\tx, y = robotgo.Location()\n\tfmt.Println(\"Get location: \", x, y)\n}\n\nfunc TestGetSysScale(t *testing.T) {\n\ts := robotgo.SysScale()\n\tlog.Println(\"SysScale: \", s)\n\n\tf := robotgo.ScaleF()\n\tlog.Println(\"scale: \", f)\n}\n\nfunc TestGetTitle(t *testing.T) {\n\t// just exercise the function, it used to crash with a segfault + \"Maximum\n\t// number of clients reached\"\n\tfor i := 0; i < 128; i++ {\n\t\trobotgo.GetTitle()\n\t}\n}\n"
  },
  {
    "path": "robotgo.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\n/*\nPackage robotgo Go native cross-platform system automation.\n\nPlease make sure Golang, GCC is installed correctly before installing RobotGo;\n\nSee Requirements:\n\n\thttps://github.com/go-vgo/robotgo#requirements\n\nInstallation:\n\nWith Go module support (Go 1.11+), just import:\n\n\timport \"github.com/go-vgo/robotgo\"\n\nOtherwise, to install the robotgo package, run the command:\n\n\tgo get -u github.com/go-vgo/robotgo\n*/\npackage robotgo\n\n/*\n#cgo darwin CFLAGS: -x objective-c -Wno-deprecated-declarations\n#cgo darwin LDFLAGS: -framework Cocoa -framework CoreFoundation -framework IOKit\n#cgo darwin LDFLAGS: -framework Carbon -framework OpenGL\n//\n#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 140400\n#cgo darwin LDFLAGS: -framework ScreenCaptureKit\n#endif\n\n#cgo linux CFLAGS: -I/usr/src\n#cgo linux LDFLAGS: -L/usr/src -lm -lX11 -lXtst\n\n#cgo windows LDFLAGS: -lgdi32 -luser32\n//\n#include \"screen/goScreen.h\"\n#include \"mouse/mouse_c.h\"\n#include \"window/goWindow.h\"\n*/\nimport \"C\"\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"image\"\n\t\"runtime\"\n\t\"syscall\"\n\t\"time\"\n\t\"unsafe\"\n\n\t\"github.com/vcaesar/tt\"\n)\n\nconst (\n\t// Version get the robotgo version\n\tVersion = \"v1.00.0.1189, MT. Baker!\"\n)\n\n// GetVersion get the robotgo version\nfunc GetVersion() string {\n\treturn Version\n}\n\nvar (\n\t// MouseSleep set the mouse default millisecond sleep time\n\tMouseSleep = 0\n\t// KeySleep set the key default millisecond sleep time\n\tKeySleep = 10\n\n\t// DisplayID set the screen display id\n\tDisplayID = -1\n\n\t// NotPid used the hwnd not pid in windows\n\tNotPid bool\n\t// Scale option the os screen scale\n\tScale bool\n)\n\ntype (\n\t// Map a map[string]interface{}\n\tMap map[string]interface{}\n\t// CHex define CHex as c rgb Hex type (C.MMRGBHex)\n\tCHex C.MMRGBHex\n\t// CBitmap define CBitmap as C.MMBitmapRef type\n\tCBitmap C.MMBitmapRef\n\t// Handle define window Handle as C.MData type\n\tHandle C.MData\n)\n\n// Bitmap define the go Bitmap struct\n//\n// The common type conversion of bitmap:\n//\n//\thttps://github.com/go-vgo/robotgo/blob/master/docs/keys.md#type-conversion\ntype Bitmap struct {\n\tImgBuf        *uint8\n\tWidth, Height int\n\n\tBytewidth     int\n\tBitsPixel     uint8\n\tBytesPerPixel uint8\n}\n\n// Point is point struct\ntype Point struct {\n\tX int\n\tY int\n}\n\n// Size is size structure\ntype Size struct {\n\tW, H int\n}\n\n// Rect is rect structure\ntype Rect struct {\n\tPoint\n\tSize\n}\n\n// Try handler(err)\nfunc Try(fun func(), handler func(interface{})) {\n\tdefer func() {\n\t\tif err := recover(); err != nil {\n\t\t\thandler(err)\n\t\t}\n\t}()\n\tfun()\n}\n\n// MilliSleep sleep tm milli second\nfunc MilliSleep(tm int) {\n\ttime.Sleep(time.Duration(tm) * time.Millisecond)\n}\n\n// Sleep time.Sleep tm second\nfunc Sleep(tm int) {\n\ttime.Sleep(time.Duration(tm) * time.Second)\n}\n\n// Deprecated: use the MilliSleep(),\n//\n// MicroSleep time C.microsleep(tm)\nfunc MicroSleep(tm float64) {\n\tC.microsleep(C.double(tm))\n}\n\n// GoString trans C.char to string\nfunc GoString(char *C.char) string {\n\treturn C.GoString(char)\n}\n\n/*\n      _______.  ______ .______       _______  _______ .__   __.\n    /       | /      ||   _  \\     |   ____||   ____||  \\ |  |\n   |   (----`|  ,----'|  |_)  |    |  |__   |  |__   |   \\|  |\n    \\   \\    |  |     |      /     |   __|  |   __|  |  . `  |\n.----)   |   |  `----.|  |\\  \\----.|  |____ |  |____ |  |\\   |\n|_______/     \\______|| _| `._____||_______||_______||__| \\__|\n*/\n\n// ToMMRGBHex trans CHex to C.MMRGBHex\nfunc ToMMRGBHex(hex CHex) C.MMRGBHex {\n\treturn C.MMRGBHex(hex)\n}\n\n// UintToHex trans uint32 to robotgo.CHex\nfunc UintToHex(u uint32) CHex {\n\thex := U32ToHex(C.uint32_t(u))\n\treturn CHex(hex)\n}\n\n// U32ToHex trans C.uint32_t to C.MMRGBHex\nfunc U32ToHex(hex C.uint32_t) C.MMRGBHex {\n\treturn C.MMRGBHex(hex)\n}\n\n// U8ToHex trans *C.uint8_t to C.MMRGBHex\nfunc U8ToHex(hex *C.uint8_t) C.MMRGBHex {\n\treturn C.MMRGBHex(*hex)\n}\n\n// PadHex trans C.MMRGBHex to string\nfunc PadHex(hex C.MMRGBHex) string {\n\tcolor := C.pad_hex(hex)\n\tgcolor := C.GoString(color)\n\tC.free(unsafe.Pointer(color))\n\n\treturn gcolor\n}\n\n// PadHexs trans CHex to string\nfunc PadHexs(hex CHex) string {\n\treturn PadHex(C.MMRGBHex(hex))\n}\n\n// HexToRgb trans hex to rgb\nfunc HexToRgb(hex uint32) *C.uint8_t {\n\treturn C.color_hex_to_rgb(C.uint32_t(hex))\n}\n\n// RgbToHex trans rgb to hex\nfunc RgbToHex(r, g, b uint8) C.uint32_t {\n\treturn C.color_rgb_to_hex(C.uint8_t(r), C.uint8_t(g), C.uint8_t(b))\n}\n\n// GetPxColor get the pixel color return C.MMRGBHex\nfunc GetPxColor(x, y int, displayId ...int) C.MMRGBHex {\n\tcx := C.int32_t(x)\n\tcy := C.int32_t(y)\n\n\tdisplay := displayIdx(displayId...)\n\tcolor := C.get_px_color(cx, cy, C.int32_t(display))\n\treturn color\n}\n\n// GetPixelColor get the pixel color return string\nfunc GetPixelColor(x, y int, displayId ...int) string {\n\treturn PadHex(GetPxColor(x, y, displayId...))\n}\n\n// GetLocationColor get the location pos's color\nfunc GetLocationColor(displayId ...int) string {\n\tx, y := Location()\n\treturn GetPixelColor(x, y, displayId...)\n}\n\n// IsMain is main display\nfunc IsMain(displayId int) bool {\n\treturn displayId == GetMainId()\n}\n\nfunc displayIdx(id ...int) int {\n\tdisplay := -1\n\tif DisplayID != -1 {\n\t\tdisplay = DisplayID\n\t}\n\tif len(id) > 0 {\n\t\tdisplay = id[0]\n\t}\n\n\treturn display\n}\n\nfunc getNumDisplays() int {\n\treturn int(C.get_num_displays())\n}\n\n// GetHWNDByPid get the hwnd by pid\nfunc GetHWNDByPid(pid int) int {\n\treturn int(C.get_hwnd_by_pid(C.uintptr(pid)))\n}\n\n// SysScale get the sys scale\nfunc SysScale(displayId ...int) float64 {\n\tdisplay := displayIdx(displayId...)\n\ts := C.sys_scale(C.int32_t(display))\n\treturn float64(s)\n}\n\n// Scaled get the screen scaled return scale size\nfunc Scaled(x int, displayId ...int) int {\n\tf := ScaleF(displayId...)\n\treturn Scaled0(x, f)\n}\n\n// Scaled0 return int(x * f)\nfunc Scaled0(x int, f float64) int {\n\treturn int(float64(x) * f)\n}\n\n// Scaled1 return int(x / f)\nfunc Scaled1(x int, f float64) int {\n\treturn int(float64(x) / f)\n}\n\n// GetScreenSize get the screen size\nfunc GetScreenSize() (int, int) {\n\tsize := C.getMainDisplaySize()\n\treturn int(size.w), int(size.h)\n}\n\n// GetScreenRect get the screen rect (x, y, w, h)\nfunc GetScreenRect(displayId ...int) Rect {\n\tdisplay := -1\n\tif len(displayId) > 0 {\n\t\tdisplay = displayId[0]\n\t}\n\n\trect := C.getScreenRect(C.int32_t(display))\n\tx, y, w, h := int(rect.origin.x), int(rect.origin.y),\n\t\tint(rect.size.w), int(rect.size.h)\n\n\tif runtime.GOOS == \"windows\" {\n\t\t// f := ScaleF(displayId...)\n\t\tf := ScaleF()\n\t\tx, y, w, h = Scaled0(x, f), Scaled0(y, f), Scaled0(w, f), Scaled0(h, f)\n\t}\n\treturn Rect{\n\t\tPoint{X: x, Y: y},\n\t\tSize{W: w, H: h},\n\t}\n}\n\n// GetScaleSize get the screen scale size\nfunc GetScaleSize(displayId ...int) (int, int) {\n\tx, y := GetScreenSize()\n\tf := ScaleF(displayId...)\n\treturn int(float64(x) * f), int(float64(y) * f)\n}\n\n// CaptureScreen capture the screen return bitmap(c struct),\n// use `defer robotgo.FreeBitmap(bitmap)` to free the bitmap\n//\n// robotgo.CaptureScreen(x, y, w, h int)\nfunc CaptureScreen(args ...int) CBitmap {\n\tvar x, y, w, h C.int32_t\n\tdisplayId := -1\n\tif DisplayID != -1 {\n\t\tdisplayId = DisplayID\n\t}\n\n\tif len(args) > 4 {\n\t\tdisplayId = args[4]\n\t}\n\n\tif len(args) > 3 {\n\t\tx = C.int32_t(args[0])\n\t\ty = C.int32_t(args[1])\n\t\tw = C.int32_t(args[2])\n\t\th = C.int32_t(args[3])\n\t} else {\n\t\t// Get the main screen rect.\n\t\trect := GetScreenRect(displayId)\n\t\tif runtime.GOOS == \"windows\" {\n\t\t\tx = C.int32_t(rect.X)\n\t\t\ty = C.int32_t(rect.Y)\n\t\t}\n\n\t\tw = C.int32_t(rect.W)\n\t\th = C.int32_t(rect.H)\n\t}\n\n\tisPid := 0\n\tif NotPid || len(args) > 5 {\n\t\tisPid = 1\n\t}\n\n\tbit := C.capture_screen(x, y, w, h, C.int32_t(displayId), C.int8_t(isPid))\n\treturn CBitmap(bit)\n}\n\n// CaptureGo capture the screen and return bitmap(go struct)\nfunc CaptureGo(args ...int) Bitmap {\n\tbit := CaptureScreen(args...)\n\tdefer FreeBitmap(bit)\n\n\treturn ToBitmap(bit)\n}\n\n// CaptureImg capture the screen and return image.Image, error\nfunc CaptureImg(args ...int) (image.Image, error) {\n\tbit := CaptureScreen(args...)\n\tif unsafe.Pointer(bit) == nil {\n\t\treturn nil, errors.New(\"Capture image not found.\")\n\t}\n\tdefer FreeBitmap(bit)\n\n\treturn ToImage(bit), nil\n}\n\n// FreeBitmap free and dealloc the C bitmap\nfunc FreeBitmap(bitmap CBitmap) {\n\t// C.destroyMMBitmap(bitmap)\n\tC.bitmap_dealloc(C.MMBitmapRef(bitmap))\n}\n\n// FreeBitmapArr free and dealloc the C bitmap array\nfunc FreeBitmapArr(bit ...CBitmap) {\n\tfor i := 0; i < len(bit); i++ {\n\t\tFreeBitmap(bit[i])\n\t}\n}\n\n// ToMMBitmapRef trans CBitmap to C.MMBitmapRef\nfunc ToMMBitmapRef(bit CBitmap) C.MMBitmapRef {\n\treturn C.MMBitmapRef(bit)\n}\n\n// ToBitmap trans C.MMBitmapRef to Bitmap\nfunc ToBitmap(bit CBitmap) Bitmap {\n\tbitmap := Bitmap{\n\t\tImgBuf:        (*uint8)(bit.imageBuffer),\n\t\tWidth:         int(bit.width),\n\t\tHeight:        int(bit.height),\n\t\tBytewidth:     int(bit.bytewidth),\n\t\tBitsPixel:     uint8(bit.bitsPerPixel),\n\t\tBytesPerPixel: uint8(bit.bytesPerPixel),\n\t}\n\n\treturn bitmap\n}\n\n// ToCBitmap trans Bitmap to C.MMBitmapRef\nfunc ToCBitmap(bit Bitmap) CBitmap {\n\tcbitmap := C.createMMBitmap_c(\n\t\t(*C.uint8_t)(bit.ImgBuf),\n\t\tC.int32_t(bit.Width),\n\t\tC.int32_t(bit.Height),\n\t\tC.int32_t(bit.Bytewidth),\n\t\tC.uint8_t(bit.BitsPixel),\n\t\tC.uint8_t(bit.BytesPerPixel),\n\t)\n\n\treturn CBitmap(cbitmap)\n}\n\n// ToImage convert C.MMBitmapRef to standard image.Image\nfunc ToImage(bit CBitmap) image.Image {\n\treturn ToRGBA(bit)\n}\n\n// ToRGBA convert C.MMBitmapRef to standard image.RGBA\nfunc ToRGBA(bit CBitmap) *image.RGBA {\n\tbmp1 := ToBitmap(bit)\n\treturn ToRGBAGo(bmp1)\n}\n\n// ImgToCBitmap trans image.Image to CBitmap\nfunc ImgToCBitmap(img image.Image) CBitmap {\n\treturn ToCBitmap(ImgToBitmap(img))\n}\n\n// ByteToCBitmap trans []byte to CBitmap\nfunc ByteToCBitmap(by []byte) CBitmap {\n\timg, _ := ByteToImg(by)\n\treturn ImgToCBitmap(img)\n}\n\n// SetXDisplayName set XDisplay name (Linux)\nfunc SetXDisplayName(name string) error {\n\tcname := C.CString(name)\n\tstr := C.set_XDisplay_name(cname)\n\tC.free(unsafe.Pointer(cname))\n\n\treturn toErr(str)\n}\n\n// GetXDisplayName get XDisplay name (Linux)\nfunc GetXDisplayName() string {\n\tname := C.get_XDisplay_name()\n\tgname := C.GoString(name)\n\tC.free(unsafe.Pointer(name))\n\n\treturn gname\n}\n\n// CloseMainDisplay close the main X11 display\nfunc CloseMainDisplay() {\n\tC.close_main_display()\n}\n\n// Deprecated: use the ScaledF(),\n//\n// ScaleX get the primary display horizontal DPI scale factor, drop\nfunc ScaleX() int {\n\treturn int(C.scaleX())\n}\n\n/*\n.___  ___.   ______    __    __       _______. _______\n|   \\/   |  /  __  \\  |  |  |  |     /       ||   ____|\n|  \\  /  | |  |  |  | |  |  |  |    |   (----`|  |__\n|  |\\/|  | |  |  |  | |  |  |  |     \\   \\    |   __|\n|  |  |  | |  `--'  | |  `--'  | .----)   |   |  |____\n|__|  |__|  \\______/   \\______/  |_______/    |_______|\n\n*/\n\n// CheckMouse check the mouse button\nfunc CheckMouse(btn string) C.MMMouseButton {\n\t// button = args[0].(C.MMMouseButton)\n\tm1 := map[string]C.MMMouseButton{\n\t\t\"left\":       C.LEFT_BUTTON,\n\t\t\"center\":     C.CENTER_BUTTON,\n\t\t\"right\":      C.RIGHT_BUTTON,\n\t\t\"wheelDown\":  C.WheelDown,\n\t\t\"wheelUp\":    C.WheelUp,\n\t\t\"wheelLeft\":  C.WheelLeft,\n\t\t\"wheelRight\": C.WheelRight,\n\t}\n\tif v, ok := m1[btn]; ok {\n\t\treturn v\n\t}\n\n\treturn C.LEFT_BUTTON\n}\n\n// MouseButtonString converts a C.MMMouseButton to a readable name.\nfunc MouseButtonString(btn C.MMMouseButton) string {\n\tm1 := map[C.MMMouseButton]string{\n\t\tC.LEFT_BUTTON:   \"left\",\n\t\tC.CENTER_BUTTON: \"center\",\n\t\tC.RIGHT_BUTTON:  \"right\",\n\t\tC.WheelDown:     \"wheelDown\",\n\t\tC.WheelUp:       \"wheelUp\",\n\t\tC.WheelLeft:     \"wheelLeft\",\n\t\tC.WheelRight:    \"wheelRight\",\n\t}\n\tif v, ok := m1[btn]; ok {\n\t\treturn v\n\t}\n\n\treturn fmt.Sprintf(\"button%d\", btn)\n}\n\n// MoveScale calculate the os scale factor x, y\nfunc MoveScale(x, y int, displayId ...int) (int, int) {\n\tif Scale || runtime.GOOS == \"windows\" {\n\t\tf := ScaleF()\n\t\tx, y = Scaled1(x, f), Scaled1(y, f)\n\t}\n\n\treturn x, y\n}\n\n// Move move the mouse to (x, y)\n//\n// Examples:\n//\n//\trobotgo.MouseSleep = 100  // 100 millisecond\n//\trobotgo.Move(10, 10)\nfunc Move(x, y int, displayId ...int) {\n\tx, y = MoveScale(x, y, displayId...)\n\n\tcx := C.int32_t(x)\n\tcy := C.int32_t(y)\n\tC.moveMouse(C.MMPointInt32Make(cx, cy))\n\n\tMilliSleep(MouseSleep)\n}\n\n// Deprecated: use the DragSmooth(),\n//\n// Drag drag the mouse to (x, y),\n// It's not valid now, use the DragSmooth()\nfunc Drag(x, y int, args ...string) {\n\tx, y = MoveScale(x, y)\n\n\tvar button C.MMMouseButton = C.LEFT_BUTTON\n\tcx := C.int32_t(x)\n\tcy := C.int32_t(y)\n\n\tif len(args) > 0 {\n\t\tbutton = CheckMouse(args[0])\n\t}\n\n\tC.dragMouse(C.MMPointInt32Make(cx, cy), button)\n\tMilliSleep(MouseSleep)\n}\n\n// DragSmooth drag the mouse like smooth to (x, y)\n//\n// Examples:\n//\n//\trobotgo.DragSmooth(10, 10)\nfunc DragSmooth(x, y int, args ...interface{}) {\n\tToggle(\"left\")\n\tMilliSleep(50)\n\tsmoothMove(x, y, true, args...)\n\tToggle(\"left\", \"up\")\n}\n\nfunc smoothMove(x, y int, drag bool, args ...interface{}) bool {\n\tx, y = MoveScale(x, y)\n\n\tcx := C.int32_t(x)\n\tcy := C.int32_t(y)\n\n\tvar (\n\t\tmouseDelay = 1\n\t\tlow        C.double\n\t\thigh       C.double\n\t)\n\n\tif len(args) > 2 {\n\t\tmouseDelay = args[2].(int)\n\t}\n\n\tif len(args) > 1 {\n\t\tlow = C.double(args[0].(float64))\n\t\thigh = C.double(args[1].(float64))\n\t} else {\n\t\tlow = 1.0\n\t\thigh = 3.0\n\t}\n\n\tvar cbool C.bool\n\tif drag {\n\t\tcbool = C.smoothlyDragMouse(C.MMPointInt32Make(cx, cy), low, high, C.LEFT_BUTTON)\n\t} else {\n\t\tcbool = C.smoothlyMoveMouse(C.MMPointInt32Make(cx, cy), low, high)\n\t}\n\tMilliSleep(MouseSleep + mouseDelay)\n\n\treturn bool(cbool)\n}\n\n// MoveSmooth move the mouse smooth,\n// moves mouse to x, y human like, with the mouse button up.\n//\n// robotgo.MoveSmooth(x, y int, low, high float64, mouseDelay int)\n//\n// Examples:\n//\n//\trobotgo.MoveSmooth(10, 10)\n//\trobotgo.MoveSmooth(10, 10, 1.0, 2.0)\nfunc MoveSmooth(x, y int, args ...interface{}) bool {\n\treturn smoothMove(x, y, false, args...)\n}\n\n// MoveArgs get the mouse relative args\nfunc MoveArgs(x, y int) (int, int) {\n\tmx, my := Location()\n\tmx = mx + x\n\tmy = my + y\n\n\treturn mx, my\n}\n\n// MoveRelative move mouse with relative\nfunc MoveRelative(x, y int) {\n\tMove(MoveArgs(x, y))\n}\n\n// MoveSmoothRelative move mouse smooth with relative\nfunc MoveSmoothRelative(x, y int, args ...interface{}) {\n\tmx, my := MoveArgs(x, y)\n\tMoveSmooth(mx, my, args...)\n}\n\n// Location get the mouse location position return x, y\nfunc Location() (int, int) {\n\tpos := C.location()\n\tx := int(pos.x)\n\ty := int(pos.y)\n\n\tif Scale || runtime.GOOS == \"windows\" {\n\t\tf := ScaleF()\n\t\tx, y = Scaled0(x, f), Scaled0(y, f)\n\t}\n\n\treturn x, y\n}\n\n// ClickV1 click the mouse button\n//\n// robotgo.Click(button string, double bool)\n//\n// Examples:\n//\n//\trobotgo.Click() // default is left button\n//\trobotgo.Click(\"right\")\n//\trobotgo.Click(\"wheelLeft\")\nfunc ClickV1(args ...interface{}) {\n\tvar (\n\t\tbutton C.MMMouseButton = C.LEFT_BUTTON\n\t\tdouble bool\n\t)\n\n\tif len(args) > 0 {\n\t\tbutton = CheckMouse(args[0].(string))\n\t}\n\n\tif len(args) > 1 {\n\t\tdouble = args[1].(bool)\n\t}\n\n\tif !double {\n\t\tC.clickMouse(button)\n\t} else {\n\t\tC.doubleClick(button, 2)\n\t}\n\n\tMilliSleep(MouseSleep)\n}\n\n// Click click the mouse button and return error\n//\n// robotgo.Click(button string, double bool)\n//\n// Examples:\n//\n//\terr := robotgo.Click() // default is left button\n//\terr := robotgo.Click(\"right\")\nfunc Click(args ...interface{}) error {\n\tvar (\n\t\tbutton C.MMMouseButton = C.LEFT_BUTTON\n\t\tdouble bool\n\t\tcount  int\n\t)\n\n\tif len(args) > 0 {\n\t\tbtn, ok := args[0].(string)\n\t\tif !ok {\n\t\t\treturn errors.New(\"first argument must be a button string\")\n\t\t}\n\t\tbutton = CheckMouse(btn)\n\t}\n\n\tif len(args) > 1 {\n\t\tdbl, ok := args[1].(bool)\n\t\tif !ok {\n\t\t\treturn errors.New(\"second argument must be a bool indicating double click\")\n\t\t}\n\t\tdouble = dbl\n\t}\n\tif len(args) > 2 {\n\t\tcount = args[2].(int)\n\t}\n\n\tdefer MilliSleep(MouseSleep)\n\tif !double {\n\t\tif code := C.toggleMouse(true, button); code != 0 {\n\t\t\treturn formatClickError(int(code), button, \"down\", count)\n\t\t}\n\n\t\tMilliSleep(5)\n\t\tcode := C.toggleMouse(false, button)\n\t\treturn formatClickError(int(code), button, \"up\", count)\n\t}\n\n\tcode := C.doubleClick(button, 2)\n\treturn formatClickError(int(code), button, \"double\", 2)\n}\n\n// MultiClick performs multiple clicks and returns error\n//\n// robotgo.MultiClick(button string, count int)\nfunc MultiClick(button string, count int, click ...bool) error {\n\tif count < 1 {\n\t\treturn nil\n\t}\n\tdefer MilliSleep(MouseSleep)\n\n\tif runtime.GOOS == \"darwin\" && len(click) <= 0 {\n\t\tbtn := CheckMouse(button)\n\t\tcode := C.doubleClick(btn, C.int(count))\n\t\treturn formatClickError(int(code), btn, \"down\", count)\n\t}\n\n\tfor i := 0; i < count; i++ {\n\t\tif err := Click(button, false, i+1); err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc formatClickError(code int, button C.MMMouseButton, stage string, count int) error {\n\tif code == 0 {\n\t\treturn nil\n\t}\n\tbtnName := MouseButtonString(button)\n\tdetail := \"\"\n\n\tswitch runtime.GOOS {\n\tcase \"windows\":\n\t\tif code != 0 {\n\t\t\tdetail = syscall.Errno(code).Error()\n\t\t}\n\tcase \"darwin\":\n\t\tcgErrors := map[int]string{\n\t\t\t0:    \"kCGErrorSuccess\",\n\t\t\t1000: \"kCGErrorFailure\",\n\t\t\t1001: \"kCGErrorIllegalArgument\",\n\t\t\t1002: \"kCGErrorInvalidConnection\",\n\t\t\t1003: \"kCGErrorInvalidContext\",\n\t\t\t1004: \"kCGErrorCannotComplete\",\n\t\t\t1005: \"kCGErrorNotImplemented\",\n\t\t\t1006: \"kCGErrorRangeCheck\",\n\t\t\t1007: \"kCGErrorTypeCheck\",\n\t\t\t1008: \"kCGErrorNoCurrentPoint\",\n\t\t\t1010: \"kCGErrorInvalidOperation\",\n\t\t}\n\t\tif v, ok := cgErrors[code]; ok {\n\t\t\tdetail = v\n\t\t}\n\tdefault:\n\t\tif code == 1 {\n\t\t\tdetail = \"XTestFakeButtonEvent returned false\"\n\t\t}\n\t}\n\n\tif detail != \"\" {\n\t\treturn fmt.Errorf(\"click %s failed (%s, count=%d): %s (code=%d)\", stage, btnName, count, detail, code)\n\t}\n\treturn fmt.Errorf(\"click %s failed (%s, count=%d), code=%d\", stage, btnName, count, code)\n}\n\n// MoveClick move and click the mouse\n//\n// robotgo.MoveClick(x, y int, button string, double bool)\n//\n// Examples:\n//\n//\trobotgo.MouseSleep = 100\n//\trobotgo.MoveClick(10, 10)\nfunc MoveClick(x, y int, args ...interface{}) {\n\tMove(x, y)\n\tMilliSleep(50)\n\tClick(args...)\n}\n\n// MovesClick move smooth and click the mouse\n//\n// use the `robotgo.MouseSleep = 100`\nfunc MovesClick(x, y int, args ...interface{}) {\n\tMoveSmooth(x, y)\n\tMilliSleep(50)\n\tClick(args...)\n}\n\n// Toggle toggle the mouse, support button:\n//\n//\t\t\"left\", \"center\", \"right\",\n//\t \"wheelDown\", \"wheelUp\", \"wheelLeft\", \"wheelRight\"\n//\n// Examples:\n//\n//\trobotgo.Toggle(\"left\") // default is down\n//\trobotgo.Toggle(\"left\", \"up\")\nfunc Toggle(key ...interface{}) error {\n\tvar button C.MMMouseButton = C.LEFT_BUTTON\n\tif len(key) > 0 {\n\t\tbutton = CheckMouse(key[0].(string))\n\t}\n\n\tdown := true\n\tif len(key) > 1 && key[1].(string) == \"up\" {\n\t\tdown = false\n\t}\n\n\tcode := C.toggleMouse(C.bool(down), button)\n\tif len(key) > 2 {\n\t\tMilliSleep(MouseSleep)\n\t}\n\treturn formatClickError(int(code), button, \"down\", 1)\n}\n\n// MouseDown send mouse down event\nfunc MouseDown(key ...interface{}) error {\n\treturn Toggle(key...)\n}\n\n// MouseUp send mouse up event\nfunc MouseUp(key ...interface{}) error {\n\tif len(key) <= 0 {\n\t\tkey = append(key, \"left\")\n\t}\n\treturn Toggle(append(key, \"up\")...)\n}\n\n// Scroll scroll the mouse to (x, y)\n//\n// robotgo.Scroll(x, y, msDelay int)\n//\n// Examples:\n//\n//\trobotgo.Scroll(10, 10)\nfunc Scroll(x, y int, args ...int) {\n\tvar msDelay = 10\n\tif len(args) > 0 {\n\t\tmsDelay = args[0]\n\t}\n\n\tcx := C.int(x)\n\tcy := C.int(y)\n\n\tC.scrollMouseXY(cx, cy)\n\tMilliSleep(MouseSleep + msDelay)\n}\n\n// ScrollDir scroll the mouse with direction to (x, \"up\")\n// supported: \"up\", \"down\", \"left\", \"right\"\n//\n// Examples:\n//\n//\trobotgo.ScrollDir(10, \"down\")\n//\trobotgo.ScrollDir(10, \"up\")\nfunc ScrollDir(x int, direction ...interface{}) {\n\td := \"down\"\n\tif len(direction) > 0 {\n\t\td = direction[0].(string)\n\t}\n\n\tif d == \"down\" {\n\t\tScroll(0, -x)\n\t}\n\tif d == \"up\" {\n\t\tScroll(0, x)\n\t}\n\n\tif d == \"left\" {\n\t\tScroll(x, 0)\n\t}\n\tif d == \"right\" {\n\t\tScroll(-x, 0)\n\t}\n\t// MilliSleep(MouseSleep)\n}\n\n// ScrollSmooth scroll the mouse smooth,\n// default scroll 5 times and sleep 100 millisecond\n//\n// robotgo.ScrollSmooth(toy, num, sleep, tox)\n//\n// Examples:\n//\n//\trobotgo.ScrollSmooth(-10)\n//\trobotgo.ScrollSmooth(-10, 6, 200, -10)\nfunc ScrollSmooth(to int, args ...int) {\n\ti := 0\n\tnum := 5\n\tif len(args) > 0 {\n\t\tnum = args[0]\n\t}\n\ttm := 100\n\tif len(args) > 1 {\n\t\ttm = args[1]\n\t}\n\ttox := 0\n\tif len(args) > 2 {\n\t\ttox = args[2]\n\t}\n\n\tfor {\n\t\tScroll(tox, to)\n\t\tMilliSleep(tm)\n\t\ti++\n\t\tif i == num {\n\t\t\tbreak\n\t\t}\n\t}\n\tMilliSleep(MouseSleep)\n}\n\n// ScrollRelative scroll mouse with relative\n//\n// Examples:\n//\n//\trobotgo.ScrollRelative(10, 10)\nfunc ScrollRelative(x, y int, args ...int) {\n\tmx, my := MoveArgs(x, y)\n\tScroll(mx, my, args...)\n}\n\n/*\n____    __    ____  __  .__   __.  _______   ______   ____    __    ____\n\\   \\  /  \\  /   / |  | |  \\ |  | |       \\ /  __  \\  \\   \\  /  \\  /   /\n \\   \\/    \\/   /  |  | |   \\|  | |  .--.  |  |  |  |  \\   \\/    \\/   /\n  \\            /   |  | |  . `  | |  |  |  |  |  |  |   \\            /\n   \\    /\\    /    |  | |  |\\   | |  '--'  |  `--'  |    \\    /\\    /\n    \\__/  \\__/     |__| |__| \\__| |_______/ \\______/      \\__/  \\__/\n\n*/\n\nfunc alertArgs(args ...string) (string, string) {\n\tvar (\n\t\tdefaultBtn = \"Ok\"\n\t\tcancelBtn  = \"Cancel\"\n\t)\n\n\tif len(args) > 0 {\n\t\tdefaultBtn = args[0]\n\t}\n\n\tif len(args) > 1 {\n\t\tcancelBtn = args[1]\n\t}\n\n\treturn defaultBtn, cancelBtn\n}\n\nfunc showAlert(title, msg string, args ...string) bool {\n\tdefaultBtn, cancelBtn := alertArgs(args...)\n\n\tcTitle := C.CString(title)\n\tcMsg := C.CString(msg)\n\tdefaultButton := C.CString(defaultBtn)\n\tcancelButton := C.CString(cancelBtn)\n\n\tcbool := C.showAlert(cTitle, cMsg, defaultButton, cancelButton)\n\tibool := int(cbool)\n\n\tC.free(unsafe.Pointer(cTitle))\n\tC.free(unsafe.Pointer(cMsg))\n\tC.free(unsafe.Pointer(defaultButton))\n\tC.free(unsafe.Pointer(cancelButton))\n\n\treturn ibool == 0\n}\n\n// IsValid valid the window\nfunc IsValid() bool {\n\tabool := C.is_valid()\n\tgbool := bool(abool)\n\treturn gbool\n}\n\n// SetActive set the window active\nfunc SetActive(win Handle) {\n\tSetActiveC(C.MData(win))\n}\n\n// SetActiveC set the window active\nfunc SetActiveC(win C.MData) {\n\tC.set_active(win)\n}\n\n// GetActive get the active window\nfunc GetActive() Handle {\n\treturn Handle(GetActiveC())\n}\n\n// GetActiveC get the active window\nfunc GetActiveC() C.MData {\n\tmdata := C.get_active()\n\t// fmt.Println(\"active----\", mdata)\n\treturn mdata\n}\n\n// MinWindow set the window min\nfunc MinWindow(pid int, args ...interface{}) {\n\tvar (\n\t\tstate = true\n\t\tisPid int\n\t)\n\n\tif len(args) > 0 {\n\t\tstate = args[0].(bool)\n\t}\n\tif len(args) > 1 || NotPid {\n\t\tisPid = 1\n\t}\n\n\tC.min_window(C.uintptr(pid), C.bool(state), C.int8_t(isPid))\n}\n\n// MaxWindow set the window max\nfunc MaxWindow(pid int, args ...interface{}) {\n\tvar (\n\t\tstate = true\n\t\tisPid int\n\t)\n\n\tif len(args) > 0 {\n\t\tstate = args[0].(bool)\n\t}\n\tif len(args) > 1 || NotPid {\n\t\tisPid = 1\n\t}\n\n\tC.max_window(C.uintptr(pid), C.bool(state), C.int8_t(isPid))\n}\n\n// CloseWindow close the window\nfunc CloseWindow(args ...int) {\n\tif len(args) <= 0 {\n\t\tC.close_main_window()\n\t\treturn\n\t}\n\n\tvar pid, isPid int\n\tif len(args) > 0 {\n\t\tpid = args[0]\n\t}\n\tif len(args) > 1 || NotPid {\n\t\tisPid = 1\n\t}\n\n\tC.close_window_by_PId(C.uintptr(pid), C.int8_t(isPid))\n}\n\n// SetHandle set the window handle\nfunc SetHandle(hwnd int) {\n\tchwnd := C.uintptr(hwnd)\n\tC.setHandle(chwnd)\n}\n\n// SetHandlePid set the window handle by pid\nfunc SetHandlePid(pid int, args ...int) {\n\tvar isPid int\n\tif len(args) > 0 || NotPid {\n\t\tisPid = 1\n\t}\n\n\tC.set_handle_pid_mData(C.uintptr(pid), C.int8_t(isPid))\n}\n\n// GetHandById get handle mdata by id\nfunc GetHandById(id int, args ...int) Handle {\n\tisPid := 1\n\tif len(args) > 0 {\n\t\tisPid = args[0]\n\t}\n\treturn GetHandByPid(id, isPid)\n}\n\n// GetHandByPid get handle mdata by pid\nfunc GetHandByPid(pid int, args ...int) Handle {\n\treturn Handle(GetHandByPidC(pid, args...))\n}\n\n// Deprecated: use the GetHandByPid(),\n//\n// GetHandPid get handle mdata by pid\nfunc GetHandPid(pid int, args ...int) Handle {\n\treturn GetHandByPid(pid, args...)\n}\n\n// GetHandByPidC get handle mdata by pid\nfunc GetHandByPidC(pid int, args ...int) C.MData {\n\tvar isPid int\n\tif len(args) > 0 || NotPid {\n\t\tisPid = 1\n\t}\n\n\treturn C.set_handle_pid(C.uintptr(pid), C.int8_t(isPid))\n}\n\n// GetHandle get the window handle\nfunc GetHandle() int {\n\thwnd := C.get_handle()\n\tghwnd := int(hwnd)\n\t// fmt.Println(\"gethwnd---\", ghwnd)\n\treturn ghwnd\n}\n\n// Deprecated: use the GetHandle(),\n//\n// # GetBHandle get the window handle, Wno-deprecated\n//\n// This function will be removed in version v1.0.0\nfunc GetBHandle() int {\n\ttt.Drop(\"GetBHandle\", \"GetHandle\")\n\thwnd := C.b_get_handle()\n\tghwnd := int(hwnd)\n\t//fmt.Println(\"gethwnd---\", ghwnd)\n\treturn ghwnd\n}\n\nfunc cgetTitle(pid, isPid int) string {\n\ttitle := C.get_title_by_pid(C.uintptr(pid), C.int8_t(isPid))\n\tgtitle := C.GoString(title)\n\n\treturn gtitle\n}\n\n// GetTitle get the window title return string\n//\n// Examples:\n//\n//\tfmt.Println(robotgo.GetTitle())\n//\n//\tids, _ := robotgo.FindIds()\n//\trobotgo.GetTitle(ids[0])\nfunc GetTitle(args ...int) string {\n\tif len(args) <= 0 {\n\t\ttitle := C.get_main_title()\n\t\tgtitle := C.GoString(title)\n\t\treturn gtitle\n\t}\n\n\tif len(args) > 1 {\n\t\treturn internalGetTitle(args[0], args[1])\n\t}\n\n\treturn internalGetTitle(args[0])\n}\n\n// GetPid get the process id return int32\nfunc GetPid() int {\n\tpid := C.get_PID()\n\treturn int(pid)\n}\n\n// internalGetBounds get the window bounds\nfunc internalGetBounds(pid, isPid int) (int, int, int, int) {\n\tbounds := C.get_bounds(C.uintptr(pid), C.int8_t(isPid))\n\treturn int(bounds.X), int(bounds.Y), int(bounds.W), int(bounds.H)\n}\n\n// internalGetClient get the window client bounds\nfunc internalGetClient(pid, isPid int) (int, int, int, int) {\n\tbounds := C.get_client(C.uintptr(pid), C.int8_t(isPid))\n\treturn int(bounds.X), int(bounds.Y), int(bounds.W), int(bounds.H)\n}\n\n// Is64Bit determine whether the sys is 64bit\nfunc Is64Bit() bool {\n\tb := C.Is64Bit()\n\treturn bool(b)\n}\n\nfunc internalActive(pid, isPid int) {\n\tC.active_PID(C.uintptr(pid), C.int8_t(isPid))\n}\n\n// ActivePid active the window by Pid,\n// If args[0] > 0 on the Windows platform via a window handle to active\n// func ActivePid(pid int32, args ...int) {\n// \tvar isPid int\n// \tif len(args) > 0 {\n// \t\tisPid = args[0]\n// \t}\n\n// \tC.active_PID(C.uintptr(pid), C.uintptr(isPid))\n// }\n\n// ActiveName active the window by name\n//\n// Examples:\n//\n//\trobotgo.ActiveName(\"chrome\")\nfunc ActiveName(name string) error {\n\tpids, err := FindIds(name)\n\tif err == nil && len(pids) > 0 {\n\t\treturn ActivePid(pids[0])\n\t}\n\n\treturn err\n}\n"
  },
  {
    "path": "robotgo_adb.go",
    "content": "package robotgo\n"
  },
  {
    "path": "robotgo_android.go",
    "content": "package robotgo\n"
  },
  {
    "path": "robotgo_fn_v1.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\npackage robotgo\n\nimport \"github.com/vcaesar/tt\"\n\n// Deprecated: use the Move(),\n//\n// MoveMouse move the mouse\nfunc MoveMouse(x, y int) {\n\tMove(x, y)\n}\n\n// Deprecated: use the DragSmooth(),\n//\n// DragMouse drag the mouse to (x, y),\n// It's same with the DragSmooth() now\nfunc DragMouse(x, y int, args ...interface{}) {\n\tDragSmooth(x, y, args...)\n}\n\n// Deprecated: use the MoveSmooth(),\n//\n// MoveMouseSmooth move the mouse smooth,\n// moves mouse to x, y human like, with the mouse button up.\nfunc MoveMouseSmooth(x, y int, args ...interface{}) bool {\n\treturn MoveSmooth(x, y, args...)\n}\n\n// Deprecated: use the function Location()\n//\n// GetMousePos get the mouse's position return x, y\nfunc GetMousePos() (int, int) {\n\treturn Location()\n}\n\n// Deprecated: use the Click(),\n//\n// # MouseClick click the mouse\n//\n// robotgo.MouseClick(button string, double bool)\nfunc MouseClick(args ...interface{}) {\n\tClick(args...)\n}\n\n// Deprecated: use the TypeStr(),\n//\n// # TypeStringDelayed type string delayed, Wno-deprecated\n//\n// This function will be removed in version v1.0.0\nfunc TypeStringDelayed(str string, delay int) {\n\ttt.Drop(\"TypeStringDelayed\", \"TypeStrDelay\")\n\tTypeStrDelay(str, delay)\n}\n\n// Deprecated: use the ScaledF(),\n//\n// Scale1 get the screen scale (only windows old), drop\nfunc Scale1() int {\n\tdpi := map[int]int{\n\t\t0: 100,\n\t\t// DPI Scaling Level\n\t\t96:  100,\n\t\t120: 125,\n\t\t144: 150,\n\t\t168: 175,\n\t\t192: 200,\n\t\t216: 225,\n\t\t// Custom DPI\n\t\t240: 250,\n\t\t288: 300,\n\t\t384: 400,\n\t\t480: 500,\n\t}\n\n\tx := ScaleX()\n\treturn dpi[x]\n}\n\n// Deprecated: use the ScaledF(),\n//\n// Scale0 return ScaleX() / 0.96, drop\nfunc Scale0() int {\n\treturn int(float64(ScaleX()) / 0.96)\n}\n\n// Deprecated: use the ScaledF(),\n//\n// Mul mul the scale, drop\nfunc Mul(x int) int {\n\ts := Scale1()\n\treturn x * s / 100\n}\n"
  },
  {
    "path": "robotgo_mac.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\n//go:build darwin\n// +build darwin\n\npackage robotgo\n\n/*\n#include <CoreGraphics/CoreGraphics.h>\n*/\nimport \"C\"\n\n// GetMainId get the main display id\nfunc GetMainId() int {\n\treturn int(C.CGMainDisplayID())\n}\n"
  },
  {
    "path": "robotgo_mac_unix.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\n//go:build !windows\n// +build !windows\n\npackage robotgo\n\n// ScaleF get the system scale val\nfunc ScaleF(displayId ...int) float64 {\n\tf := SysScale(displayId...)\n\tif f == 0.0 {\n\t\tf = 1.0\n\t}\n\treturn f\n}\n"
  },
  {
    "path": "robotgo_mac_win.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\n//go:build darwin || windows\n// +build darwin windows\n\npackage robotgo\n\n// GetBounds get the window bounds\nfunc GetBounds(pid int, args ...int) (int, int, int, int) {\n\tvar isPid int\n\tif len(args) > 0 || NotPid {\n\t\tisPid = 1\n\t}\n\n\treturn internalGetBounds(pid, isPid)\n}\n\n// GetClient get the window client bounds\nfunc GetClient(pid int, args ...int) (int, int, int, int) {\n\tvar isPid int\n\tif len(args) > 0 || NotPid {\n\t\tisPid = 1\n\t}\n\n\treturn internalGetClient(pid, isPid)\n}\n\n// internalGetTitle get the window title\nfunc internalGetTitle(pid int, args ...int) string {\n\tvar isPid int\n\tif len(args) > 0 || NotPid {\n\t\tisPid = 1\n\t}\n\tgtitle := cgetTitle(pid, isPid)\n\n\treturn gtitle\n}\n\n// ActivePid active the window by PID,\n//\n// If args[0] > 0 on the Windows platform via a window handle to active\n//\n// Examples:\n//\n//\tids, _ := robotgo.FindIds()\n//\trobotgo.ActivePid(ids[0])\nfunc ActivePid(pid int, args ...int) error {\n\tvar isPid int\n\tif len(args) > 0 || NotPid {\n\t\tisPid = 1\n\t}\n\n\tinternalActive(pid, isPid)\n\treturn nil\n}\n\n// DisplaysNum get the count of displays\nfunc DisplaysNum() int {\n\treturn getNumDisplays()\n}\n\n// Alert show a alert window\n// Displays alert with the attributes.\n// If cancel button is not given, only the default button is displayed\n//\n// Examples:\n//\n//\trobotgo.Alert(\"hi\", \"window\", \"ok\", \"cancel\")\nfunc Alert(title, msg string, args ...string) bool {\n\treturn showAlert(title, msg, args...)\n}\n"
  },
  {
    "path": "robotgo_ocr.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\n//go:build ocr\n// +build ocr\n\npackage robotgo\n\nimport (\n\t\"github.com/otiai10/gosseract/v2\"\n)\n\n// GetText get the image text by tesseract ocr\nfunc GetText(imgPath string, args ...string) (string, error) {\n\tvar lang = \"eng\"\n\n\tif len(args) > 0 {\n\t\tlang = args[0]\n\t\tif lang == \"zh\" {\n\t\t\tlang = \"chi_sim\"\n\t\t}\n\t}\n\n\tclient := gosseract.NewClient()\n\tdefer client.Close()\n\n\tclient.SetImage(imgPath)\n\tclient.SetLanguage(lang)\n\treturn client.Text()\n}\n"
  },
  {
    "path": "robotgo_test.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\n//go:build darwin || windows\n// +build darwin windows\n\npackage robotgo\n\nimport (\n\t\"testing\"\n\n\t\"github.com/vcaesar/tt\"\n)\n\nfunc TestColor(t *testing.T) {\n\ts := GetPixelColor(10, 10)\n\ttt.IsType(t, \"string\", s)\n\ttt.NotEmpty(t, s)\n\n\tc := GetPxColor(10, 10)\n\ts1 := PadHex(c)\n\ttt.Equal(t, s, s1)\n}\n\nfunc TestSize(t *testing.T) {\n\tx, y := GetScreenSize()\n\ttt.NotZero(t, x)\n\ttt.NotZero(t, y)\n\n\tx, y = GetScaleSize()\n\ttt.NotZero(t, x)\n\ttt.NotZero(t, y)\n}\n\nfunc TestMoveMouse(t *testing.T) {\n\tMove(20, 20)\n\tMilliSleep(50)\n\tx, y := Location()\n\n\ttt.Equal(t, 20, x)\n\ttt.Equal(t, 20, y)\n}\n\nfunc TestMoveMouseSmooth(t *testing.T) {\n\tb := MoveSmooth(100, 100)\n\tMilliSleep(50)\n\tx, y := Location()\n\n\ttt.True(t, b)\n\ttt.Equal(t, 100, x)\n\ttt.Equal(t, 100, y)\n}\n\nfunc TestDragMouse(t *testing.T) {\n\tDragSmooth(500, 500)\n\tMilliSleep(50)\n\tx, y := Location()\n\n\ttt.Equal(t, 500, x)\n\ttt.Equal(t, 500, y)\n}\n\nfunc TestScrollMouse(t *testing.T) {\n\tScrollDir(120, \"up\")\n\tScrollDir(100, \"right\")\n\n\tScroll(0, 120)\n\tMilliSleep(100)\n\n\tScroll(210, 210)\n\tMilliSleep(10)\n}\n\nfunc TestMoveRelative(t *testing.T) {\n\tMove(200, 200)\n\tMilliSleep(50)\n\n\tMoveRelative(10, -10)\n\tMilliSleep(50)\n\n\tx, y := Location()\n\ttt.Equal(t, 210, x)\n\ttt.Equal(t, 190, y)\n}\n\nfunc TestMoveSmoothRelative(t *testing.T) {\n\tMove(200, 200)\n\tMilliSleep(50)\n\n\tMoveSmoothRelative(10, -10)\n\tMilliSleep(50)\n\n\tx, y := Location()\n\ttt.Equal(t, 210, x)\n\ttt.Equal(t, 190, y)\n}\n\nfunc TestMouseToggle(t *testing.T) {\n\te := Toggle(\"right\")\n\ttt.Nil(t, e)\n\n\te = Toggle(\"right\", \"up\")\n\ttt.Nil(t, e)\n\n\te = MouseDown(\"left\")\n\ttt.Nil(t, e)\n\n\te = MouseUp(\"left\")\n\ttt.Nil(t, e)\n}\n\nfunc TestKey(t *testing.T) {\n\te := KeyTap(\"v\", \"cmd\")\n\ttt.Nil(t, e)\n\n\te = KeyTap(\"enter\")\n\ttt.Nil(t, e)\n\n\te = KeyToggle(\"v\", \"up\")\n\ttt.Nil(t, e)\n\n\te = KeyDown(\"a\")\n\ttt.Nil(t, e)\n\te = KeyUp(\"a\")\n\ttt.Nil(t, e)\n\n\te = KeyPress(\"b\")\n\ttt.Nil(t, e)\n}\n\nfunc TestClip(t *testing.T) {\n\terr := WriteAll(\"s\")\n\ttt.Nil(t, err)\n\n\ts, e := ReadAll()\n\ttt.Equal(t, \"s\", s)\n\ttt.Nil(t, e)\n}\n\nfunc TestTypeStr(t *testing.T) {\n\tc := CharCodeAt(\"s\", 0)\n\ttt.Equal(t, 115, c)\n\n\te := PasteStr(\"s\")\n\ttt.Nil(t, e)\n\n\ts1 := \"abc\\\\\\\\cd/s@世界\"\n\tuc := ToUC(s1)\n\ttt.Equal(t, \"[a b c \\\\ \\\\ c d / s @ U4e16 U754c]\", uc)\n}\n\nfunc TestKeyCode(t *testing.T) {\n\tm := MouseMap[\"left\"]\n\ttt.Equal(t, 1, m)\n\n\tk := Keycode[\"1\"]\n\ttt.Equal(t, 2, k)\n\n\ts := Special[\"+\"]\n\ttt.Equal(t, \"=\", s)\n\n\ttt.Equal(t, \"0\", Key0)\n\ttt.Equal(t, \"a\", KeyA)\n}\n\nfunc TestImage(t *testing.T) {\n\tbit := CaptureScreen()\n\tdefer FreeBitmap(bit)\n\ttt.NotNil(t, bit)\n\n\timg := ToImage(bit)\n\terr := SavePng(img, \"robot_test.png\")\n\ttt.Nil(t, err)\n\n\timg1, err := CaptureImg(10, 10, 20, 20)\n\ttt.Nil(t, err)\n\te := Save(img1, \"robot_img.jpeg\", 50)\n\ttt.Nil(t, e)\n\n\ttt.Equal(t, 20, Width(img1))\n\ttt.Equal(t, 20, Height(img1))\n\n\tbit1 := ImgToBitmap(img1)\n\ttt.Equal(t, bit1.Width, Width(img1))\n\ttt.Equal(t, bit1.Height, Height(img1))\n}\n\nfunc TestPs(t *testing.T) {\n\tid, err := Pids()\n\ttt.Not(t, \"[]\", id)\n\ttt.IsType(t, \"[]int\", id)\n\ttt.Nil(t, err)\n\n\tps, e := Process()\n\ttt.Not(t, \"[]\", ps)\n\ttt.IsType(t, \"[]robotgo.Nps\", ps)\n\ttt.Nil(t, e)\n\n\tb, e := PidExists(id[0])\n\ttt.Bool(t, b)\n\ttt.Nil(t, e)\n\n\tn, e := FindName(id[0])\n\ttt.NotEmpty(t, n)\n\ttt.Nil(t, e)\n\n\tn1, e := FindNames()\n\ttt.Not(t, \"[]\", n1)\n\ttt.IsType(t, \"[]string\", n1)\n\ttt.Nil(t, e)\n\n\tid, err = FindIds(n1[0])\n\ttt.Not(t, \"[]\", id)\n\ttt.IsType(t, \"[]int\", id)\n\ttt.Nil(t, err)\n\n\tif len(id) > 0 {\n\t\te := KeyTap(\"v\", id[0], \"cmd\")\n\t\ttt.Nil(t, e)\n\t}\n\n\t// n, e = FindPath(id[0])\n\t// tt.NotEmpty(t, n)\n\t// tt.Nil(t, e)\n}\n\n// func TestAlert(t *testing.T) {\n// \tgo func() {\n// \t\tMilliSleep(200)\n// \t\tKeyTap(\"enter\")\n// \t\tlog.Println(\"tap...\")\n// \t}()\n\n// \ti := Alert(\"t\", \"msg\")\n//\ttt.True(t, i)\n// }\n"
  },
  {
    "path": "robotgo_win.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\n//go:build windows\n// +build windows\n\npackage robotgo\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n\n\t// \"github.com/lxn/win\"\n\t\"github.com/tailscale/win\"\n)\n\n// FindWindow find window hwnd by name\nfunc FindWindow(name string) win.HWND {\n\tu1, _ := syscall.UTF16PtrFromString(name)\n\thwnd := win.FindWindow(nil, u1)\n\treturn hwnd\n}\n\n// GetHWND get foreground window hwnd\nfunc GetHWND() win.HWND {\n\thwnd := win.GetForegroundWindow()\n\treturn hwnd\n}\n\n// SendInput send n input event\nfunc SendInput(nInputs uint32, pInputs unsafe.Pointer, cbSize int32) uint32 {\n\treturn win.SendInput(nInputs, pInputs, cbSize)\n}\n\n// SendMsg send a message with hwnd\nfunc SendMsg(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr {\n\treturn win.SendMessage(hwnd, msg, wParam, lParam)\n}\n\n// SetActiveWindow set window active with hwnd\nfunc SetActiveWindow(hwnd win.HWND) win.HWND {\n\treturn win.SetActiveWindow(hwnd)\n}\n\n// SetFocus set window focus with hwnd\nfunc SetFocus(hwnd win.HWND) win.HWND {\n\treturn win.SetFocus(hwnd)\n}\n\n// SetForeg set the window into the foreground by hwnd\nfunc SetForeg(hwnd win.HWND) bool {\n\treturn win.SetForegroundWindow(hwnd)\n}\n\n// GetMain get the main display hwnd\nfunc GetMain() win.HWND {\n\treturn win.GetActiveWindow()\n}\n\n// GetMainId get the main display id\nfunc GetMainId() int {\n\treturn int(GetMain())\n}\n\n// ScaleF get the system scale value\n// if \"displayId == -2\" this function will get the desktop scale value\nfunc ScaleF(displayId ...int) (f float64) {\n\tif len(displayId) > 0 && displayId[0] != -1 {\n\t\tif displayId[0] >= 0 {\n\t\t\tdpi := GetDPI(win.HWND(displayId[0]))\n\t\t\tf = float64(dpi) / 96.0\n\t\t}\n\n\t\tif displayId[0] == -2 {\n\t\t\tf = float64(GetDPI(GetDesktopWindow())) / 96.0\n\t\t}\n\t} else {\n\t\tf = float64(GetMainDPI()) / 96.0\n\t}\n\n\tif f == 0.0 {\n\t\tf = 1.0\n\t}\n\treturn f\n}\n\n// GetDesktopWindow get the desktop window hwnd id\nfunc GetDesktopWindow() win.HWND {\n\treturn win.GetDesktopWindow()\n}\n\n// GetMainDPI get the display dpi\nfunc GetMainDPI() int {\n\treturn int(GetDPI(GetHWND()))\n}\n\n// GetDPI get the window dpi\nfunc GetDPI(hwnd win.HWND) uint32 {\n\treturn win.GetDpiForWindow(hwnd)\n}\n\n// GetSysDPI get the system metrics dpi\nfunc GetSysDPI(idx int32, dpi uint32) int32 {\n\treturn win.GetSystemMetricsForDpi(idx, dpi)\n}\n"
  },
  {
    "path": "robotgo_x11.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\n//go:build !darwin && !windows\n// +build !darwin,!windows\n\npackage robotgo\n\nimport (\n\t\"errors\"\n\t\"log\"\n\n\t\"github.com/robotn/xgb\"\n\t\"github.com/robotn/xgb/xinerama\"\n\t\"github.com/robotn/xgb/xproto\"\n\t\"github.com/robotn/xgbutil\"\n\t\"github.com/robotn/xgbutil/ewmh\"\n)\n\nvar xu *xgbutil.XUtil\n\n// GetBounds get the window bounds\nfunc GetBounds(pid int, args ...int) (int, int, int, int) {\n\tvar isPid int\n\tif len(args) > 0 || NotPid {\n\t\tisPid = 1\n\t\treturn internalGetBounds(pid, isPid)\n\t}\n\n\txid, err := GetXid(xu, pid)\n\tif err != nil {\n\t\tlog.Println(\"Get Xid from Pid errors is: \", err)\n\t\treturn 0, 0, 0, 0\n\t}\n\n\treturn internalGetBounds(int(xid), isPid)\n}\n\n// GetClient get the window client bounds\nfunc GetClient(pid int, args ...int) (int, int, int, int) {\n\tvar isPid int\n\tif len(args) > 0 || NotPid {\n\t\tisPid = 1\n\t\treturn internalGetClient(pid, isPid)\n\t}\n\n\txid, err := GetXid(xu, pid)\n\tif err != nil {\n\t\tlog.Println(\"Get Xid from Pid errors is: \", err)\n\t\treturn 0, 0, 0, 0\n\t}\n\n\treturn internalGetClient(int(xid), isPid)\n}\n\n// internalGetTitle get the window title\nfunc internalGetTitle(pid int, args ...int) string {\n\tvar isPid int\n\tif len(args) > 0 || NotPid {\n\t\tisPid = 1\n\t\treturn cgetTitle(pid, isPid)\n\t}\n\n\txid, err := GetXid(xu, pid)\n\tif err != nil {\n\t\tlog.Println(\"Get Xid from Pid errors is: \", err)\n\t\treturn \"\"\n\t}\n\n\treturn cgetTitle(int(xid), isPid)\n}\n\n// ActivePidC active the window by Pid,\n// If args[0] > 0 on the unix platform via a xid to active\nfunc ActivePidC(pid int, args ...int) error {\n\tvar isPid int\n\tif len(args) > 0 || NotPid {\n\t\tisPid = 1\n\t\tinternalActive(pid, isPid)\n\t\treturn nil\n\t}\n\n\txid, err := GetXid(xu, pid)\n\tif err != nil {\n\t\tlog.Println(\"Get Xid from Pid errors is: \", err)\n\t\treturn err\n\t}\n\n\tinternalActive(int(xid), isPid)\n\treturn nil\n}\n\n// ActivePid active the window by Pid,\n//\n// If args[0] > 0 on the Windows platform via a window handle to active,\n// If args[0] > 0 on the unix platform via a xid to active\nfunc ActivePid(pid int, args ...int) error {\n\tif xu == nil {\n\t\tvar err error\n\t\txu, err = xgbutil.NewConn()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\tif len(args) > 0 {\n\t\terr := ewmh.ActiveWindowReq(xu, xproto.Window(pid))\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t}\n\n\t// get the xid from pid\n\txid, err := GetXidByPid(xu, pid)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\terr = ewmh.ActiveWindowReq(xu, xid)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// GetXid get the xid return window and error\nfunc GetXid(xu *xgbutil.XUtil, pid int) (xproto.Window, error) {\n\tif xu == nil {\n\t\tvar err error\n\t\txu, err = xgbutil.NewConn()\n\t\tif err != nil {\n\t\t\t// log.Println(\"xgbutil.NewConn errors is: \", err)\n\t\t\treturn 0, err\n\t\t}\n\t}\n\n\txid, err := GetXidByPid(xu, pid)\n\treturn xid, err\n}\n\n// Deprecated: use the GetXidByPid(),\n//\n// GetXidFromPid get the xid from pid\nfunc GetXidFromPid(xu *xgbutil.XUtil, pid int) (xproto.Window, error) {\n\treturn GetXidByPid(xu, pid)\n}\n\n// GetXidByPid get the xid from pid\nfunc GetXidByPid(xu *xgbutil.XUtil, pid int) (xproto.Window, error) {\n\twindows, err := ewmh.ClientListGet(xu)\n\tif err != nil {\n\t\treturn 0, err\n\t}\n\n\tfor _, window := range windows {\n\t\twmPid, err := ewmh.WmPidGet(xu, window)\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\n\t\tif uint(pid) == wmPid {\n\t\t\treturn window, nil\n\t\t}\n\t}\n\n\treturn 0, errors.New(\"failed to find a window with a matching pid.\")\n}\n\n// DisplaysNum get the count of displays\nfunc DisplaysNum() int {\n\tc, err := xgb.NewConn()\n\tif err != nil {\n\t\treturn 0\n\t}\n\tdefer c.Close()\n\n\terr = xinerama.Init(c)\n\tif err != nil {\n\t\treturn 0\n\t}\n\n\treply, err := xinerama.QueryScreens(c).Reply()\n\tif err != nil {\n\t\treturn 0\n\t}\n\n\treturn int(reply.Number)\n}\n\n// GetMainId get the main display id\nfunc GetMainId() int {\n\tconn, err := xgb.NewConn()\n\tif err != nil {\n\t\treturn -1\n\t}\n\n\tsetup := xproto.Setup(conn)\n\tdefaultScreen := setup.DefaultScreen(conn)\n\tid := -1\n\tfor i, screen := range setup.Roots {\n\t\tif defaultScreen.Root == screen.Root {\n\t\t\tid = i\n\t\t\tbreak\n\t\t}\n\t}\n\treturn id\n}\n\n// Alert show a alert window\n// Displays alert with the attributes.\n// If cancel button is not given, only the default button is displayed\n//\n// Examples:\n//\n//\trobotgo.Alert(\"hi\", \"window\", \"ok\", \"cancel\")\nfunc Alert(title, msg string, args ...string) bool {\n\tdefaultBtn, cancelBtn := alertArgs(args...)\n\tc := `xmessage -center ` + msg +\n\t\t` -title ` + title + ` -buttons ` + defaultBtn + \":0,\"\n\tif cancelBtn != \"\" {\n\t\tc += cancelBtn + \":1\"\n\t}\n\tc += ` -default ` + defaultBtn\n\tc += ` -geometry 400x200`\n\n\tout, err := Run(c)\n\tif err != nil {\n\t\t// fmt.Println(\"Alert: \", err, \". \", string(out))\n\t\treturn false\n\t}\n\n\tif string(out) == \"1\" {\n\t\treturn false\n\t}\n\treturn true\n}\n"
  },
  {
    "path": "screen/goScreen.h",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n// \n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0> \n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\n#include \"../base/types.h\"\n#include \"../base/pubs.h\"\n#include \"../base/rgb.h\"\n#include \"screengrab_c.h\"\n#include <stdio.h>\n\nvoid padHex(MMRGBHex color, char* hex) {\n\t// Length needs to be 7 because snprintf includes a terminating null.\n\tsnprintf(hex, 7, \"%06x\", color);\n}\n\nchar* pad_hex(MMRGBHex color) {\n\tchar hex[7];\n\tpadHex(color, hex);\n\t// destroyMMBitmap(bitmap);\n\n\tchar* str = (char*)calloc(100, sizeof(char*));\n    if (str) { strcpy(str, hex); }\n\treturn str;\n}\n\nstatic uint8_t rgb[3];\n\nuint8_t* color_hex_to_rgb(uint32_t h) {\n\trgb[0] = RED_FROM_HEX(h);\n\trgb[1] = GREEN_FROM_HEX(h);\n\trgb[2] = BLUE_FROM_HEX(h);\n\treturn rgb;\n}\n\nuint32_t color_rgb_to_hex(uint8_t r, uint8_t g, uint8_t b) {\n\treturn RGB_TO_HEX(r, g, b);\n}\n\nMMRGBHex get_px_color(int32_t x, int32_t y, int32_t display_id) {\n\tMMBitmapRef bitmap;\n\tMMRGBHex color;\n\n\tif (!pointVisibleOnMainDisplay(MMPointInt32Make(x, y))) {\n\t\treturn color;\n\t}\n\n\tbitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, 1, 1), display_id, 0);\n\tcolor = MMRGBHexAtPoint(bitmap, 0, 0);\n\tdestroyMMBitmap(bitmap);\n\n\treturn color;\n}\n\nchar* set_XDisplay_name(char* name) {\n\t#if defined(USE_X11)\n\t\tsetXDisplay(name);\n\t\treturn \"\";\n\t#else\n\t\treturn \"SetXDisplayName is only supported on Linux\";\n\t#endif\n}\n\nchar* get_XDisplay_name() {\n\t#if defined(USE_X11)\n\t\tconst char* display = getXDisplay();\n\t\t\n\t\tchar* sd = (char*)calloc(100, sizeof(char*));\n\t\tif (sd) { strcpy(sd, display); }\n\t\treturn sd;\n\t#else\n\t\treturn \"GetXDisplayName is only supported on Linux\";\n\t#endif\n}\n\nvoid close_main_display() {\n\t#if defined(USE_X11)\n\t\tXCloseMainDisplay();\n\t#else\n\t\t// \n\t#endif\n}\n\nuint32_t get_num_displays() {\n\t#if defined(IS_MACOSX)\n\t\tuint32_t count = 0;\n\t\tif (CGGetActiveDisplayList(0, nil, &count) == kCGErrorSuccess) {\n\t\t\treturn count;\n\t\t}\n\t\treturn 0;\n\t#elif defined(USE_X11)\n\t\treturn 0;\n\t#elif defined(IS_WINDOWS)\n\t\tuint32_t count = 0;\n\t\tif (EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&count)) {\n\t\t\treturn count;\n\t\t}\n\t\treturn 0;\n\t#endif\n}\n\nuintptr get_hwnd_by_pid(uintptr pid) {\n\t#if defined(IS_WINDOWS)\n\t\tHWND hwnd = GetHwndByPid(pid);\n\t\treturn (uintptr)hwnd;\n\t#else\n\t\treturn 0;\n\t#endif\n}\n\nvoid bitmap_dealloc(MMBitmapRef bitmap) {\n\tif (bitmap != NULL) {\n\t\tdestroyMMBitmap(bitmap);\n\t\tbitmap = NULL;\n\t}\n}\n\n// capture_screen capture screen\nMMBitmapRef capture_screen(int32_t x, int32_t y, int32_t w, int32_t h, int32_t display_id, int8_t isPid) {\n\tMMBitmapRef bitmap = copyMMBitmapFromDisplayInRect(MMRectInt32Make(x, y, w, h), display_id, isPid);\n\treturn bitmap;\n}\n\n"
  },
  {
    "path": "screen/screen.go",
    "content": "package screen\n"
  },
  {
    "path": "screen/screen_c.h",
    "content": "//#include \"../base/os.h\"\n\n#if defined(IS_MACOSX)\n\t#include <ApplicationServices/ApplicationServices.h>\n#elif defined(USE_X11)\n\t#include <X11/Xlib.h>\n\t#include <X11/Xresource.h>\n\t// #include \"../base/xdisplay_c.h\"\n#endif\n\nintptr scaleX();\n\ndouble sys_scale(int32_t display_id) {\n\t#if defined(IS_MACOSX)\n\t\tCGDirectDisplayID displayID = (CGDirectDisplayID) display_id;\n\t\tif (displayID == -1) {\n\t\t\tdisplayID = CGMainDisplayID();\n\t\t}\n\t\t\n\t\tCGDisplayModeRef modeRef = CGDisplayCopyDisplayMode(displayID);\n\t\tdouble pixelWidth = CGDisplayModeGetPixelWidth(modeRef);\n\t\tdouble targetWidth = CGDisplayModeGetWidth(modeRef);\n\t\n\t\treturn pixelWidth / targetWidth;\n\t#elif defined(USE_X11)\n\t\tDisplay *dpy = XOpenDisplay(NULL);\n\n\t\tint scr = 0; /* Screen number */\n\t\tdouble xres = ((((double) DisplayWidth(dpy, scr)) * 25.4) /\n\t\t\t((double) DisplayWidthMM(dpy, scr)));\n\n\t\tchar *rms = XResourceManagerString(dpy);\n\t\tif (rms) {\n\t\t\tXrmDatabase db = XrmGetStringDatabase(rms);\n\t\t\tif (db) {\n\t\t\t\tXrmValue value;\n\t\t\t\tchar *type = NULL;\n\n\t\t\t\tif (XrmGetResource(db, \"Xft.dpi\", \"String\", &type, &value)) {\n\t\t\t\t\tif (value.addr) {\n\t\t\t\t\t\txres = atof(value.addr);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tXrmDestroyDatabase(db);\n\t\t\t}\n\t\t}\n\t\tXCloseDisplay (dpy);\n\n\t\treturn xres / 96.0;\n   \t#elif defined(IS_WINDOWS)\n   \t\tdouble s = scaleX() / 96.0;\n   \t\treturn s;\n   \t#endif\n}\n\nintptr scaleX(){\n\t#if defined(IS_MACOSX)\n\t\treturn 0;\n\t#elif defined(USE_X11)\n\t\treturn 0;\n\t#elif defined(IS_WINDOWS)\n\t\t// Get desktop dc\n\t\tHDC desktopDc = GetDC(NULL);\n\t\t// Get native resolution\n\t\tintptr horizontalDPI = GetDeviceCaps(desktopDc, LOGPIXELSX);\n\t\treturn horizontalDPI;\n\t#endif\n}\n\nMMSizeInt32 getMainDisplaySize(void) {\n#if defined(IS_MACOSX)\n\tCGDirectDisplayID displayID = CGMainDisplayID();\n\tCGRect displayRect = CGDisplayBounds(displayID);\n\t\n\tCGSize size = displayRect.size;\n\treturn MMSizeInt32Make((int32_t)size.width, (int32_t)size.height);\n#elif defined(USE_X11)\n\tDisplay *display = XGetMainDisplay();\n\tconst int screen = DefaultScreen(display);\n\n\treturn MMSizeInt32Make(\n\t\t\t\t\t\t(int32_t)DisplayWidth(display, screen),\n\t                \t(int32_t)DisplayHeight(display, screen));\n#elif defined(IS_WINDOWS)\n\treturn MMSizeInt32Make(\n \t\t\t\t\t\t(int32_t)GetSystemMetrics(SM_CXSCREEN),\n \t\t                (int32_t)GetSystemMetrics(SM_CYSCREEN));\n#endif\n}\n\nMMRectInt32 getScreenRect(int32_t display_id) {\n#if defined(IS_MACOSX)\n\tCGDirectDisplayID displayID = (CGDirectDisplayID) display_id;\n\tif (display_id == -1) {\n\t\tdisplayID = CGMainDisplayID();\n\t}\n\tCGRect displayRect = CGDisplayBounds(displayID);\n\n\tCGPoint point = displayRect.origin;\n\tCGSize size = displayRect.size;\n\treturn MMRectInt32Make(\n\t\t(int32_t)point.x, (int32_t)point.y,\n\t\t(int32_t)size.width, (int32_t)size.height);\n#elif defined(USE_X11)\n\tDisplay *display = XGetMainDisplay();\n\tconst int screen = DefaultScreen(display);\n\n\treturn MMRectInt32Make(\n\t\t\t\t\t(int32_t)0, (int32_t)0,\n\t\t\t\t\t(int32_t)DisplayWidth(display, screen),\n\t                (int32_t)DisplayHeight(display, screen));\n#elif defined(IS_WINDOWS)\n\tif (GetSystemMetrics(SM_CMONITORS) == 1 \n\t\t\t|| display_id == -1 || display_id == 0) {\n \t\treturn MMRectInt32Make(\n\t\t\t\t\t\t(int32_t)0,\n\t\t\t\t\t\t(int32_t)0,\n\t\t\t \t\t\t(int32_t)GetSystemMetrics(SM_CXSCREEN),\n \t\t                (int32_t)GetSystemMetrics(SM_CYSCREEN));\n \t} else {\n \t\treturn MMRectInt32Make(\n\t\t\t \t\t\t(int32_t)GetSystemMetrics(SM_XVIRTUALSCREEN),\n\t\t\t\t\t\t(int32_t)GetSystemMetrics(SM_YVIRTUALSCREEN),\n\t\t\t\t\t\t(int32_t)GetSystemMetrics(SM_CXVIRTUALSCREEN),\n \t\t                (int32_t)GetSystemMetrics(SM_CYVIRTUALSCREEN));\n \t}\n#endif\n}\n\nbool pointVisibleOnMainDisplay(MMPointInt32 point){\n\tMMSizeInt32 displaySize = getMainDisplaySize();\n\treturn point.x < displaySize.w && point.y < displaySize.h;\n}\n"
  },
  {
    "path": "screen/screengrab_c.h",
    "content": "#include \"../base/bitmap_free_c.h\"\n#include <stdlib.h> /* malloc() */\n\n#if defined(IS_MACOSX)\n\t#include <OpenGL/OpenGL.h>\n\t#include <OpenGL/gl.h>\n\t#include <ApplicationServices/ApplicationServices.h>\n\t#include <ScreenCaptureKit/ScreenCaptureKit.h>\n#elif defined(USE_X11)\n\t#include <X11/Xlib.h>\n\t#include <X11/Xutil.h>\n\t#include \"../base/xdisplay_c.h\"\n#elif defined(IS_WINDOWS)\n\t#include <string.h>\n#endif\n#include \"screen_c.h\"\n\n#if defined(IS_MACOSX) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 140400\n\tstatic CGImageRef capture15(CGDirectDisplayID id, CGRect diIntersectDisplayLocal, CGColorSpaceRef colorSpace) {\n\t\tdispatch_semaphore_t semaphore = dispatch_semaphore_create(0);\n\t\t__block CGImageRef image1 = nil;\n\t\t[SCShareableContent getShareableContentWithCompletionHandler:^(SCShareableContent* content, NSError* error) {\n\t\t\t@autoreleasepool {\n\t\t\t\tif (error) {\n\t\t\t\t\tdispatch_semaphore_signal(semaphore);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tSCDisplay* target = nil;\n\t\t\t\tfor (SCDisplay *display in content.displays) {\n\t\t\t\t\tif (display.displayID == id) {\n\t\t\t\t\t\ttarget = display;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!target) {\n\t\t\t\t\tdispatch_semaphore_signal(semaphore);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tSCContentFilter* filter = [[SCContentFilter alloc] initWithDisplay:target excludingWindows:@[]];\n\t\t\t\tSCStreamConfiguration* config = [[SCStreamConfiguration alloc] init];\n\t\t\t\tconfig.queueDepth = 5;\n\t\t\t\tconfig.sourceRect = diIntersectDisplayLocal;\n\t\t\t\tconfig.width = diIntersectDisplayLocal.size.width * sys_scale(id);\n\t\t\t\tconfig.height = diIntersectDisplayLocal.size.height * sys_scale(id);\n\t\t\t\tconfig.scalesToFit = false;\n\t\t\t\tconfig.captureResolution = 1;\n\n\t\t\t\t[SCScreenshotManager captureImageWithFilter:filter\n\t\t\t\t\tconfiguration:config\n\t\t\t\t\tcompletionHandler:^(CGImageRef img, NSError* error) {\n\t\t\t\t\t\tif (!error) {\n\t\t\t\t\t\t\timage1 = CGImageCreateCopyWithColorSpace(img, colorSpace);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdispatch_semaphore_signal(semaphore);\n\t\t\t\t}];\n\t\t\t}\n\t\t}];\n\n\t\tdispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);\n\t\tdispatch_release(semaphore);\n\t\treturn image1;\n\t}\n#endif\n\nMMBitmapRef copyMMBitmapFromDisplayInRect(MMRectInt32 rect, int32_t display_id, int8_t isPid) {\n#if defined(IS_MACOSX)\n\tMMBitmapRef bitmap = NULL;\n\tuint8_t *buffer = NULL;\n\tsize_t bufferSize = 0;\n\n\tCGDirectDisplayID displayID = (CGDirectDisplayID) display_id;\n\tif (displayID == -1 || displayID == 0) {\n\t\tdisplayID = CGMainDisplayID();\n\t}\n\n\tMMPointInt32 o = rect.origin; MMSizeInt32 s = rect.size;\n\t#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 140400\n\t\tCGColorSpaceRef color = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);\n\t\tCGImageRef image = capture15(displayID, CGRectMake(o.x, o.y, s.w, s.h), color);\n\t\tCGColorSpaceRelease(color);\n\t#else\n\t\t// This API is deprecated in macos 15, use ScreenCaptureKit's captureScreenshot\n\t\tCGImageRef image = CGDisplayCreateImageForRect(displayID, CGRectMake(o.x, o.y, s.w, s.h));\n\t#endif\n\tif (!image) { return NULL; }\n\t\n\tCFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(image));\n\tif (!imageData) { return NULL; }\n\n\tbufferSize = CFDataGetLength(imageData);\n\tbuffer = malloc(bufferSize);\n\tCFDataGetBytes(imageData, CFRangeMake(0, bufferSize), buffer);\n\n\tbitmap = createMMBitmap_c(buffer, \n\t\t\tCGImageGetWidth(image), CGImageGetHeight(image), CGImageGetBytesPerRow(image), \n\t\t\tCGImageGetBitsPerPixel(image), CGImageGetBitsPerPixel(image) / 8);\n\n\tCFRelease(imageData);\n\tCGImageRelease(image);\n\n\treturn bitmap;\n#elif defined(USE_X11)\n\tMMBitmapRef bitmap;\n\tDisplay *display;\n\tif (display_id == -1) {\n\t\tdisplay = XOpenDisplay(NULL);\n\t} else {\n\t\tdisplay = XGetMainDisplay();\n\t}\n\n\tMMPointInt32 o = rect.origin; MMSizeInt32 s = rect.size;\n\tXImage *image = XGetImage(display, XDefaultRootWindow(display), \n\t\t\t\t\t\t\t(int)o.x, (int)o.y, (unsigned int)s.w, (unsigned int)s.h, \n\t\t\t\t\t\t\tAllPlanes, ZPixmap);\n\tXCloseDisplay(display);\n\tif (image == NULL) { return NULL; }\n\n\tbitmap = createMMBitmap_c((uint8_t *)image->data, \n\t\t\t\ts.w, s.h, (size_t)image->bytes_per_line, \n\t\t\t\t(uint8_t)image->bits_per_pixel, (uint8_t)image->bits_per_pixel / 8);\n\timage->data = NULL; /* Steal ownership of bitmap data so we don't have to copy it. */\n\tXDestroyImage(image);\n\n\treturn bitmap;\n#elif defined(IS_WINDOWS)\n\tMMBitmapRef bitmap;\n\tvoid *data;\n\tHDC screen = NULL, screenMem = NULL;\n\tHBITMAP dib;\n\tBITMAPINFO bi;\n\n\tint32_t x = rect.origin.x, y = rect.origin.y;\n\tint32_t w = rect.size.w, h = rect.size.h;\n\n\t/* Initialize bitmap info. */\n\tbi.bmiHeader.biSize = sizeof(bi.bmiHeader);\n   \tbi.bmiHeader.biWidth = (long) w;\n   \tbi.bmiHeader.biHeight = -(long) h; /* Non-cartesian, please */\n   \tbi.bmiHeader.biPlanes = 1;\n   \tbi.bmiHeader.biBitCount = 32;\n   \tbi.bmiHeader.biCompression = BI_RGB;\n   \tbi.bmiHeader.biSizeImage = (DWORD)(4 * w * h);\n\tbi.bmiHeader.biXPelsPerMeter = 0;\n\tbi.bmiHeader.biYPelsPerMeter = 0;\n\tbi.bmiHeader.biClrUsed = 0;\n\tbi.bmiHeader.biClrImportant = 0;\n\n\tHWND hwnd;\n\tif (display_id == -1 || isPid == 0) {\n\t// \tscreen = GetDC(NULL); /* Get entire screen */\n\t\thwnd = GetDesktopWindow();\n\t} else {\n\t\thwnd = (HWND) (uintptr) display_id;\n\t}\n\tscreen = GetDC(hwnd);\n\t\n\tif (screen == NULL) { return NULL; }\n\n\t// Todo: Use DXGI\n\tscreenMem = CreateCompatibleDC(screen);\n\t/* Get screen data in display device context. */\n   \tdib = CreateDIBSection(screen, &bi, DIB_RGB_COLORS, &data, NULL, 0);\n\n\t/* Copy the data into a bitmap struct. */\n\tBOOL b = (screenMem == NULL) || \n\t\tSelectObject(screenMem, dib) == NULL ||\n\t    !BitBlt(screenMem, (int)0, (int)0, (int)w, (int)h, screen, x, y, SRCCOPY);\n\tif (b) {\n\t\t/* Error copying data. */\n\t\tReleaseDC(hwnd, screen);\n\t\tDeleteObject(dib);\n\t\tif (screenMem != NULL) { DeleteDC(screenMem); }\n\n\t\treturn NULL;\n\t}\n\n\tbitmap = createMMBitmap_c(NULL, w, h, 4 * w, (uint8_t)bi.bmiHeader.biBitCount, 4);\n\n\t/* Copy the data to our pixel buffer. */\n\tif (bitmap != NULL) {\n\t\tbitmap->imageBuffer = malloc(bitmap->bytewidth * bitmap->height);\n\t\tmemcpy(bitmap->imageBuffer, data, bitmap->bytewidth * bitmap->height);\n\t}\n\n\tReleaseDC(hwnd, screen);\n\tDeleteObject(dib);\n\tDeleteDC(screenMem);\n\n\treturn bitmap;\n#endif\n}\n"
  },
  {
    "path": "screen.go",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n//\n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\npackage robotgo\n\nimport (\n\t\"image\"\n\n\t// \"github.com/kbinani/screenshot\"\n\t\"github.com/vcaesar/screenshot\"\n)\n\n// GetDisplayBounds gets the display screen bounds\nfunc GetDisplayBounds(i int) (x, y, w, h int) {\n\tbs := screenshot.GetDisplayBounds(i)\n\treturn bs.Min.X, bs.Min.Y, bs.Dx(), bs.Dy()\n}\n\n// GetDisplayRect gets the display rect\nfunc GetDisplayRect(i int) Rect {\n\tx, y, w, h := GetDisplayBounds(i)\n\treturn Rect{\n\t\tPoint{X: x, Y: y},\n\t\tSize{W: w, H: h}}\n}\n\n// Capture capture the screenshot, use the CaptureImg default\nfunc Capture(args ...int) (*image.RGBA, error) {\n\tdisplayId := 0\n\tif DisplayID != -1 {\n\t\tdisplayId = DisplayID\n\t}\n\n\tif len(args) > 4 {\n\t\tdisplayId = args[4]\n\t}\n\n\tvar x, y, w, h int\n\tif len(args) > 3 {\n\t\tx, y, w, h = args[0], args[1], args[2], args[3]\n\t} else {\n\t\tx, y, w, h = GetDisplayBounds(displayId)\n\t}\n\n\treturn screenshot.Capture(x, y, w, h)\n}\n\n// SaveCapture capture screen and save the screenshot to image\nfunc SaveCapture(path string, args ...int) error {\n\timg, err := CaptureImg(args...)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn Save(img, path)\n}\n"
  },
  {
    "path": "test/index.html",
    "content": "<h1>Type and check the console</h1>\n\n<script>\n    window.onclick = function(events) {\n        console.log({\n            event: \"click\",\n            altKey: events.altKey,\n            shiftKey: events.shiftKey\n        });\n    };\n\n    window.onkeydown = function(events) {\n        console.log({\n            event: \"keydown\",\n            key: events.key,\n            keyCode: events.keyCode,\n            keyChar: events.charCode\n        });\n    };\n\n    window.onkeyup = function(events) {\n        console.log({\n            event: \"keyup\",\n            key: events.key,\n            keyCode: events.keyCode,\n            keyChar: events.charCode\n        });\n    };\n\n    // move\n    window.onmousemove = function(events) {\n        console.log({\n            event: \"move\",\n            x: events.x,\n            y: events.y\n        });\n    }\n</script>"
  },
  {
    "path": "wayland_n.go",
    "content": "// +bulid linux,next\npackage robotgo\n"
  },
  {
    "path": "window/alert_c.h",
    "content": "// #include \"os.h\"\n#if defined(IS_MACOSX)\n\t#include <CoreFoundation/CoreFoundation.h>\n#endif\n\n#if defined(IS_MACOSX)\n\tCFStringRef CFStringCreateWithUTF8String(const char *title) {\n\t\tif (title == NULL) { return NULL; }\n\t\treturn CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);\n\t}\n#endif\n\nint showAlert(const char *title, const char *msg, \n\t\tconst char *defaultButton, const char *cancelButton) {\n\t#if defined(IS_MACOSX)\n\t\tCFStringRef alertHeader = CFStringCreateWithUTF8String(title);\n\t\tCFStringRef alertMessage = CFStringCreateWithUTF8String(msg);\n\t\tCFStringRef defaultButtonTitle = CFStringCreateWithUTF8String(defaultButton);\n\t\tCFStringRef cancelButtonTitle = CFStringCreateWithUTF8String(cancelButton);\n\t\tCFOptionFlags responseFlags;\n\t\t\n\t\tSInt32 err = CFUserNotificationDisplayAlert(\n\t\t\t0.0, kCFUserNotificationNoteAlertLevel, NULL, NULL, NULL, alertHeader, alertMessage,\n\t\t\tdefaultButtonTitle, cancelButtonTitle, NULL, &responseFlags);\n\t\t\t\t\t\t\t\t\t\t\t\t\n\t\tif (alertHeader != NULL) CFRelease(alertHeader);\n\t\tif (alertMessage != NULL) CFRelease(alertMessage);\n\t\tif (defaultButtonTitle != NULL) CFRelease(defaultButtonTitle);\n\t\tif (cancelButtonTitle != NULL) CFRelease(cancelButtonTitle);\n\n\t\tif (err != 0) { return -1; }\n\t\treturn (responseFlags == kCFUserNotificationDefaultResponse) ? 0 : 1;\n\t#elif defined(USE_X11)\n\t\treturn 0;\n\t#else\n\t\t/* TODO: Display custom buttons instead of the pre-defined \"OK\" and \"Cancel\". */\n\t\tint response = MessageBox(NULL, msg, title,\n\t\t\t\t\t\t\t\t(cancelButton == NULL) ? MB_OK : MB_OKCANCEL );\n\t\treturn (response == IDOK) ? 0 : 1;\n\t#endif\n}\n\n"
  },
  {
    "path": "window/goWindow.h",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n// \n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0> \n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\n#include \"alert_c.h\"\n#include \"window.h\"\n#include \"win_sys.h\"\n\nvoid min_window(uintptr pid, bool state, int8_t isPid){\n\t#if defined(IS_MACOSX)\n\t\t// return 0;\n\t\tAXUIElementRef axID = AXUIElementCreateApplication(pid);\n\t\tAXUIElementSetAttributeValue(axID, kAXMinimizedAttribute, \n\t\t\t\t\t\t\t\t\t\tstate ? kCFBooleanTrue : kCFBooleanFalse);\n\t#elif defined(USE_X11)\n\t\t// Ignore X errors\n\t\tXDismissErrors();\n\t\t// SetState((Window)pid, STATE_MINIMIZE, state);\n\t#elif defined(IS_WINDOWS)\n        HWND hwnd = getHwnd(pid, isPid);\n\t\twin_min(hwnd, state);\n\t#endif\n}\n\nvoid max_window(uintptr pid, bool state, int8_t isPid){\n\t#if defined(IS_MACOSX)\n\t\t// return 0;\n\t#elif defined(USE_X11)\n\t\tXDismissErrors();\n\t\t// SetState((Window)pid, STATE_MINIMIZE, false);\n\t\t// SetState((Window)pid, STATE_MAXIMIZE, state);\n\t#elif defined(IS_WINDOWS)\n        HWND hwnd = getHwnd(pid, isPid);\n\t\twin_max(hwnd, state);\n\t#endif\n}\n\nuintptr get_handle(){\n\tMData mData = get_active();\n\n\t#if defined(IS_MACOSX)\n\t\treturn (uintptr)mData.CgID;\n\t#elif defined(USE_X11)\n\t\treturn (uintptr)mData.XWin;\n\t#elif defined(IS_WINDOWS)\n\t\treturn (uintptr)mData.HWnd;\n\t#endif\n}\n\nuintptr b_get_handle() {\n\t#if defined(IS_MACOSX)\n\t\treturn (uintptr)pub_mData.CgID;\n\t#elif defined(USE_X11)\n\t\treturn (uintptr)pub_mData.XWin;\n\t#elif defined(IS_WINDOWS)\n\t\treturn (uintptr)pub_mData.HWnd;\n\t#endif\n}\n\nvoid active_PID(uintptr pid, int8_t isPid){\n\tMData win = set_handle_pid(pid, isPid);\n\tset_active(win);\n}\n"
  },
  {
    "path": "window/pub.h",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n// \n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0> \n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\n// #include \"../base/os.h\"\n#if defined(IS_MACOSX)\n\t#include <dlfcn.h>\n#elif defined(USE_X11)\n\t#include <X11/Xatom.h>\n#endif\n\nstruct _MData{\n\t#if defined(IS_MACOSX)\n\t\tCGWindowID\t\tCgID;\t\t// Handle to a CGWindowID\n\t\tAXUIElementRef\tAxID;\t\t// Handle to a AXUIElementRef\n\t#elif defined(USE_X11)\n\t\tWindow\t\tXWin;\t\t// Handle to an X11 window\n\t#elif defined(IS_WINDOWS)\n\t\tHWND\t\t\tHWnd;\t\t// Handle to a window HWND\n\t\tTCHAR \tTitle[512];\n\t#endif\n};\n\ntypedef struct _MData MData;\nMData pub_mData;\n\nstruct _Bounds {\n\tint32_t\t\tX;\t\t\t\t// Top left X coordinate\n\tint32_t\t\tY;\t\t\t\t// Top left Y coordinate\n\tint32_t\t\tW;\t\t\t\t// bounds width\n\tint32_t\t\tH;\t\t\t\t// bounds height\n};\ntypedef struct _Bounds Bounds;\n\n#if defined(IS_MACOSX)\n\tstatic Boolean(*gAXIsProcessTrustedWithOptions) (CFDictionaryRef);\n\tstatic CFStringRef* gkAXTrustedCheckOptionPrompt;\n\n\tAXError _AXUIElementGetWindow(AXUIElementRef, CGWindowID* out);\n\tstatic AXUIElementRef GetUIElement(CGWindowID win){\n\t\tintptr pid = 0;\n\t\t// double_t pid = 0;\n\t\t// Create array storing window\n\t\tCGWindowID window[1] = { win };\n\t\tCFArrayRef wlist = CFArrayCreate(NULL, (const void**)window, 1, NULL);\n\n\t\t// Get window info\n\t\tCFArrayRef info = CGWindowListCreateDescriptionFromArray(wlist);\n\t\tCFRelease(wlist);\n\n\t\t// Check whether the resulting array is populated\n\t\tif (info != NULL && CFArrayGetCount(info) > 0) {\n\t\t\t// Retrieve description from info array\n\t\t\tCFDictionaryRef desc = (CFDictionaryRef)CFArrayGetValueAtIndex(info, 0);\n\t\t\t// Get window PID\n\t\t\tCFNumberRef data = (CFNumberRef) CFDictionaryGetValue(desc, kCGWindowOwnerPID);\n\t\t\tif (data != NULL) {\n\t\t\t\tCFNumberGetValue(data, kCFNumberIntType, &pid);\n\t\t\t}\n\n\t\t\t// Return result\n\t\t\tCFRelease(info);\n\t\t}\n\n\t\t// Check if PID was retrieved\n\t\tif (pid <= 0) { return NULL; }\n\n\t\t// Create an accessibility object using retrieved PID\n\t\tAXUIElementRef application = AXUIElementCreateApplication(pid);\n\t\tif (application == 0) {return NULL;}\n\n\t\tCFArrayRef windows = NULL;\n\t\t// Get all windows associated with the app\n\t\tAXUIElementCopyAttributeValues(application, kAXWindowsAttribute, 0, 1024, &windows);\n\n\t\t// Reference to resulting value\n\t\tAXUIElementRef result = NULL;\n\n\t\tif (windows != NULL) {\n\t\t\tint count = CFArrayGetCount(windows);\n\t\t\t// Loop all windows in the process\n\t\t\tfor (CFIndex i = 0; i < count; ++i){\n\t\t\t\t// Get the element at the index\n\t\t\t\tAXUIElementRef element = (AXUIElementRef) CFArrayGetValueAtIndex(windows, i);\n\t\t\t\tCGWindowID temp = 0;\n\t\t\t\t// Use undocumented API to get WindowID\n\t\t\t\t_AXUIElementGetWindow(element, &temp);\n\n\t\t\t\tif (temp == win) {\n\t\t\t\t\t// Retain element\n\t\t\t\t\tCFRetain(element);\n\t\t\t\t\tresult = element;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tCFRelease(windows);\n\t\t}\n\n\t\tCFRelease(application);\n\t\treturn result;\n\t}\n#elif defined(USE_X11)\n\t// Error Handling\n\ttypedef int (*XErrorHandler) (Display*, XErrorEvent*);\n\n\tstatic int XHandleError(Display* dp, XErrorEvent* e) { return 0; }\n\t\tXErrorHandler mOld;\n\t\tvoid XDismissErrors (void) {\n\t\t\tDisplay *rDisplay = XOpenDisplay(NULL);\n\t\t\t// Save old handler and dismiss errors\n\t\t\tmOld = XSetErrorHandler(XHandleError);\n\t\t\t// Flush output buffer\n\t\t\tXSync(rDisplay, False);\n\n\t\t\t// Reinstate old handler\n\t\t\tXSetErrorHandler(mOld);\n\t\t\tXCloseDisplay(rDisplay);\n\t\t}\n\n\t// Definitions\n\tstruct Hints{\n\t\tunsigned long Flags;\n\t\tunsigned long Funcs;\n\t\tunsigned long Decorations;\n\t\tsigned   long Mode;\n\t\tunsigned long Stat;\n\t};\n\n\tstatic Atom WM_STATE\t= None;\n\tstatic Atom WM_ABOVE\t= None;\n\tstatic Atom WM_HIDDEN\t= None;\n\tstatic Atom WM_HMAX\t\t= None;\n\tstatic Atom WM_VMAX\t\t= None;\n\n\tstatic Atom WM_DESKTOP\t= None;\n\tstatic Atom WM_CURDESK\t= None;\n\n\tstatic Atom WM_NAME\t\t= None;\n\tstatic Atom WM_UTF8\t\t= None;\n\tstatic Atom WM_PID\t\t= None;\n\tstatic Atom WM_ACTIVE\t= None;\n\tstatic Atom WM_HINTS\t= None;\n\tstatic Atom WM_EXTENTS\t= None;\n\n\t////////////////////////////////////////////////////////////////////////////////\n\n\tstatic void LoadAtoms (void){\n\t\tDisplay *rDisplay = XOpenDisplay(NULL);\n\t\tWM_STATE   = XInternAtom(rDisplay, \"_NET_WM_STATE\",                True);\n\t\tWM_ABOVE   = XInternAtom(rDisplay, \"_NET_WM_STATE_ABOVE\",          True);\n\t\tWM_HIDDEN  = XInternAtom(rDisplay, \"_NET_WM_STATE_HIDDEN\",         True);\n\t\tWM_HMAX    = XInternAtom(rDisplay, \"_NET_WM_STATE_MAXIMIZED_HORZ\", True);\n\t\tWM_VMAX    = XInternAtom(rDisplay, \"_NET_WM_STATE_MAXIMIZED_VERT\", True);\n\n\t\tWM_DESKTOP = XInternAtom(rDisplay, \"_NET_WM_DESKTOP\",              True);\n\t\tWM_CURDESK = XInternAtom(rDisplay, \"_NET_CURRENT_DESKTOP\",         True);\n\n\t\tWM_NAME    = XInternAtom(rDisplay, \"_NET_WM_NAME\",                 True);\n\t\tWM_UTF8    = XInternAtom(rDisplay, \"UTF8_STRING\",                  True);\n\t\tWM_PID     = XInternAtom(rDisplay, \"_NET_WM_PID\",                  True);\n\t\tWM_ACTIVE  = XInternAtom(rDisplay, \"_NET_ACTIVE_WINDOW\",           True);\n\t\tWM_HINTS   = XInternAtom(rDisplay, \"_MOTIF_WM_HINTS\",              True);\n\t\tWM_EXTENTS = XInternAtom(rDisplay, \"_NET_FRAME_EXTENTS\",           True);\n\t\tXCloseDisplay(rDisplay);\n\t}\n\n\t// Functions\n\tstatic void* GetWindowProperty(MData win, Atom atom, uint32_t* items) {\n\t\t// Property variables\n\t\tAtom type; int format;\n\t\tunsigned long  nItems;\n\t\tunsigned long  bAfter;\n\t\tunsigned char* result = NULL;\n\n\t\tDisplay *rDisplay = XOpenDisplay(NULL);\n\t\t// Check the atom\n\t\tif (atom != None) {\n\t\t\t// Retrieve and validate the specified property\n\t\t\tif (!XGetWindowProperty(rDisplay, win.XWin, atom, 0, \n\t\t\t\tBUFSIZ, False, AnyPropertyType, &type, &format, &nItems, &bAfter, &result) \n\t\t\t\t&& result && nItems) {\n\n\t\t\t\t// Copy items result\n\t\t\t\tif (items != NULL) {\n\t\t\t\t\t*items = (uint32_t) nItems;\n\t\t\t\t}\n\t\t\t\tXCloseDisplay(rDisplay);\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\n\t\t// Reset the items result if valid\n\t\tif (items != NULL) { *items = 0; }\n\t\tif (result != NULL) {\n\t\t\tXFree(result);\n\t\t}\n\n\t\tXCloseDisplay(rDisplay);\n\t\treturn NULL;\n\t}\n\n\t//////\n\t#define STATE_TOPMOST  0\n\t#define STATE_MINIMIZE 1\n\t#define STATE_MAXIMIZE 2\n\n\t//////\n\tstatic void SetDesktopForWindow(MData win){\n\t\tDisplay *rDisplay = XOpenDisplay(NULL);\n\t\t// Validate every atom that we want to use\n\t\tif (WM_DESKTOP != None && WM_CURDESK != None) {\n\t\t\t// Get desktop property\n\t\t\tlong* desktop = (long*)GetWindowProperty(win, WM_DESKTOP,NULL);\n\t\t\t// Check result value\n\t\t\tif (desktop != NULL) {\n\t\t\t\t// Retrieve the screen number\n\t\t\t\tXWindowAttributes attr = { 0 };\n\t\t\t\tXGetWindowAttributes(rDisplay, win.XWin, &attr);\n\t\t\t\tint s = XScreenNumberOfScreen(attr.screen);\n\t\t\t\tWindow root = XRootWindow(rDisplay, s);\n\n\t\t\t\t// Prepare an event\n\t\t\t\tXClientMessageEvent e = { 0 };\n\t\t\t\te.window = root; e.format = 32;\n\t\t\t\te.message_type = WM_CURDESK;\n\t\t\t\te.display = rDisplay;\n\t\t\t\te.type = ClientMessage;\n\t\t\t\te.data.l[0] = *desktop;\n\t\t\t\te.data.l[1] = CurrentTime;\n\n\t\t\t\t// Send the message\n\t\t\t\tXSendEvent(rDisplay, root, False, SubstructureNotifyMask | SubstructureRedirectMask, \n\t\t\t\t\t(XEvent*) &e);\n\n\t\t\t\tXFree(desktop);\n\t\t\t}\n\t\t}\n\t\tXCloseDisplay(rDisplay);\n\t}\n\n\tstatic Bounds GetFrame(MData win){\n\t\tBounds frame;\n\t\t// Retrieve frame bounds\n\t\tif (WM_EXTENTS != None) {\n\t\t\tlong* result; uint32_t nItems = 0;\n\t\t\t// Get the window extents property\n\t\t\tresult = (long*) GetWindowProperty(win, WM_EXTENTS, &nItems);\n\t\t\tif (result != NULL) {\n\t\t\t\tif (nItems == 4) {\n\t\t\t\t\tframe.X = (int32_t) result[0];\n\t\t\t\t\tframe.Y = (int32_t) result[2];\n\t\t\t\t\tframe.W = (int32_t) result[0] + (int32_t) result[1];\n\t\t\t\t\tframe.H = (int32_t) result[2] + (int32_t) result[3];\n\t\t\t\t}\n\n\t\t\t\tXFree(result);\n\t\t\t}\n\t\t}\n\t\treturn frame;\n\t}\n\n\n#elif defined(IS_WINDOWS)\n\tHWND getHwnd(uintptr pid, int8_t isPid);\n\t\n\tvoid win_min(HWND hwnd, bool state){\n        if (state) {\n            ShowWindow(hwnd, SW_MINIMIZE);\n        } else {\n            ShowWindow(hwnd, SW_RESTORE);\n        }\n    }\n\n    void win_max(HWND hwnd, bool state){\n        if (state) {\n            ShowWindow(hwnd, SW_MAXIMIZE);\n        } else {\n            ShowWindow(hwnd, SW_RESTORE);\n        }\n    }\n#endif"
  },
  {
    "path": "window/win_sys.h",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n// \n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0>\n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\n// #if defined(USE_X11)\n// \t#include <X11/Xresource.h>\n// #endif\n\nBounds get_client(uintptr pid, int8_t isPid);\n\nBounds get_bounds(uintptr pid, int8_t isPid){\n\t// Check if the window is valid\n\tBounds bounds;\n\tif (!is_valid()) { return bounds; }\n\n    #if defined(IS_MACOSX)\n\t\t// Bounds bounds;\n\t\tAXValueRef axp = NULL;\n\t\tAXValueRef axs = NULL;\n\t\tAXUIElementRef AxID = AXUIElementCreateApplication(pid);\n\t\tAXUIElementRef AxWin = NULL;\n\n\t\t// Get the window from the application\n\t\tif (AXUIElementCopyAttributeValue(AxID, kAXFocusedWindowAttribute, (CFTypeRef *)&AxWin)\n\t\t\t!= kAXErrorSuccess || AxWin == NULL) {\n\t\t\t// If no focused window, try to get the main window\n\t\t\tif (AXUIElementCopyAttributeValue(AxID, kAXMainWindowAttribute, (CFTypeRef *)&AxWin)\n\t\t\t\t!= kAXErrorSuccess || AxWin == NULL) {\n\t\t\t\tgoto exit;\n\t\t\t}\n\t\t}\n\n\t\t// Determine the current point of the window\n\t\tif (AXUIElementCopyAttributeValue(AxWin, kAXPositionAttribute, (CFTypeRef*) &axp)\n\t\t\t!= kAXErrorSuccess || axp == NULL) {\n\t\t\tgoto exit;\n\t\t}\n\n\t\t// Determine the current size of the window\n\t\tif (AXUIElementCopyAttributeValue(AxWin, kAXSizeAttribute, (CFTypeRef*) &axs)\n\t\t\t!= kAXErrorSuccess || axs == NULL) {\n\t\t\tgoto exit;\n\t\t}\n\n\t\tCGPoint p; CGSize s;\n\t\t// Attempt to convert both values into atomic types\n\t\tif (AXValueGetValue(axp, kAXValueCGPointType, &p) &&\n\t\t\tAXValueGetValue(axs, kAXValueCGSizeType, &s)) {\n\t\t\tbounds.X = p.x;\n\t\t\tbounds.Y = p.y;\n\t\t\tbounds.W = s.width;\n\t\t\tbounds.H = s.height;\n\t\t}\n\n\texit:\n\t\tif (axp != NULL) { CFRelease(axp); }\n\t\tif (axs != NULL) { CFRelease(axs); }\n\t\tif (AxWin != NULL) { CFRelease(AxWin); }\n\t\tif (AxID != NULL) { CFRelease(AxID); }\n\n\t\treturn bounds;\n    #elif defined(USE_X11)\n        // Ignore X errors\n        XDismissErrors();\n        MData win;\n        win.XWin = (Window)pid;\n\n        Bounds client = get_client(pid, isPid);\n        Bounds frame = GetFrame(win);\n\n        bounds.X = client.X - frame.X;\n        bounds.Y = client.Y - frame.Y;\n        bounds.W = client.W + frame.W;\n        bounds.H = client.H + frame.H;\n\n        return bounds;\n    #elif defined(IS_WINDOWS)\n        HWND hwnd = getHwnd(pid, isPid);\n\n        RECT rect = { 0 };\n        GetWindowRect(hwnd, &rect);\n\n        bounds.X = rect.left;\n        bounds.Y = rect.top;\n        bounds.W = rect.right - rect.left;\n        bounds.H = rect.bottom - rect.top;\n\n        return bounds;\n    #endif\n}\n\nBounds get_client(uintptr pid, int8_t isPid) {\n\t// Check if the window is valid\n\tBounds bounds;\n\tif (!is_valid()) { return bounds; }\n\n\t#if defined(IS_MACOSX)\n\t\treturn get_bounds(pid, isPid);\n\t#elif defined(USE_X11)\n        Display *rDisplay = XOpenDisplay(NULL);\n\n\t\t// Ignore X errors\n\t\tXDismissErrors();\n\t\tMData win;\n        win.XWin = (Window)pid;\n\n\t\t// Property variables\n\t\tWindow root, parent;\n\t\tWindow* children;\n\t\tunsigned int count;\n\t\tint32_t x = 0, y = 0;\n\n\t\t// Check if the window is the root\n\t\tXQueryTree(rDisplay, win.XWin, &root, &parent, &children, &count);\n\t\tif (children) { XFree(children); }\n\n\t\t// Retrieve window attributes\n\t\tXWindowAttributes attr = { 0 };\n\t\tXGetWindowAttributes(rDisplay, win.XWin, &attr);\n\n\t\t// Coordinates must be translated\n\t\tif (parent != attr.root) {\n\t\t\tXTranslateCoordinates(rDisplay, win.XWin, attr.root, attr.x, attr.y, &x, &y, &parent);\n\t\t} else {\n\t\t\tx = attr.x;\n\t\t\ty = attr.y;\n\t\t}\n\n\t\t// Return resulting window bounds\n\t\tbounds.X = x;\n\t\tbounds.Y = y;\n\t\tbounds.W = attr.width;\n\t\tbounds.H = attr.height;\n\t\tXCloseDisplay(rDisplay);\n\n\t\treturn bounds;\n\t#elif defined(IS_WINDOWS)\n\t\tHWND hwnd = getHwnd(pid, isPid);\n\n\t\tRECT rect = { 0 };\n\t\tGetClientRect(hwnd, &rect);\n\n\t\tPOINT point;\n\t\tpoint.x = rect.left;\n\t\tpoint.y = rect.top;\n\n\t\t// Convert the client point to screen\n\t\tClientToScreen(hwnd, &point);\n\n\t\tbounds.X = point.x;\n\t\tbounds.Y = point.y;\n\t\tbounds.W = rect.right - rect.left;\n\t\tbounds.H = rect.bottom - rect.top;\n\n\t\treturn bounds;\n\t#endif\n}\n"
  },
  {
    "path": "window/window.go",
    "content": "package window\n"
  },
  {
    "path": "window/window.h",
    "content": "// Copyright (c) 2016-2025 AtomAI, All rights reserved.\n// \n// See the COPYRIGHT file at the top-level directory of this distribution and at\n// https://github.com/go-vgo/robotgo/blob/master/LICENSE\n//\n// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or\n// http://www.apache.org/licenses/LICENSE-2.0> \n//\n// This file may not be copied, modified, or distributed\n// except according to those terms.\n\n#include \"pub.h\"\n\nbool setHandle(uintptr handle);\nbool is_valid();\nbool IsAxEnabled(bool options);\n\nMData get_active(void);\nvoid initWindow(uintptr handle);\nchar* get_title_by_hand(MData m_data);\nvoid close_window_by_Id(MData m_data);\n\n// int findwindow()\nuintptr initHandle = 0;\n\nvoid initWindow(uintptr handle){\n#if defined(IS_MACOSX)\n\tpub_mData.CgID = 0;\n\tpub_mData.AxID = 0;\n#elif defined(USE_X11)\n\tDisplay *rDisplay = XOpenDisplay(NULL);\n\t// If atoms loaded\n\tif (WM_PID == None) {\n\t\t// Load all necessary atom properties\n\t\tif (rDisplay != NULL) {LoadAtoms();}\n\t}\n\n\tpub_mData.XWin = 0;\n\tXCloseDisplay(rDisplay);\n#elif defined(IS_WINDOWS)\n\tpub_mData.HWnd = 0;\n#endif\n\tsetHandle(handle);\n}\n\nbool Is64Bit() {\n\t#ifdef RobotGo_64\n\t\treturn true;\n\t#endif\n\n\treturn false;\n}\n\nMData set_handle_pid(uintptr pid, int8_t isPid){\n\tMData win;\n\t#if defined(IS_MACOSX)\n\t\t// Handle to a AXUIElementRef\n\t\twin.AxID = AXUIElementCreateApplication(pid);\n\t#elif defined(USE_X11)\n\t\twin.XWin = (Window)pid;  // Handle to an X11 window\n\t#elif defined(IS_WINDOWS)\n\t\t// win.HWnd = (HWND)pid;\t\t// Handle to a window HWND\n        win.HWnd = getHwnd(pid, isPid);\n\t#endif\n\n\treturn win;\n}\n\nvoid set_handle_pid_mData(uintptr pid, int8_t isPid){\n\tMData win = set_handle_pid(pid, isPid);\n\tpub_mData = win;\n}\n\nbool is_valid() {\n\tinitWindow(initHandle);\n\tif (!IsAxEnabled(true)) {\n\t\tprintf(\"%s\\n\", \"Window: Accessibility API is disabled! \"\n\t\t\"Failed to enable access for assistive devices. \\n\");\n\t}\n\tMData actdata = get_active();\n\n#if defined(IS_MACOSX)\n\tpub_mData.CgID = actdata.CgID;\n\tpub_mData.AxID = actdata.AxID;\n\tif (pub_mData.CgID == 0 || pub_mData.AxID == 0) { return false; }\n\n\tCFTypeRef r = NULL;\n\t// Attempt to get the window role\n\tif (AXUIElementCopyAttributeValue(pub_mData.AxID, kAXRoleAttribute, &r) == kAXErrorSuccess && r){\n\t\t\tCFRelease(r);\n\t\t\treturn true;\n\t}\n\n\treturn false;\n#elif defined(USE_X11)\n\tpub_mData.XWin = actdata.XWin;\n\tif (pub_mData.XWin == 0) { return false; }\n\n\tDisplay *rDisplay = XOpenDisplay(NULL);\n\t// Check for a valid X-Window display\n\tif (rDisplay == NULL) { return false; }\n\n\t// Ignore X errors\n\tXDismissErrors();\n\n\t// Get the window PID property\n\tvoid* result = GetWindowProperty(pub_mData, WM_PID,NULL);\n\tif (result == NULL) {\n\t\tXCloseDisplay(rDisplay);\n\t\treturn false;\n\t}\n\n\t// Free result and return true\n\tXFree(result);\n\tXCloseDisplay(rDisplay);\n\n\treturn true;\n#elif defined(IS_WINDOWS)\n\tpub_mData.HWnd = actdata.HWnd;\n\tif (pub_mData.HWnd == 0) {\n\t\treturn false;\n\t}\n\n\treturn IsWindow(pub_mData.HWnd) != 0;\n#endif\n}\n\nbool IsAxEnabled(bool options){\n#if defined(IS_MACOSX)\n\t// Statically load all required functions one time\n\tstatic dispatch_once_t once; dispatch_once (&once,\n\t^{\n\t\t// Open the framework\n\t\tvoid* handle = dlopen(\"/System/Library/Frameworks/Application\" \n\t\t\t\"Services.framework/ApplicationServices\", RTLD_LAZY);\n\n\t\t// Validate the handle\n\t\tif (handle != NULL) {\n\t\t\t*(void**) (&gAXIsProcessTrustedWithOptions) = dlsym (handle, \"AXIsProcessTrustedWithOptions\");\n\t\t\tgkAXTrustedCheckOptionPrompt = (CFStringRef*) dlsym (handle, \"kAXTrustedCheckOptionPrompt\");\n\t\t}\n\t});\n\n\t// Check for new OSX 10.9 function\n\tif (gAXIsProcessTrustedWithOptions) {\n\t\t// Check whether to show prompt\n\t\tCFBooleanRef displayPrompt = options ? kCFBooleanTrue : kCFBooleanFalse;\n\n\t\t// Convert display prompt value into a dictionary\n\t\tconst void* k[] = { *gkAXTrustedCheckOptionPrompt };\n\t\tconst void* v[] = { displayPrompt };\n\t\tCFDictionaryRef o = CFDictionaryCreate(NULL, k, v, 1, NULL, NULL);\n\n\t\t// Determine whether the process is actually trusted\n\t\tbool result = (*gAXIsProcessTrustedWithOptions)(o);\n\t\t// Free memory\n\t\tCFRelease(o);\n\t\treturn result;\n\t} else {\n\t\t// Ignore deprecated warnings\n\t\t#pragma clang diagnostic push\n\t\t#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n\n\t\t// Check whether we have accessibility access\n\t\treturn AXAPIEnabled() || AXIsProcessTrusted();\n\t\t#pragma clang diagnostic pop\n\t}\n#elif defined(USE_X11)\n\treturn true;\n#elif defined(IS_WINDOWS)\n\treturn true;\n#endif\n}\n\n// int\nbool setHandle(uintptr handle){\n#if defined(IS_MACOSX)\n\t// Release the AX element\n\tif (pub_mData.AxID != NULL) {\n\t\tCFRelease(pub_mData.AxID);\n\t}\n\n\t// Reset both values\n\tpub_mData.CgID = 0;\n\tpub_mData.AxID = 0;\n\n\tif (handle == 0) {\n\t\t// return 0;\n\t\treturn true;\n\t}\n\n\t// Retrieve the window element\n\tCGWindowID cgID = (CGWindowID)handle;\n\tAXUIElementRef axID = GetUIElement(cgID);\n\tif (axID != NULL){\n\t\tpub_mData.CgID = cgID;\n\t\tpub_mData.AxID = axID;\n\t\t// return 0;\n\t\treturn true;\n\t}\n\n\t// return 1;\n\treturn false;\n#elif defined(USE_X11)\n\tpub_mData.XWin = (Window)handle;\n\tif (handle == 0) {\n\t\treturn true;\n\t}\n\n\tif (is_valid()) {\n\t\treturn true;\n\t}\n\n\tpub_mData.XWin = 0;\n\treturn false;\n#elif defined(IS_WINDOWS)\n\tpub_mData.HWnd = (HWND)handle;\n\tif (handle == 0) {\n\t\treturn true;\n\t}\n\n\tif (is_valid()) {\n\t\treturn true;\n\t}\n\n\tpub_mData.HWnd = 0;\n\treturn false;\n#endif\n}\n\nbool IsTopMost(void){\n\t// Check the window validity\n\tif (!is_valid()) { return false; }\n#if defined(IS_MACOSX)\n\treturn false; // WARNING: Unavailable\n#elif defined(USE_X11)\n\t// Ignore X errors\n\t// XDismissErrors ();\n\t// return GetState (mData.XWin, STATE_TOPMOST);\n#elif defined(IS_WINDOWS)\n\treturn (GetWindowLongPtr(pub_mData.HWnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;\n#endif\n}\n\nbool IsMinimized(void){\n\t// Check the window validity\n\tif (!is_valid()) { return false; }\n#if defined(IS_MACOSX)\n\tCFBooleanRef data = NULL;\n\t// Determine whether the window is minimized\n\tif (AXUIElementCopyAttributeValue(pub_mData.AxID, kAXMinimizedAttribute, \n\t(CFTypeRef*) &data) == kAXErrorSuccess && data != NULL) {\n\t\t// Convert resulting data into a bool\n\t\tbool result = CFBooleanGetValue(data);\n\t\tCFRelease(data);\n\t\treturn result;\n\t}\n\n\treturn false;\n#elif defined(USE_X11)\n\t// Ignore X errors\n\t// XDismissErrors();\n\t// return GetState(mData.XWin, STATE_MINIMIZE);\n#elif defined(IS_WINDOWS)\n\treturn (GetWindowLongPtr(pub_mData.HWnd, GWL_STYLE) & WS_MINIMIZE) != 0;\n#endif\n}\n\n//////\nbool IsMaximized(void){\n\t// Check the window validity\n\tif (!is_valid()) { return false; }\n#if defined(IS_MACOSX)\n\treturn false; // WARNING: Unavailable\n#elif defined(USE_X11)\n\t// Ignore X errors\n\t// XDismissErrors();\n\t// return GetState(mData.XWin, STATE_MAXIMIZE);\n#elif defined(IS_WINDOWS)\n\treturn (GetWindowLongPtr(pub_mData.HWnd, GWL_STYLE) & WS_MAXIMIZE) != 0;\n#endif\n}\n\nvoid set_active(const MData win) {\n\t// Check if the window is valid\n\tif (!is_valid()) { return; }\n#if defined(IS_MACOSX)\n\t// Attempt to raise the specified window object\n\tif (AXUIElementPerformAction(win.AxID, kAXRaiseAction) != kAXErrorSuccess) {\n\t\tpid_t pid = 0;\n\t\t// Attempt to retrieve the PID of the window\n\t\tif (AXUIElementGetPid(win.AxID, &pid) != kAXErrorSuccess || !pid) { return; }\n\n\t\t// Ignore deprecated warnings\n\t\t#pragma clang diagnostic push\n\t\t#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n\n\t\tProcessSerialNumber psn;\n\t\t// Attempt to retrieve the process psn\n\t\tif (GetProcessForPID(pid, &psn) == 0) {\n\t\t\t// Gracefully activate process\n\t\t\tSetFrontProcessWithOptions(&psn, kSetFrontProcessFrontWindowOnly);\n\t\t}\n\n\t\t#pragma clang diagnostic pop\n\t}\n#elif defined(USE_X11)\n\t// Ignore X errors\n\tXDismissErrors();\n\n\t// Go to the specified window's desktop\n\tSetDesktopForWindow(win);\n\tDisplay *rDisplay = XOpenDisplay(NULL);\n\t// Check the atom value\n\tif (WM_ACTIVE != None) {\n\t\t// Retrieve the screen number\n\t\tXWindowAttributes attr = { 0 };\n\t\tXGetWindowAttributes(rDisplay, win.XWin, &attr);\n\t\tint s = XScreenNumberOfScreen(attr.screen);\n\n\t\t// Prepare an event\n\t\tXClientMessageEvent e = { 0 };\n\t\te.window = win.XWin;\n\t\te.format = 32;\n\t\te.message_type = WM_ACTIVE;\n\t\te.display = rDisplay;\n\t\te.type = ClientMessage;\n\t\te.data.l[0] = 2;\n\t\te.data.l[1] = CurrentTime;\n\n\t\t// Send the message\n\t\tXSendEvent(rDisplay, XRootWindow(rDisplay, s), False,\n\t\t\tSubstructureNotifyMask | SubstructureRedirectMask,\n\t\t\t(XEvent*) &e);\n\t} else {\n\t\t// Attempt to raise the specified window\n\t\tXRaiseWindow(rDisplay, win.XWin);\n\t\t// Set the specified window's input focus\n\t\tXSetInputFocus(rDisplay, win.XWin, RevertToParent, CurrentTime);\n\t}\n\tXCloseDisplay(rDisplay);\n#elif defined(IS_WINDOWS)\n\tif (IsMinimized()) {\n\t\tShowWindow(win.HWnd, SW_RESTORE);\n\t}\n\n\tSetForegroundWindow(win.HWnd);\n#endif\n}\n\nMData get_active(void) {\n#if defined(IS_MACOSX)\n\tMData result = {0};\n\t// Ignore deprecated warnings\n\t#pragma clang diagnostic push\n\t#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n\n\tProcessSerialNumber psn; pid_t pid;\n\t// Attempt to retrieve the front process\n\tif (GetFrontProcess(&psn) != 0 || GetProcessPID(&psn, &pid) != 0) {\n\t\treturn result;\n\t}\n\n\t#pragma clang diagnostic pop\n\n\t// Create accessibility object using focused PID\n\tAXUIElementRef focused = AXUIElementCreateApplication(pid);\n\tif (focused == NULL) { return result; } // Verify\n\n\tAXUIElementRef element = NULL;\n\tCGWindowID win = 0;\n\t// Retrieve the currently focused window\n\tif (AXUIElementCopyAttributeValue(focused, kAXFocusedWindowAttribute, (CFTypeRef*) &element)\n\t\t== kAXErrorSuccess && element) {\n\n\t\t// Use undocumented API to get WID\n\t\tif (_AXUIElementGetWindow(element, &win) == kAXErrorSuccess && win) {\n\t\t\t// Manually set internals\n\t\t\tresult.CgID = win;\n\t\t\tresult.AxID = element;\n\t\t} else {\n\t\t\tCFRelease(element);\n\t\t}\n\t}\n\tCFRelease(focused);\n\n\treturn result;\n#elif defined(USE_X11)\n\tMData result = {0};\n\tDisplay *rDisplay = XOpenDisplay(NULL);\n\t// Check X-Window display\n\tif (WM_ACTIVE == None || rDisplay == NULL) {\n\t\treturn result;\n\t}\n\n\t// Ignore X errors\n\tXDismissErrors();\n\n\t// Get the current active window\n\tresult.XWin = XDefaultRootWindow(rDisplay);\n\tvoid* active = GetWindowProperty(result, WM_ACTIVE, NULL);\n\n\t// Check result value\n\tif (active != NULL) {\n\t\t// Extract window from the result\n\t\tlong window = *((long*)active);\n\t\tXFree(active);\n\n\t\tif (window != 0) {\n\t\t\t// Set and return the foreground window\n\t\t\tresult.XWin = (Window)window;\n\t\t\tXCloseDisplay(rDisplay);\n\t\t\treturn result;\n\t\t}\n\t}\n\n\t// Use input focus instead\n\tWindow window = None;\n\tint revert = RevertToNone;\n\tXGetInputFocus(rDisplay, &window, &revert);\n\tXCloseDisplay(rDisplay);\n\n\t// Return foreground window\n\tresult.XWin = window;\n\treturn result;\n#elif defined(IS_WINDOWS)\n\t// Attempt to get the foreground window multiple times in case\n\tMData result = {0};\n\n\tuint8_t times = 0;\n\twhile (++times < 20) {\n\t\tHWND handle;\n\t\thandle = GetForegroundWindow();\n\t\tif (handle != NULL) {\n\t\t\t// mData.HWnd = (uintptr) handle;\n\t\t\tresult.HWnd = (HWND)handle;\n\t\t\treturn result;\n\t\t}\n\t\tSleep(20);\n\t}\n\n\treturn result;\n#endif\n}\n\nvoid SetTopMost(bool state){\n\t// Check window validity\n\tif (!is_valid()) { return; }\n#if defined(IS_MACOSX)\n\t// WARNING: Unavailable\n#elif defined(USE_X11)\n\t// Ignore X errors\n\t// XDismissErrors();\n\t// SetState(pub_mData.XWin, STATE_TOPMOST, state);\n#elif defined(IS_WINDOWS)\n\tSetWindowPos(pub_mData.HWnd, state ? HWND_TOPMOST : HWND_NOTOPMOST,\n\t\t0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);\n#endif\n}\n\nvoid close_main_window () {\n   // Check if the window is valid\n\tif (!is_valid()) { return; }\n\n\tclose_window_by_Id(pub_mData);\n}\n\nvoid close_window_by_PId(uintptr pid, int8_t isPid){\n\tMData win = set_handle_pid(pid, isPid);\n\tclose_window_by_Id(win);\n}\n\n// CloseWindow\nvoid close_window_by_Id(MData m_data){\n\t// Check window validity\n\tif (!is_valid()) { return; }\n#if defined(IS_MACOSX)\n\tAXUIElementRef b = NULL;\n\t// Retrieve the close button of this window\n\tif (AXUIElementCopyAttributeValue(m_data.AxID, kAXCloseButtonAttribute, (CFTypeRef*) &b) \n\t\t== kAXErrorSuccess && b != NULL) {\n\t\t// Simulate button press on the close button\n\t\tAXUIElementPerformAction(b, kAXPressAction);\n\t\tCFRelease(b);\n\t}\n#elif defined(USE_X11)\n\tDisplay *rDisplay = XOpenDisplay(NULL);\n\t// Ignore X errors\n\tXDismissErrors();\n\n\t// Close the window\n\tXDestroyWindow(rDisplay, m_data.XWin);\n\tXCloseDisplay(rDisplay);\n#elif defined(IS_WINDOWS)\n\tPostMessage(m_data.HWnd, WM_CLOSE, 0, 0);\n#endif\n}\n\nchar* get_main_title(){\n\t// Check if the window is valid\n\tif (!is_valid()) { return \"is_valid failed.\"; }\n\n\treturn get_title_by_hand(pub_mData);\n}\n\nchar* get_title_by_pid(uintptr pid, int8_t isPid){\n\tMData win = set_handle_pid(pid, isPid);\n\treturn get_title_by_hand(win);\n}\n\nchar* named(void *result) {\n\tchar *name = (char*)calloc(strlen(result)+1, sizeof(char*));\n\tchar *rptr = (char*)result;\n\tchar *nptr = name;\n\twhile (*rptr) {\n\t\t*nptr = *rptr;\n\t\tnptr++;\n\t\trptr++;\n\t}\n\t*nptr = '\\0';\n\n\treturn name;\n}\n\nchar* get_title_by_hand(MData m_data){\n\t// Check if the window is valid\n\tif (!is_valid()) { return \"is_valid failed.\"; }\n#if defined(IS_MACOSX)\n\tCFStringRef data = NULL;\n\t// Determine the current title of the window\n\tif (AXUIElementCopyAttributeValue(m_data.AxID, kAXTitleAttribute, (CFTypeRef*) &data) == \n\t\t\tkAXErrorSuccess && data != NULL) {\n\t\tchar conv[512];\n\t\t// Convert result to a C-String\n\t\tCFStringGetCString(data, conv, 512, kCFStringEncodingUTF8);\n\t\tCFRelease(data);\n\n\t\tchar* s = (char*)calloc(100, sizeof(char*));\n\t\tif (s) { strcpy(s, conv); }\n\t\t// return (char *)&conv;\n\t\treturn s;\n\t}\n\n\treturn \"\";\n#elif defined(USE_X11)\n\tvoid* result;\n\t// Ignore X errors\n\tXDismissErrors();\n\n\t// Get window title (UTF-8)\n\tresult = GetWindowProperty(m_data, WM_NAME, NULL);\n\t// Check result value\n\tif (result != NULL) {\n\t\t// Convert result to a string\n\t\tchar* name = named(result);\n\t\tXFree(result);\n\n\t\tif (name != NULL) { return name; }\n\t}\n\n\t// Get window title (ASCII)\n\tresult = GetWindowProperty(m_data, XA_WM_NAME, NULL);\n\t// Check result value\n\tif (result != NULL) {\n\t\t// Convert result to a string\n\t\tchar* name = named(result);\n\t\tXFree(result);\n\n\t\treturn name;\n\t}\n\n\treturn \"\";\n#elif defined(IS_WINDOWS)\n\tif (GetWindowText(m_data.HWnd, m_data.Title, 512) > 0){\n\t\tchar* name = m_data.Title;\n\n\t\tchar* str = (char*)calloc(100, sizeof(char*));\n\t\tif (str) { strcpy(str, name); }\n\t\treturn str;\n\t}\n\n\treturn \"\";\n#endif\n}\n\nint32_t get_PID(void) {\n\t// Check window validity\n\tif (!is_valid()) { return 0; }\n#if defined(IS_MACOSX)\n\tpid_t pid = 0;\n\t// Attempt to retrieve the window pid\n\tif (AXUIElementGetPid(pub_mData.AxID, &pid)== kAXErrorSuccess) {\n\t\treturn pid;\n\t}\n\treturn 0;\n#elif defined(USE_X11)\n\t// Ignore X errors\n\tXDismissErrors();\n\n\t// Get the window PID\n\tlong* result = (long*)GetWindowProperty(pub_mData, WM_PID,NULL);\n\t// Check result and convert it\n\tif (result == NULL) { return 0; }\n\t\n\tint32_t pid = (int32_t) *result;\n\tXFree(result);\n\treturn pid;\n#elif defined(IS_WINDOWS)\n\tDWORD id = 0;\n\tGetWindowThreadProcessId(pub_mData.HWnd, &id);\n\treturn id;\n#endif\n}\n"
  },
  {
    "path": "windows_n.go",
    "content": "// +bulid windows,next\npackage robotgo\n"
  }
]