{"id":7363,"date":"2026-01-31T00:01:16","date_gmt":"2026-01-31T08:01:16","guid":{"rendered":"https:\/\/c-for-dummies.com\/blog\/?p=7363"},"modified":"2026-02-07T09:48:14","modified_gmt":"2026-02-07T17:48:14","slug":"reading-the-mouse-in-a-terminal-window","status":"publish","type":"post","link":"https:\/\/c-for-dummies.com\/blog\/?p=7363","title":{"rendered":"Reading the Mouse in a Terminal Window"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/c-for-dummies.com\/blog\/wp-content\/uploads\/2026\/01\/House-mouse-Mus-musculus-shutterstock_321795701-300x167.jpg\" alt=\"\" width=\"300\" height=\"167\" class=\"alignnone size-medium wp-image-7374\" srcset=\"https:\/\/c-for-dummies.com\/blog\/wp-content\/uploads\/2026\/01\/House-mouse-Mus-musculus-shutterstock_321795701-300x167.jpg 300w, https:\/\/c-for-dummies.com\/blog\/wp-content\/uploads\/2026\/01\/House-mouse-Mus-musculus-shutterstock_321795701-1024x569.jpg 1024w, https:\/\/c-for-dummies.com\/blog\/wp-content\/uploads\/2026\/01\/House-mouse-Mus-musculus-shutterstock_321795701-768x427.jpg 768w, https:\/\/c-for-dummies.com\/blog\/wp-content\/uploads\/2026\/01\/House-mouse-Mus-musculus-shutterstock_321795701-1536x853.jpg 1536w, https:\/\/c-for-dummies.com\/blog\/wp-content\/uploads\/2026\/01\/House-mouse-Mus-musculus-shutterstock_321795701-500x278.jpg 500w, https:\/\/c-for-dummies.com\/blog\/wp-content\/uploads\/2026\/01\/House-mouse-Mus-musculus-shutterstock_321795701.jpg 2000w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><br \/>\nAfter I bought a mouse for my first PC, I set out to write a mouse-based program &mdash; a game. (The Microsoft Mouse manual came with the full API.) It was fun and challenging, as all programming tasks should be. Surprisingly, reading the mouse is also possible in a Linux terminal window &mdash; providing that you know the secret.<br \/>\n<!--more--><br \/>\nThe secret: ANSI.<\/p>\n<p>Yes, just as various ANSI commands let you manipulate <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=5270\">text output<\/a> and <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=6482\">cursor position<\/a>, you can also use ANSI commands to read the mouse&#8217;s location, movement, and clicks in a terminal window. But this trick isn&#8217;t without its issues.<\/p>\n<p>To start, the commands to read the mouse are not part of the original ANSI standard. They are, however, available with the xterm extensions, which are implemented in most terminal windows.<\/p>\n<p>Like most other ANSI commands, the mouse commands are delivered by sending a specific string of characters to standard output. The sequence starts with an Escape character (<code>\\e<\/code>) followed by a left bracket and a question mark. Then comes a mode value and finally a little H or little L.<\/p>\n<p>The sequence <code>\\e[?1000h<\/code> activates mouse tracking.<br \/>\nThe sequence <code>\\e[?1000l<\/code> deactivates mouse tracking.<\/p>\n<p>The following code implements these escape sequences as macros, <em>mouse_enable()<\/em> and <em>mouse_disable()<\/em>:<\/p>\n<h3><a href=\"https:\/\/github.com\/dangookin\/C-For-Dummies-Blog\/blob\/master\/2026_01_31-Lesson-a.c\" rel=\"noopener\" target=\"_blank\">2026_01_31-Lesson-a.c<\/a><\/h3>\n<pre class=\"screen\">\r\n#include &lt;stdio.h&gt;\r\n\r\n#define mouse_enable() printf(\"\\e[?1000h\")\r\n#define mouse_disable() printf(\"\\e[?1000l\")\r\n\r\nint main()\r\n{\r\n    <span class=\"comments\">\/* enable mouse reporting *\/<\/span>\r\n    mouse_enable();\r\n\r\n    getchar();\r\n\r\n    <span class=\"comments\">\/* clean-up *\/<\/span>\r\n    mouse_disable();    <span class=\"comments\">\/* disable mouse reporting *\/<\/span>\r\n    return 0;\r\n}<\/pre>\n<p>It&#8217;s important that you disable mouse tracking before the program ends. Failing to do means that mouse activity in the terminal window continues to be monitored, which can really ruin your day. (Issue the <em>reset<\/em> command to restore the terminal to sanity.)<\/p>\n<p>Running this program generates no output unless you click the mouse. When you do, output appears similar to this:<\/p>\n<pre>^[[M ;4^[[M#;4<\/pre>\n<p>Press the Enter key to terminate the program.<\/p>\n<p>When you click the mouse, the output you see reports the button clicked and the mouse&#8217;s location in some cryptic format. What&#8217;s better is to also issue the ANSI &#8220;any event&#8221; tracking sequence, <code>\\e[?1003h<\/code>, which provides more information about the mouse&#8217;s location and button status. The following code provides this update:<\/p>\n<h3><a href=\"https:\/\/github.com\/dangookin\/C-For-Dummies-Blog\/blob\/master\/2026_01_31-Lesson-b.c\" rel=\"noopener\" target=\"_blank\">2026_01_31-Lesson-b.c<\/a><\/h3>\n<pre class=\"screen\">\r\n#include &lt;stdio.h&gt;\r\n\r\n#define mouse_enable() printf(\"\\e[?1000h\")\r\n#define mouse_motion() printf(\"\\e[?1003h\")\r\n#define mouse_disable() printf(\"\\e[?1000l\")\r\n\r\nint main()\r\n{\r\n    <span class=\"comments\">\/* enable mouse reporting *\/<\/span>\r\n    mouse_enable();\r\n    mouse_motion();\r\n\r\n    getchar();\r\n\r\n    <span class=\"comments\">\/* clean-up *\/<\/span>\r\n    mouse_disable();    <span class=\"comments\">\/* disable mouse reporting *\/<\/span>\r\n    return 0;\r\n}<\/pre>\n<p>The <em>mouse_motion()<\/em> macro is assigned to the <code>\\e[?1003h<\/code> escape sequence. When you run the program, moving the mouse immediately generates output. You see something like this:<\/p>\n<pre>^[[MCY.^[[MCZ-^[[MCZ.^[[MCY\/^[[MCX\/^[[MCW0^[[MCV0^[[MCV1^[[MCU1^[[MCU2^[[MCU1^[[MCT1^[[MCS1^[[MCS0^[[MCR0^[[M R0^[[M#R0^[[M R0^[[M#R0<\/pre>\n<p>Each sequence output represents the mouse&#8217;s movement from one character position to the next, as well as any button clicks.<\/p>\n<p>The output can be quite overwhelming, rapidly filling the screen. It&#8217;s also cryptic. To make the output human readable, I recommend adding a fourth macro to the code, <em>mouse_extended()<\/em>, as shown in this final update:<\/p>\n<h3><a href=\"https:\/\/github.com\/dangookin\/C-For-Dummies-Blog\/blob\/master\/2026_01_31-Lesson-c.c\" rel=\"noopener\" target=\"_blank\">2026_01_31-Lesson-c.c<\/a><\/h3>\n<pre class=\"screen\">\r\n#include &lt;stdio.h&gt;\r\n\r\n#define mouse_enable() printf(\"\\e[?1000h\")\r\n#define mouse_motion() printf(\"\\e[?1003h\")\r\n#define mouse_extended() printf(\"\\e[?1006h\")\r\n#define mouse_disable() printf(\"\\e[?1000l\")\r\n\r\nint main()\r\n{\r\n    <span class=\"comments\">\/* enable mouse reporting *\/<\/span>\r\n    mouse_enable();\r\n    mouse_motion();\r\n    mouse_extended();\r\n\r\n    getchar();\r\n\r\n    <span class=\"comments\">\/* clean-up *\/<\/span>\r\n    mouse_disable();    <span class=\"comments\">\/* disable mouse reporting *\/<\/span>\r\n    return 0;\r\n}<\/pre>\n<p>The <em>mouse_extended()<\/em> escape sequence is <code>\\e[?1006h<\/code>. Here&#8217;s a sample run with this macro issued:<\/p>\n<pre>^[[<35;49;15M^[[<35;49;16M^[[<35;49;17M^[[<35;48;17M^[[<35;48;16M^[[<35;47;16M^[[<35;47;17M^[[<35;47;16M^[[<35;46;16M^[[<0;46;16M^[[<0;46;16m<\/pre>\n<p>The sequences generated follow a pattern that offers the mouse's button status, row and column location on the terminal screen. I cover deciphering this information in <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=7378\">next week's Lesson<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Yes, you can read the mouse in a terminal window. <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=7363\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-7363","post","type-post","status-publish","format-standard","hentry","category-main"],"_links":{"self":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/7363","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=7363"}],"version-history":[{"count":9,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/7363\/revisions"}],"predecessor-version":[{"id":7409,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/7363\/revisions\/7409"}],"wp:attachment":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=7363"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=7363"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=7363"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}