How to move a red rectangle with the mouse in Linux character terminal

How to move a red rectangle with the mouse in Linux character terminal

Everything is a file! UNIX has already said it. Eric Raymond said this, don't you agree?

Since /dev/fb0 has been abstracted into a display, we can draw 32-bit true-color images on the screen by operating the memory mapped to /dev/fb0 on the character terminal. So how do we operate the mouse and keyboard?

/dev/input/mouse0 can be used to read mouse events. When you cat it in a character terminal and move the mouse, it seems to tell you that something happened, but you can't interpret it:


In order to find the correct way to interpret it, you can either Google or Baidu, or the most direct way is to check the read callback function of the file mouse0 in the Linux kernel source code:

static ssize_t mousedev_read(struct file *file, char __user *buffer,
     size_t count, loff_t *ppos)
{
 struct mousedev_client *client = file->private_data;
 struct mousedev *mousedev = client->mousedev;
 // The size of ps2 found in the mousedev_client structure is 6 bytes.
 signed char data[sizeof(client->ps2)];
 int retval = 0;

 spin_lock_irq(&client->packet_lock);

 if (!client->buffer && client->ready) {
  // This is the core, continue to follow mousedev_packet(client, client->ps2);
  client->buffer = client->bufsiz;
 }
 ...

Let's see how mousedev_packet assembles the packet:

static void mousedev_packet(struct mousedev_client *client,
    signed char *ps2_data)
{
 struct mousedev_motion *p = &client->packets[client->tail];

 ps2_data[0] = 0x08 |
  ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
 ps2_data[1] = mousedev_limit_delta(p->dx, 127);
 ps2_data[2] = mousedev_limit_delta(p->dy, 127);
 p->dx -= ps2_data[1];
 p->dy -= ps2_data[2];
...

I understand it very well. I don't care about anything else and I have no motivation to learn. I just want to know the X and Y coordinates of the mouse:

  • p->dx, p->dy As can be seen from the name and the code, this is the change of coordinates relative to the previous one!

All the information is there.

Now, we can write the code:

#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <stdlib.h>

// The side length of the square is 100 pixels #define LENGTH 100

//Abstract display memory unsigned int *mem = NULL;
// Save the last screen unsigned int *old_mem = NULL;
//Screen information static struct fb_var_screeninfo info;
int mouse_fd, fb_fd;

// Paint the square red int start = 0xffff0000;

int main(int argc, char **argv)
{
 signed char mouse_event[6];
 char rel_x, rel_y;
 int old_x = 0, old_y = 0;
 int abs_x = 0, abs_y = 0;

 mouse_fd = open("/dev/input/mouse0", O_RDONLY);
 fb_fd = open("/dev/fb0", O_RDWR);

 ioctl(fb_fd, FBIOGET_VSCREENINFO, &info);

 mem = (unsigned int *)mmap(NULL, info.xres*info.yres*info.bits_per_pixel/8, PROT_READ|PROT_WRITE, MAP_SHARED, fb_fd, 0);

 while(read(mouse_fd, &mouse_event[0], 6)) {
 int i, w, h;
 static int idx = 0;

 // According to the definition of kernel mousedev_packet, parse the relative displacement.
 rel_x = (char) mouse_event[1];
 rel_y = (char) mouse_event[2];
 // Calculate absolute displacement abs_x += rel_x;
 abs_y -= rel_y;
 if (abs_x <= 0 || abs_x >= info.xres - LENGTH || abs_y <= 0 || abs_y >= info.yres - LENGTH) {
 continue;
 }

 if (old_mem == NULL) {
 old_mem = (unsigned int *)mmap(NULL, info.xres*info.yres*info.bits_per_pixel/8, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
 if (old_mem == NULL) {
 exit(1);
 }
 } else {
 // Restore the pixels in the last square area for (w = old_x; w < old_x + LENGTH; w++) {
 for (h = old_y; h < old_y + LENGTH; h++) {
  idx = h*info.xres + w;
  mem[idx] = old_mem[idx];
 }
 }
 old_x = abs_x;
 old_y = abs_y;
 }

 // Save the current pixel for next restoration for (w = abs_x; w < abs_x + LENGTH; w++) {
 for (h = abs_y; h < abs_y + LENGTH; h++) {
 idx = h*info.xres + w;
 old_mem[idx] = mem[idx];
 }
 }

 // Paint the red rectangle according to the mouse position for (w = abs_x; w < abs_x + LENGTH; w++) {
 for (h = abs_y; h < abs_y + LENGTH; h++) {
 idx = h*info.xres + w;
 mem[idx] = start;
 }
 }
 }

 return 0;
}

