{"id":7419,"date":"2026-02-28T00:01:42","date_gmt":"2026-02-28T08:01:42","guid":{"rendered":"https:\/\/c-for-dummies.com\/blog\/?p=7419"},"modified":"2026-03-07T07:46:36","modified_gmt":"2026-03-07T15:46:36","slug":"accessing-the-mouse-in-a-terminal-window","status":"publish","type":"post","link":"https:\/\/c-for-dummies.com\/blog\/?p=7419","title":{"rendered":"Accessing 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 \/>\nThe point of reading and capturing mouse data is to do something at the mouse&#8217;s location. Specifically, the goal is to have the terminal somehow react to a mouse click. Yes, even though C is stream oriented and rarely involves graphics or the mouse, this feat is made possible thanks to ANSI commands.<br \/>\n<!--more--><br \/>\n<a href=\"https:\/\/c-for-dummies.com\/blog\/?p=7411\">Last week&#8217;s Lesson<\/a> covered how to capture and store mouse input. For today&#8217;s lesson, this data is used along with ANSI cursor manipulation sequences to report mouse movement and to set a character at the location in the terminal window where the mouse is clicked.<\/p>\n<p>Seriously, I didn&#8217;t think such a trick would be possible in C without benefit of a library such as Ncurses. But, yes, providing that you&#8217;ve followed along with the last few posts here, this feat is entirely possible.<\/p>\n<p>The following code updates what was presented in last week&#8217;s lesson. I&#8217;ve added two ANSI macros: <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=6457\"><em>clear()<\/em><\/a> and <em>moveto()<\/em> (based on another macro, <em>locate()<\/em>, presented in <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=6579\">an earlier Lesson<\/a>).<\/p>\n<p>Most of new code appear in the <em>main()<\/em> function, where the <em>while<\/em> loop contains an <em>if-else<\/em> decision to output information based on whether the mouse is moving or has been clicked. The screen is updated to reflect the click and button number.<\/p>\n<h3><a href=\"https:\/\/github.com\/dangookin\/C-For-Dummies-Blog\/blob\/master\/2026_02_28-Lesson.c\" rel=\"noopener\" target=\"_blank\">2026_02_28-Lesson.c<\/a><\/h3>\n<pre class=\"screen\">\r\n#include &lt;stdio.h&gt;\r\n#include &lt;stdlib.h&gt;\r\n#include &lt;ctype.h&gt;\r\n#include &lt;termios.h&gt;\r\n#include &lt;unistd.h&gt;\r\n\r\n#define clear() printf(\"\\e[H\\e[2J\")\r\n#define moveto(a,b) printf(\"\\e[%d;%dH\",b,a)\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\nstruct mouse_data {\r\n    int button;\r\n    int column;\r\n    int row;\r\n};\r\n\r\n<span class=\"comments\">\/* read an integer from a string\r\n   Exercise 2026_02 *\/<\/span>\r\nchar *extract(char *s)\r\n{\r\n    static char *sp;\r\n\r\n    <span class=\"comments\">\/* check for recall *\/<\/span>\r\n    if( s != NULL )\r\n        sp = s;\r\n    else\r\n        while( isdigit(*sp) )\r\n            sp++;\r\n\r\n    <span class=\"comments\">\/* find the next digit *\/<\/span>\r\n    while( *sp != '\\0' )\r\n    {\r\n        if( isdigit(*sp) )\r\n        {\r\n            return(sp);\r\n        }\r\n        sp++;\r\n    }\r\n\r\n    return(NULL);\r\n}\r\n\r\n<span class=\"comments\">\/* obtain values from mouse data *\/<\/span>\r\nvoid read_mouse(char *b, struct mouse_data *m)\r\n{\r\n    m-&gt;button = atoi(extract(b));\r\n    m-&gt;column = atoi(extract(NULL));\r\n    m-&gt;row = atoi(extract(NULL));\r\n}\r\n\r\nint main()\r\n{\r\n    struct termios original,noecho;\r\n    struct mouse_data mickey;\r\n    char buffer[13];\r\n    int key;\r\n\r\n    <span class=\"comments\">\/* obtain terminal configuration *\/<\/span>\r\n    tcgetattr(fileno(stdin),&amp;original);\r\n    noecho = original;        <span class=\"comments\">\/* duplicate *\/<\/span>\r\n        <span class=\"comments\">\/* enable raw input *\/<\/span>\r\n    noecho.c_lflag = noecho.c_lflag ^ ICANON;\r\n        <span class=\"comments\">\/* disable full duplex *\/<\/span>\r\n    noecho.c_lflag = noecho.c_lflag ^ ECHO;\r\n        <span class=\"comments\">\/* update terminal definition *\/<\/span>\r\n    tcsetattr(fileno(stdin), TCSANOW, &amp;noecho);\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    <span class=\"comments\">\/* remove line buffering *\/<\/span>\r\n    setvbuf(stdin,NULL,_IONBF,0);\r\n\r\n    <span class=\"comments\">\/* read stdin *\/<\/span>\r\n    clear();\r\n    puts(\"Play with the mouse; press Enter  to end\");\r\n    while( (key=getchar()) != '\\n' )\r\n    {\r\n        read(fileno(stdin),buffer,12);\r\n        buffer[12] = '\\0';        <span class=\"comments\">\/* make it a string *\/<\/span>\r\n        read_mouse(buffer,&amp;mickey);\r\n        if( mickey.button != 35 )\r\n        {\r\n            clear();\r\n            moveto(mickey.column,mickey.row);\r\n            printf(\"%d\",mickey.button);\r\n            moveto(1,1);\r\n            printf(\"Button %d clicked at column %d row %d\\n\",\r\n                    mickey.button,\r\n                    mickey.column,\r\n                    mickey.row\r\n                  );\r\n        }\r\n        else\r\n        {\r\n            clear();\r\n            printf(\"Mouse moving to column %d row %d\\n\",\r\n                    mickey.column,\r\n                    mickey.row\r\n                  );\r\n        }\r\n    }\r\n\r\n    <span class=\"comments\">\/* clean-up *\/<\/span>\r\n    mouse_disable();    <span class=\"comments\">\/* disable mouse reporting *\/<\/span>\r\n    tcsetattr(fileno(stdin), TCSANOW, &amp;original);\r\n    return 0;\r\n}<\/pre>\n<p>The <em>main()<\/em> function&#8217;s <em>while<\/em> loop monitors standard input. The input is captured and sent to the <em>read_mouse()<\/em> function. After extraction and storage in the <em>mouse_data<\/em> <code>mickey<\/code> structure, an <em>if<\/em> decision determines whether the &#8220;button&#8221; value isn&#8217;t 35, meaning that a mouse button has been clicked. When true, the button number is output at the click&#8217;s position. The <em>else<\/em> part of the loop reports the mouse&#8217;s current location.<\/p>\n<p>The loop repeats until the Enter key is pressed.<\/p>\n<p>Figure 1 shows a sample run.<\/p>\n<div id=\"attachment_7422\" style=\"width: 650px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-7422\" src=\"https:\/\/c-for-dummies.com\/blog\/wp-content\/uploads\/2026\/02\/0228.gif\" alt=\"Terminal window showing mouse movement and text output\" width=\"640\" height=\"427\" class=\"size-full wp-image-7422\" \/><p id=\"caption-attachment-7422\" class=\"wp-caption-text\">Figure 1. The program tracks mouse movements and clicks.<\/p><\/div>\n<p>This code goofs up if the terminal features a scrollback buffer and you drag the mouse on the screen or shift-click. Remember, these are ANSI codes and not a full-screen terminal API like Ncurses. (If the terminal window screws up, use the <em>reset<\/em> command to set things straight.)<\/p>\n<p>For <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=7440\">next week&#8217;s Lesson<\/a>, I wrap up the mouse manipulation series by working with text output at the click points.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Time to put the mouse to work! <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=7419\">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-7419","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\/7419","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=7419"}],"version-history":[{"count":5,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/7419\/revisions"}],"predecessor-version":[{"id":7463,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/7419\/revisions\/7463"}],"wp:attachment":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=7419"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=7419"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=7419"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}