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

Detailed explanation of Docker working mode and principle

As shown in the following figure: When we use vir...

JavaScript Basics Series: Functions and Methods

Table of contents 1. The difference between funct...

JS realizes the effect of picture waterfall flow

This article shares the specific code of JS to re...

Implementation of vertical centering with unknown height in CSS

This article mainly introduces the implementation...

How to encapsulate query components based on element-ui step by step

Table of contents Function Basic query functions ...

Detailed explanation of reduce fold unfold usage in JS

Table of contents fold (reduce) Using for...of Us...

MySQL 5.7 installation and configuration tutorial under CentOS7 64 bit

Installation environment: CentOS7 64-bit MINI ver...

Implementation of MySQL index-based stress testing

1. Simulate database data 1-1 Create database and...

Six important selectors in CSS (remember them in three seconds)

From: https://blog.csdn.net/qq_44761243/article/d...

Detailed explanation of docker version es, milvus, minio startup commands

1. es startup command: docker run -itd -e TAKE_FI...

Detailed explanation of jQuery method attributes

Table of contents 1. Introduction to jQuery 2. jQ...

Detailed explanation of CSS3+JS perfect implementation of magnifying glass mode

About a year ago, I wrote an article: Analysis of...

CentOS7 firewall and port related commands introduction

Table of contents 1. Check the current status of ...

Floating menu, can achieve up and down scrolling effect

The code can be further streamlined, but due to t...

The difference and introduction of ARGB, RGB and RGBA

ARGB is a color mode, which is the RGB color mode...