Run it, and then move the mouse in the character terminal, the effect is as follows:

Well, the rectangle moves with the mouse and does not destroy any characters wherever it goes.

Now, let me review what I did this weekend and what it means.

  • I can draw 32-bit true-color images on a character terminal;
  • I can detect mouse and keyboard events and react.

This means that if I have the time and energy, I can implement a GUI system.

Of course, the GUI system and the network protocol stack are like mountains apart, and there will definitely be a lot of trouble, not just reading and writing two files:

  • /dev/fb0
  • /dev/input/mouse0

It can be done.

In fact, real GUI systems never use this approach. They seem to rebel against the UNIX philosophy of everything being a file, and prove that this is better! Oh, and the success of Windows GUI is a proof of this, as well as the latest version of MacOS…

When it comes to character terminals, the characters are also drawn. It's no big deal. However, if you want to use pixels to set characters, you need to understand the information of the character dot matrix... This is another topic in another field.

Summarize

The above is the full content of this article. I hope that the content of this article will have certain reference learning value for your study or work. Thank you for your support of 123WORDPRESS.COM.

You may also be interested in:
  • How to modify fonts in Linux system terminal
  • Detailed explanation of commonly used shortcut keys for Linux terminal command line
  • Two methods of terminal split screen under Linux (screen and tmux)
  • Linux Shell Script Series Tutorial (Part 2): Detailed Explanation of Terminal Printing Commands
  • Simple way to use Python in Linux command line terminal (recommended)
  • How to exit the Python command line in the Linux terminal
  • The perfect solution to terminal garbled characters in Linux operating system
  • Homemade Linux terminal lock screen tool
  • How to display asterisks when entering a password in the terminal in Linux

<<:  In-depth understanding of Worker threads in Node.js

>>:  Install and configure MySQL 5.7 under CentOS 7

Recommend

React Synthetic Events Explained

Table of contents Start by clicking the input box...

Discuss the development trend of Baidu Encyclopedia UI

<br />The official version of Baidu Encyclop...

Several things to note when making a web page

--Homepage backup 1.txt text 2. Scan the image 3. ...

Creation, constraints and deletion of foreign keys in MySQL

Preface After MySQL version 3.23.44, InnoDB engin...

How to split and merge multiple values ​​in a single field in MySQL

Multiple values ​​combined display Now we have th...

MySQL trigger detailed explanation and simple example

MySQL trigger simple example grammar CREATE TRIGG...

A brief discussion of several browser compatibility issues encountered

background Solving browser compatibility issues i...

Examples of using the or statement in MySQL

1. The use of or syntax in MySQL, and the points ...

How to solve the 10060 unknow error when Navicat remotely connects to MySQL

Preface: Today I want to remotely connect to MySQ...

Sharing ideas on processing tens of millions of data in a single MySQL table

Table of contents Project Background Improvement ...

Win10 64-bit MySQL8.0 download and installation tutorial diagram

How do I download MySQL from the official website...

Let’s take a look at JavaScript precompilation (summary)

JS running trilogy js running code is divided int...

Detailed example of SpringBoot+nginx to achieve resource upload function

Recently, I have been learning to use nginx to pl...

A quick guide to Docker

Docker provides a way to automatically deploy sof...