wok annotate busybox/stuff/busybox-1.30-fbvnc.u @ rev 21157

updated libconfig and libconfig-dev again (1.4.8 -> 1.7.2)
author Hans-G?nter Theisgen
date Sat Mar 30 16:34:10 2019 +0100 (2019-03-30)
parents
children
rev   line source
pascal@20652 1 text data bss dec hex filename
pascal@20652 2 3179 0 0 3179 c6b util-linux/fbvnc.o
pascal@20652 3 --- /dev/null
pascal@20652 4 +++ busybox/util-linux/fbvnc.c
pascal@20652 5 @@ -0,0 +1,552 @@
pascal@20652 6 +/* vi: set sw=4 ts=4: */
pascal@20652 7 +/*
pascal@20652 8 + * A small linux framebuffer VNC viewer
pascal@20652 9 + *
pascal@20652 10 + * pascal.bellard@ads-lu.com
pascal@20652 11 + *
pascal@20652 12 + * Based on Ali Gholami Rudi's fbvnc.c
pascal@20652 13 + * http://repo.or.cz/w/fbvnc.git
pascal@20652 14 + *
pascal@20652 15 + * Licensed under GPLv2 or later, see file LICENSE in this source tree.
pascal@20652 16 + */
pascal@20652 17 +
pascal@20652 18 +//applet:IF_FBVNC(APPLET(fbvnc, BB_DIR_BIN, BB_SUID_DROP))
pascal@20652 19 +
pascal@20652 20 +//kbuild:lib-$(CONFIG_FBVNC) += fbvnc.o
pascal@20652 21 +
pascal@20652 22 +//config:config FBVNC
pascal@20652 23 +//config: bool "fbvnc"
pascal@20652 24 +//config: default n
pascal@20652 25 +//config: depends on PLATFORM_LINUX
pascal@20652 26 +//config: help
pascal@20652 27 +//config: A linux framebuffer VNC viewer.
pascal@20652 28 +
pascal@20652 29 +//usage:#define fbvnc_trivial_usage
pascal@20652 30 +//usage: "[VNC_SERVER] [PORT]"
pascal@20652 31 +//usage:#define fbvnc_full_usage "\n\n"
pascal@20652 32 +//usage: "A linux framebuffer VNC viewer."
pascal@20652 33 +//usage: "\nTo exit, press any mouse button and press ESC."
pascal@20652 34 +
pascal@20652 35 +#include "libbb.h"
pascal@20652 36 +#include "vnc.h"
pascal@20652 37 +#include "common_bufsiz.h"
pascal@20652 38 +
pascal@20652 39 +/* Stuff stolen from the kernel's fb.h */
pascal@20652 40 +#define FB_ACTIVATE_ALL 64
pascal@20652 41 +enum {
pascal@20652 42 + FBIOGET_VSCREENINFO = 0x4600,
pascal@20652 43 + FBIOPUT_VSCREENINFO = 0x4601,
pascal@20652 44 + FBIOGET_FSCREENINFO = 0x4602,
pascal@20652 45 + FBIOGETCMAP = 0x4604,
pascal@20652 46 + FBIOPUTCMAP = 0x4605
pascal@20652 47 +};
pascal@20652 48 +
pascal@20652 49 +struct fb_bitfield {
pascal@20652 50 + uint32_t offset; /* beginning of bitfield */
pascal@20652 51 + uint32_t length; /* length of bitfield */
pascal@20652 52 + uint32_t msb_right; /* !=0: Most significant bit is right */
pascal@20652 53 +};
pascal@20652 54 +struct fb_var_screeninfo {
pascal@20652 55 + uint32_t xres; /* visible resolution */
pascal@20652 56 + uint32_t yres;
pascal@20652 57 + uint32_t xres_virtual; /* virtual resolution */
pascal@20652 58 + uint32_t yres_virtual;
pascal@20652 59 + uint32_t xoffset; /* offset from virtual to visible */
pascal@20652 60 + uint32_t yoffset; /* resolution */
pascal@20652 61 +
pascal@20652 62 + uint32_t bits_per_pixel;
pascal@20652 63 + uint32_t grayscale; /* !=0 Graylevels instead of colors */
pascal@20652 64 +
pascal@20652 65 + struct fb_bitfield red; /* bitfield in fb mem if true color, */
pascal@20652 66 + struct fb_bitfield green; /* else only length is significant */
pascal@20652 67 + struct fb_bitfield blue;
pascal@20652 68 + struct fb_bitfield transp; /* transparency */
pascal@20652 69 +
pascal@20652 70 + uint32_t nonstd; /* !=0 Non standard pixel format */
pascal@20652 71 +
pascal@20652 72 + uint32_t activate; /* see FB_ACTIVATE_x */
pascal@20652 73 +
pascal@20652 74 + uint32_t height; /* height of picture in mm */
pascal@20652 75 + uint32_t width; /* width of picture in mm */
pascal@20652 76 +
pascal@20652 77 + uint32_t accel_flags; /* acceleration flags (hints) */
pascal@20652 78 +
pascal@20652 79 + /* Timing: All values in pixclocks, except pixclock (of course) */
pascal@20652 80 + uint32_t pixclock; /* pixel clock in ps (pico seconds) */
pascal@20652 81 + uint32_t left_margin; /* time from sync to picture */
pascal@20652 82 + uint32_t right_margin; /* time from picture to sync */
pascal@20652 83 + uint32_t upper_margin; /* time from sync to picture */
pascal@20652 84 + uint32_t lower_margin;
pascal@20652 85 + uint32_t hsync_len; /* length of horizontal sync */
pascal@20652 86 + uint32_t vsync_len; /* length of vertical sync */
pascal@20652 87 + uint32_t sync; /* see FB_SYNC_x */
pascal@20652 88 + uint32_t vmode; /* see FB_VMODE_x */
pascal@20652 89 + uint32_t reserved[6]; /* Reserved for future compatibility */
pascal@20652 90 +};
pascal@20652 91 +
pascal@20652 92 +#define DEFAULTFBDEV FB_0
pascal@20652 93 +
pascal@20652 94 +struct fb_fix_screeninfo {
pascal@20652 95 + char id[16]; /* identification string eg "TT Builtin" */
pascal@20652 96 + unsigned long smem_start; /* Start of frame buffer mem */
pascal@20652 97 + /* (physical address) */
pascal@20652 98 + uint32_t smem_len; /* Length of frame buffer mem */
pascal@20652 99 + uint32_t type; /* see FB_TYPE_* */
pascal@20652 100 + uint32_t type_aux; /* Interleave for interleaved Planes */
pascal@20652 101 + uint32_t visual; /* see FB_VISUAL_* */
pascal@20652 102 + uint16_t xpanstep; /* zero if no hardware panning */
pascal@20652 103 + uint16_t ypanstep; /* zero if no hardware panning */
pascal@20652 104 + uint16_t ywrapstep; /* zero if no hardware ywrap */
pascal@20652 105 + uint32_t line_length; /* length of a line in bytes */
pascal@20652 106 + unsigned long mmio_start; /* Start of Memory Mapped I/O */
pascal@20652 107 + /* (physical address) */
pascal@20652 108 + uint32_t mmio_len; /* Length of Memory Mapped I/O */
pascal@20652 109 + uint32_t accel; /* Indicate to driver which */
pascal@20652 110 + /* specific chip/card we have */
pascal@20652 111 + uint16_t reserved[3]; /* Reserved for future compatibility */
pascal@20652 112 +};
pascal@20652 113 +
pascal@20652 114 +struct fb_cmap {
pascal@20652 115 + uint32_t start; /* First entry */
pascal@20652 116 + uint32_t len; /* Number of entries */
pascal@20652 117 + uint16_t *red; /* Red values */
pascal@20652 118 + uint16_t *green;
pascal@20652 119 + uint16_t *blue;
pascal@20652 120 + uint16_t *transp; /* transparency, can be NULL */
pascal@20652 121 +};
pascal@20652 122 +
pascal@20652 123 +#define FB_VISUAL_TRUECOLOR 2 /* True color */
pascal@20652 124 +
pascal@20652 125 +#define COLORLEVELS (1 << 8)
pascal@20652 126 +
pascal@20652 127 +struct scroll_data {
pascal@20652 128 + int size;
pascal@20652 129 + int srv_size;
pascal@20652 130 + int offset;
pascal@20652 131 + int pos;
pascal@20652 132 +};
pascal@20652 133 +
pascal@20652 134 +struct globals {
pascal@20652 135 + struct termios term_orig;
pascal@20652 136 + struct pollfd ufds[3];
pascal@20652 137 +#define kbd_fd ufds[0].fd
pascal@20652 138 +#define vnc_fd ufds[1].fd
pascal@20652 139 +#define rat_fd ufds[2].fd
pascal@20652 140 + struct scroll_data scroll[2];
pascal@20652 141 +#define cols scroll[0].size
pascal@20652 142 +#define srv_cols scroll[0].srv_size
pascal@20652 143 +#define oc scroll[0].offset
pascal@20652 144 +#define mc scroll[0].pos
pascal@20652 145 +#define rows scroll[1].size
pascal@20652 146 +#define srv_rows scroll[1].srv_size
pascal@20652 147 +#define or scroll[1].offset
pascal@20652 148 +#define mr scroll[1].pos
pascal@20652 149 + char rat_buttons;
pascal@20652 150 + int fb_fd;
pascal@20652 151 + void *fb_ptr;
pascal@20652 152 + int bpp;
pascal@20652 153 + int nr, ng, nb;
pascal@20652 154 + struct fb_var_screeninfo vinfo;
pascal@20652 155 + struct fb_fix_screeninfo finfo;
pascal@20652 156 + unsigned short red[COLORLEVELS], green[COLORLEVELS], blue[COLORLEVELS];
pascal@20652 157 +};
pascal@20652 158 +
pascal@20652 159 +#define G (*ptr_to_globals)
pascal@20652 160 +#define INIT_G() do { \
pascal@20652 161 + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
pascal@20652 162 +} while (0)
pascal@20652 163 +
pascal@20652 164 +static int fb_len(void)
pascal@20652 165 +{
pascal@20652 166 + return G.finfo.line_length * G.vinfo.yres_virtual;
pascal@20652 167 +}
pascal@20652 168 +
pascal@20652 169 +static void fb_ioctl_cmap(int fct, struct fb_cmap *cmap)
pascal@20652 170 +{
pascal@20652 171 + if (G.finfo.visual == FB_VISUAL_TRUECOLOR)
pascal@20652 172 + return;
pascal@20652 173 + cmap->start = 0;
pascal@20652 174 + cmap->len = MAX(G.nr, MAX(G.ng, G.nb));
pascal@20652 175 + cmap->transp = NULL;
pascal@20652 176 + xioctl(G.fb_fd, fct, cmap);
pascal@20652 177 +}
pascal@20652 178 +
pascal@20652 179 +static void fb_cmap_save(int save)
pascal@20652 180 +{
pascal@20652 181 + struct fb_cmap cmap;
pascal@20652 182 +
pascal@20652 183 + cmap.red = G.red;
pascal@20652 184 + cmap.green = G.green;
pascal@20652 185 + cmap.blue = G.blue;
pascal@20652 186 + fb_ioctl_cmap(save ? FBIOGETCMAP : FBIOPUTCMAP, &cmap);
pascal@20652 187 +}
pascal@20652 188 +
pascal@20652 189 +static void fb_build_cmap(unsigned short *color, int n)
pascal@20652 190 +{
pascal@20652 191 + int i, inc = 65535 / (n - 1);
pascal@20652 192 +
pascal@20652 193 + for (i = 0; n--; i += inc)
pascal@20652 194 + *color++ = i;
pascal@20652 195 +}
pascal@20652 196 +
pascal@20652 197 +static void fb_cmap(void)
pascal@20652 198 +{
pascal@20652 199 + unsigned short red[COLORLEVELS], green[COLORLEVELS], blue[COLORLEVELS];
pascal@20652 200 + struct fb_cmap cmap;
pascal@20652 201 +
pascal@20652 202 + fb_build_cmap(cmap.red = red, G.nr);
pascal@20652 203 + fb_build_cmap(cmap.green = green, G.ng);
pascal@20652 204 + fb_build_cmap(cmap.blue = blue, G.nb);
pascal@20652 205 + fb_ioctl_cmap(FBIOPUTCMAP, &cmap);
pascal@20652 206 +}
pascal@20652 207 +
pascal@20652 208 +static void fb_init(void)
pascal@20652 209 +{
pascal@20652 210 + G.fb_fd = xopen(DEFAULTFBDEV, O_RDWR);
pascal@20652 211 + xioctl(G.fb_fd, FBIOGET_VSCREENINFO, &G.vinfo);
pascal@20652 212 + xioctl(G.fb_fd, FBIOGET_FSCREENINFO, &G.finfo);
pascal@20652 213 + close_on_exec_on(G.fb_fd);
pascal@20652 214 + G.fb_ptr = mmap(NULL, fb_len(), PROT_READ | PROT_WRITE, MAP_SHARED, G.fb_fd, 0);
pascal@20652 215 + if (G.fb_ptr == MAP_FAILED)
pascal@20652 216 + bb_perror_msg_and_die("mmap");
pascal@20652 217 + G.bpp = (G.vinfo.bits_per_pixel + 7) >> 3;
pascal@20652 218 + G.nr = 1 << G.vinfo.red.length;
pascal@20652 219 + G.nb = 1 << G.vinfo.blue.length;
pascal@20652 220 + G.ng = 1 << G.vinfo.green.length;
pascal@20652 221 + fb_cmap_save(1);
pascal@20652 222 + fb_cmap();
pascal@20652 223 +}
pascal@20652 224 +
pascal@20652 225 +static void fb_free(void)
pascal@20652 226 +{
pascal@20652 227 + fb_cmap_save(0);
pascal@20652 228 + munmap(G.fb_ptr, fb_len());
pascal@20652 229 + close(G.fb_fd);
pascal@20652 230 +}
pascal@20652 231 +
pascal@20652 232 +#define fb_rows vinfo.yres
pascal@20652 233 +#define fb_cols vinfo.xres
pascal@20652 234 +
pascal@20652 235 +static void fb_set(int r, int c, void *mem, int len)
pascal@20652 236 +{
pascal@20652 237 + memcpy(G.fb_ptr + (r + G.vinfo.yoffset) * G.finfo.line_length +
pascal@20652 238 + (c + G.vinfo.xoffset) * G.bpp, mem, len * G.bpp);
pascal@20652 239 +}
pascal@20652 240 +
pascal@20652 241 +#define line_buffer bb_common_bufsiz1
pascal@20652 242 +#define MAXPIX (COMMON_BUFSIZE/sizeof(uint32_t))
pascal@20652 243 +
pascal@20652 244 +static void skip(int len)
pascal@20652 245 +{
pascal@20652 246 + int n;
pascal@20652 247 + while (len > 0 && (n = read(G.vnc_fd, line_buffer,
pascal@20652 248 + MIN(len, COMMON_BUFSIZE))) > 0)
pascal@20652 249 + len -= n;
pascal@20652 250 +}
pascal@20652 251 +
pascal@20652 252 +static void vnc_init(void)
pascal@20652 253 +{
pascal@20652 254 + struct vnc_client_init clientinit;
pascal@20652 255 + struct vnc_server_init serverinit;
pascal@20652 256 + struct vnc_client_pixelfmt pixfmt_cmd;
pascal@20652 257 + int connstat = VNC_CONN_FAILED;
pascal@20652 258 +
pascal@20652 259 + write(G.vnc_fd, "RFB 003.003\n", 12);
pascal@20652 260 + skip(12);
pascal@20652 261 +
pascal@20652 262 + xread(G.vnc_fd, &connstat, sizeof(connstat));
pascal@20652 263 +
pascal@20652 264 + if (ntohl(connstat) != VNC_CONN_NOAUTH)
pascal@20652 265 + bb_perror_msg_and_die("vnc auth");
pascal@20652 266 +
pascal@20652 267 + clientinit.shared = 1;
pascal@20652 268 + write(G.vnc_fd, &clientinit, sizeof(clientinit));
pascal@20652 269 + read(G.vnc_fd, &serverinit, sizeof(serverinit));
pascal@20652 270 +
pascal@20652 271 + fb_init();
pascal@20652 272 + G.srv_cols = ntohs(serverinit.w);
pascal@20652 273 + G.srv_rows = ntohs(serverinit.h);
pascal@20652 274 + G.cols = MIN(G.srv_cols, G.fb_cols);
pascal@20652 275 + G.rows = MIN(G.srv_rows, G.fb_rows);
pascal@20652 276 + G.mr = G.rows / 2;
pascal@20652 277 + G.mc = G.cols / 2;
pascal@20652 278 +
pascal@20652 279 + skip(ntohl(serverinit.len));
pascal@20652 280 + pixfmt_cmd.type = VNC_CLIENT_PIXFMT;
pascal@20652 281 + pixfmt_cmd.format.bigendian = 0;
pascal@20652 282 + pixfmt_cmd.format.truecolor = 1;
pascal@20652 283 + pixfmt_cmd.format.bpp =
pascal@20652 284 + pixfmt_cmd.format.depth = G.bpp << 3;
pascal@20652 285 + pixfmt_cmd.format.rmax = htons(G.nr - 1);
pascal@20652 286 + pixfmt_cmd.format.gmax = htons(G.ng - 1);
pascal@20652 287 + pixfmt_cmd.format.bmax = htons(G.nb - 1);
pascal@20652 288 + pixfmt_cmd.format.rshl = G.vinfo.red.offset;
pascal@20652 289 + pixfmt_cmd.format.gshl = G.vinfo.green.offset;
pascal@20652 290 + pixfmt_cmd.format.bshl = G.vinfo.blue.offset;
pascal@20652 291 + write(G.vnc_fd, &pixfmt_cmd, sizeof(pixfmt_cmd));
pascal@20652 292 +}
pascal@20652 293 +
pascal@20652 294 +static void vnc_refresh(int inc)
pascal@20652 295 +{
pascal@20652 296 + struct vnc_client_fbup fbup_req;
pascal@20652 297 + fbup_req.type = VNC_CLIENT_FBUP;
pascal@20652 298 + fbup_req.inc = inc;
pascal@20652 299 + fbup_req.x = htons(G.oc);
pascal@20652 300 + fbup_req.y = htons(G.or);
pascal@20652 301 + fbup_req.w = htons(G.oc + G.cols);
pascal@20652 302 + fbup_req.h = htons(G.or + G.rows);
pascal@20652 303 + write(G.vnc_fd, &fbup_req, sizeof(fbup_req));
pascal@20652 304 +}
pascal@20652 305 +
pascal@20652 306 +static void cleanup(void)
pascal@20652 307 +{
pascal@20652 308 +#define RESETSTR "\x1b[?25h\x1b[2J\x1b[H"
pascal@20652 309 + fb_free();
pascal@20652 310 + tcsetattr_stdin_TCSANOW(&G.term_orig);
pascal@20652 311 + write(STDOUT_FILENO, RESETSTR, sizeof(RESETSTR));
pascal@20652 312 + if (ENABLE_FEATURE_CLEAN_UP) {
pascal@20652 313 + close(G.vnc_fd);
pascal@20652 314 + close(G.rat_fd);
pascal@20652 315 + }
pascal@20652 316 +}
pascal@20652 317 +
pascal@20652 318 +static void killed(int code) NORETURN;
pascal@20652 319 +static void killed(int code)
pascal@20652 320 +{
pascal@20652 321 + cleanup();
pascal@20652 322 + if (code > EXIT_FAILURE)
pascal@20652 323 + kill_myself_with_sig(code);
pascal@20652 324 + exit(code);
pascal@20652 325 +}
pascal@20652 326 +
pascal@20652 327 +static void vnc_event(void)
pascal@20652 328 +{
pascal@20652 329 + struct vnc_rect uprect;
pascal@20652 330 + union {
pascal@20652 331 + struct vnc_server_fbup fbup;
pascal@20652 332 + struct vnc_server_cuttext cuttext;
pascal@20652 333 + struct vnc_server_colormap colormap;
pascal@20652 334 + } msg;
pascal@20652 335 + int n;
pascal@20652 336 +
pascal@20652 337 + switch (xread_char(G.vnc_fd)) {
pascal@20652 338 + case VNC_SERVER_FBUP:
pascal@20652 339 + xread(G.vnc_fd, &msg.fbup.pad, sizeof(msg.fbup) - 1);
pascal@20652 340 + n = ntohs(msg.fbup.n);
pascal@20652 341 + while (n--) {
pascal@20652 342 + int x, y, w, h, l, i;
pascal@20652 343 + xread(G.vnc_fd, &uprect, sizeof(uprect));
pascal@20652 344 + if (uprect.enc != 0)
pascal@20652 345 + killed(1);
pascal@20652 346 + i = 0;
pascal@20652 347 + x = ntohs(uprect.x) - G.oc;
pascal@20652 348 + y = ntohs(uprect.y) - G.or;
pascal@20652 349 + w = ntohs(uprect.w);
pascal@20652 350 + h = ntohs(uprect.h);
pascal@20652 351 + l = MIN(w, G.cols - x);
pascal@20652 352 + if (x < 0) {
pascal@20652 353 + l = MIN(w + x, G.cols);
pascal@20652 354 + i = -x;
pascal@20652 355 + x = 0;
pascal@20652 356 + }
pascal@20652 357 + for (; h--; y++) {
pascal@20652 358 + int a, b, c = i;
pascal@20652 359 + for (a = b = 0; w > b; b += a, c = 0) {
pascal@20652 360 + int len;
pascal@20652 361 + a = MIN(w - b, MAXPIX);
pascal@20652 362 + len = MIN(a, l - b) - c;
pascal@20652 363 + xread(G.vnc_fd, line_buffer, a * G.bpp);
pascal@20652 364 + if (y >= 0 && y < G.rows && len > 0)
pascal@20652 365 + fb_set(y, x + b,
pascal@20652 366 + line_buffer + (c * G.bpp),
pascal@20652 367 + len);
pascal@20652 368 + }
pascal@20652 369 + }
pascal@20652 370 + }
pascal@20652 371 + break;
pascal@20652 372 + case VNC_SERVER_BELL:
pascal@20652 373 + break;
pascal@20652 374 + case VNC_SERVER_CUTTEXT:
pascal@20652 375 + xread(G.vnc_fd, &msg.cuttext.pad1, sizeof(msg.cuttext) - 1);
pascal@20652 376 + skip(ntohl(msg.cuttext.len));
pascal@20652 377 + break;
pascal@20652 378 + case VNC_SERVER_COLORMAP:
pascal@20652 379 + xread(G.vnc_fd, &msg.colormap.pad, sizeof(msg.colormap) - 1);
pascal@20652 380 + skip(ntohs(msg.colormap.n) * 3 * 2);
pascal@20652 381 + break;
pascal@20652 382 + default:
pascal@20652 383 + killed(1);
pascal@20652 384 + }
pascal@20652 385 +}
pascal@20652 386 +
pascal@20652 387 +static int update_scroll(struct scroll_data *s)
pascal@20652 388 +{
pascal@20652 389 + int shift = s->size / 5;
pascal@20652 390 + int max = s->srv_size - s->size;
pascal@20652 391 + int status = 0;
pascal@20652 392 + if (s->pos < s->offset) {
pascal@20652 393 + if ((s->offset -= shift) < 0)
pascal@20652 394 + s->offset = 0;
pascal@20652 395 + }
pascal@20652 396 + else if (s->pos >= s->offset + s->size && s->offset < max) {
pascal@20652 397 + if ((s->offset += shift) > max)
pascal@20652 398 + s->offset = max;
pascal@20652 399 + }
pascal@20652 400 + else status++;
pascal@20652 401 + s->pos = MAX(s->offset, MIN(s->offset + s->size - 1, s->pos));
pascal@20652 402 + return status;
pascal@20652 403 +}
pascal@20652 404 +
pascal@20652 405 +static void rat_event(void)
pascal@20652 406 +{
pascal@20652 407 + static u8 btn2vnc[8] = {
pascal@20652 408 + 0, VNC_BUTTON1_MASK, VNC_BUTTON3_MASK,
pascal@20652 409 + VNC_BUTTON1_MASK + VNC_BUTTON3_MASK, VNC_BUTTON2_MASK,
pascal@20652 410 + VNC_BUTTON1_MASK + VNC_BUTTON2_MASK,
pascal@20652 411 + VNC_BUTTON2_MASK + VNC_BUTTON3_MASK,
pascal@20652 412 + VNC_BUTTON1_MASK + VNC_BUTTON2_MASK + VNC_BUTTON3_MASK
pascal@20652 413 + };
pascal@20652 414 + signed char ie[4];
pascal@20652 415 + struct vnc_client_ratevent me = {VNC_CLIENT_RATEVENT};
pascal@20652 416 + int refresh;
pascal@20652 417 +
pascal@20652 418 + xread(G.rat_fd, &ie, sizeof(ie));
pascal@20652 419 + G.mc += ie[1];
pascal@20652 420 + G.mr -= ie[2];
pascal@20652 421 + refresh = 2 - update_scroll(&G.scroll[0]) - update_scroll(&G.scroll[1]);
pascal@20652 422 + me.mask = btn2vnc[(int)(G.rat_buttons = ie[0] & 7)];
pascal@20652 423 + if (ie[3] > 0) /* wheel up */
pascal@20652 424 + me.mask |= VNC_BUTTON4_MASK;
pascal@20652 425 + if (ie[3] < 0) /* wheel down */
pascal@20652 426 + me.mask |= VNC_BUTTON5_MASK;
pascal@20652 427 + me.y = htons(G.mr);
pascal@20652 428 + me.x = htons(G.mc);
pascal@20652 429 + write(G.vnc_fd, &me, sizeof(me));
pascal@20652 430 + if (refresh)
pascal@20652 431 + vnc_refresh(0);
pascal@20652 432 +}
pascal@20652 433 +
pascal@20652 434 +static int press(int key, int down)
pascal@20652 435 +{
pascal@20652 436 + struct vnc_client_keyevent ke = {VNC_CLIENT_KEYEVENT};
pascal@20652 437 + ke.key = htonl(key);
pascal@20652 438 + ke.down = down;
pascal@20652 439 + return write(G.vnc_fd, &ke, sizeof(ke));
pascal@20652 440 +}
pascal@20652 441 +
pascal@20652 442 +static void kbd_event(void)
pascal@20652 443 +{
pascal@20652 444 + char key[1024];
pascal@20652 445 + int i, nr;
pascal@20652 446 +
pascal@20652 447 + if ((nr = read(0, key, sizeof(key))) <= 0 )
pascal@20652 448 + killed(1);
pascal@20652 449 + for (i = 0; i < nr; i++) {
pascal@20652 450 + int j, k;
pascal@20652 451 + int mod[4];
pascal@20652 452 + int nmod;
pascal@20652 453 +
pascal@20652 454 + k = nmod = 0;
pascal@20652 455 + switch (key[i]) {
pascal@20652 456 + case 0x08:
pascal@20652 457 + case 0x7f:
pascal@20652 458 + k = 0xff08;
pascal@20652 459 + break;
pascal@20652 460 + case 0x1b:
pascal@20652 461 + if (G.rat_buttons)
pascal@20652 462 + killed(0);
pascal@20652 463 + if (i + 2 < nr && key[i + 1] == '[') {
pascal@20652 464 + static const char arr2vnc[] = "HDACB";
pascal@20652 465 + char *p = strchr(arr2vnc, key[i + 2]);
pascal@20652 466 +
pascal@20652 467 + if (p) {
pascal@20652 468 + k = p - arr2vnc + 0xff50;
pascal@20652 469 + i += 2;
pascal@20652 470 + break;
pascal@20652 471 + }
pascal@20652 472 + }
pascal@20652 473 + if (i + 1 < nr) {
pascal@20652 474 + mod[nmod++] = 0xffe9;
pascal@20652 475 + i++;
pascal@20652 476 + }
pascal@20652 477 + case 0x09:
pascal@20652 478 + case 0x0d:
pascal@20652 479 + k = 0xff00;
pascal@20652 480 + goto getkey;
pascal@20652 481 + case 0x0c: /* Mouse button + ^L: redraw */
pascal@20652 482 + if (G.rat_buttons) {
pascal@20652 483 + vnc_refresh(0);
pascal@20652 484 + continue;
pascal@20652 485 + }
pascal@20652 486 + default:
pascal@20652 487 + getkey:
pascal@20652 488 + k += (unsigned char) key[i];
pascal@20652 489 + }
pascal@20652 490 + if ((k >= 'A' && k <= 'Z') || strchr(":\"<>?{}|+_()*&^%$#@!~", k))
pascal@20652 491 + mod[nmod++] = 0xffe1;
pascal@20652 492 + if (k >= 1 && k <= 26) {
pascal@20652 493 + k += 'a' - 1;
pascal@20652 494 + mod[nmod++] = 0xffe3;
pascal@20652 495 + }
pascal@20652 496 + mod[nmod] = k;
pascal@20652 497 + for (j = 0; j <= nmod; j++)
pascal@20652 498 + press(mod[j], 1);
pascal@20652 499 + press(k, 0);
pascal@20652 500 + for (j = 0; j < nmod; j++)
pascal@20652 501 + press(mod[j], 0);
pascal@20652 502 + }
pascal@20652 503 +}
pascal@20652 504 +
pascal@20652 505 +static void term_setup(void)
pascal@20652 506 +{
pascal@20652 507 + struct termios termios;
pascal@20652 508 +#define INITSTR "\x1b[?25l\x1b[2J\x1b[H** fbvnc **"
pascal@20652 509 +
pascal@20652 510 + write(STDOUT_FILENO, INITSTR, sizeof(INITSTR));
pascal@20652 511 + tcgetattr (STDIN_FILENO, &termios);
pascal@20652 512 + G.term_orig = termios;
pascal@20652 513 + cfmakeraw(&termios);
pascal@20652 514 + tcsetattr_stdin_TCSANOW(&termios);
pascal@20652 515 +}
pascal@20652 516 +
pascal@20652 517 +int fbvnc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
pascal@20652 518 +int fbvnc_main(int argc, char **argv)
pascal@20652 519 +{
pascal@20652 520 + char *host = (char *) "127.0.0.1";
pascal@20652 521 + int port, pending = 0;
pascal@20652 522 +
pascal@20652 523 + INIT_G();
pascal@20652 524 + if (argc >= 2)
pascal@20652 525 + host = argv[1];
pascal@20652 526 + port = bb_lookup_port((argc >= 3) ? argv[2] : "vnc", "tcp", 5900);
pascal@20652 527 + G.vnc_fd = create_and_connect_stream_or_die(host, port);
pascal@20652 528 + vnc_init();
pascal@20652 529 + G.rat_fd = open("/dev/input/mice", O_RDWR);
pascal@20652 530 + write(G.rat_fd, "\xf3\xc8\xf3\x64\xf3\x50", 6); /* for using mouse wheel */
pascal@20652 531 + read(G.rat_fd, line_buffer, 1);
pascal@20652 532 + term_setup();
pascal@20652 533 + atexit(cleanup);
pascal@20652 534 + bb_signals(BB_FATAL_SIGS, killed);
pascal@20652 535 +
pascal@20652 536 + G.ufds[0].events =
pascal@20652 537 + G.ufds[1].events =
pascal@20652 538 + G.ufds[2].events = POLLIN;
pascal@20652 539 + vnc_refresh(0);
pascal@20652 540 + while (1) {
pascal@20652 541 + int status = poll(G.ufds, 3, 500);
pascal@20652 542 + if (status == -1 && errno != EINTR)
pascal@20652 543 + killed(1);
pascal@20652 544 + if (!status)
pascal@20652 545 + continue;
pascal@20652 546 + if (G.ufds[0].revents & POLLIN)
pascal@20652 547 + kbd_event();
pascal@20652 548 + if (G.ufds[1].revents & POLLIN) {
pascal@20652 549 + vnc_event();
pascal@20652 550 + pending = 0;
pascal@20652 551 + }
pascal@20652 552 + if (G.ufds[2].revents & POLLIN)
pascal@20652 553 + rat_event();
pascal@20652 554 + if (!pending++)
pascal@20652 555 + vnc_refresh(1);
pascal@20652 556 + }
pascal@20652 557 +}
pascal@20652 558 --- /dev/null
pascal@20652 559 +++ busybox/util-linux/vnc.h
pascal@20652 560 @@ -0,0 +1,124 @@
pascal@20652 561 +#define VNC_CONN_FAILED 0
pascal@20652 562 +#define VNC_CONN_NOAUTH 1
pascal@20652 563 +#define VNC_CONN_AUTH 2
pascal@20652 564 +
pascal@20652 565 +#define VNC_AUTH_OK 0
pascal@20652 566 +#define VNC_AUTH_FAILED 1
pascal@20652 567 +#define VNC_AUTH_TOOMANY 2
pascal@20652 568 +
pascal@20652 569 +#define VNC_SERVER_FBUP 0
pascal@20652 570 +#define VNC_SERVER_COLORMAP 1
pascal@20652 571 +#define VNC_SERVER_BELL 2
pascal@20652 572 +#define VNC_SERVER_CUTTEXT 3
pascal@20652 573 +
pascal@20652 574 +#define VNC_CLIENT_PIXFMT 0
pascal@20652 575 +#define VNC_CLIENT_COLORMAP 1
pascal@20652 576 +#define VNC_CLIENT_SETENC 2
pascal@20652 577 +#define VNC_CLIENT_FBUP 3
pascal@20652 578 +#define VNC_CLIENT_KEYEVENT 4
pascal@20652 579 +#define VNC_CLIENT_RATEVENT 5
pascal@20652 580 +#define VNC_CLIENT_CUTTEXT 6
pascal@20652 581 +
pascal@20652 582 +#define VNC_ENC_RAW 0
pascal@20652 583 +#define VNC_ENC_COPYRECT 1
pascal@20652 584 +#define VNC_ENC_RRE 2
pascal@20652 585 +#define VNC_ENC_CORRE 4
pascal@20652 586 +#define VNC_ENC_HEXTILE 5
pascal@20652 587 +
pascal@20652 588 +#define VNC_BUTTON1_MASK 0x01
pascal@20652 589 +#define VNC_BUTTON2_MASK 0x02
pascal@20652 590 +#define VNC_BUTTON3_MASK 0x04
pascal@20652 591 +#define VNC_BUTTON4_MASK 0x10
pascal@20652 592 +#define VNC_BUTTON5_MASK 0x08
pascal@20652 593 +
pascal@20652 594 +typedef unsigned char u8;
pascal@20652 595 +typedef unsigned short u16;
pascal@20652 596 +typedef unsigned int u32;
pascal@20652 597 +
pascal@20652 598 +struct vnc_pixelfmt {
pascal@20652 599 + u8 bpp;
pascal@20652 600 + u8 depth;
pascal@20652 601 + u8 bigendian;
pascal@20652 602 + u8 truecolor;
pascal@20652 603 + u16 rmax;
pascal@20652 604 + u16 gmax;
pascal@20652 605 + u16 bmax;
pascal@20652 606 + u8 rshl;
pascal@20652 607 + u8 gshl;
pascal@20652 608 + u8 bshl;
pascal@20652 609 +
pascal@20652 610 + u8 pad1;
pascal@20652 611 + u16 pad2;
pascal@20652 612 +};
pascal@20652 613 +
pascal@20652 614 +struct vnc_client_init {
pascal@20652 615 + u8 shared;
pascal@20652 616 +};
pascal@20652 617 +
pascal@20652 618 +struct vnc_server_init {
pascal@20652 619 + u16 w;
pascal@20652 620 + u16 h;
pascal@20652 621 + struct vnc_pixelfmt fmt;
pascal@20652 622 + u32 len;
pascal@20652 623 + /* char name[len]; */
pascal@20652 624 +};
pascal@20652 625 +
pascal@20652 626 +struct vnc_rect {
pascal@20652 627 + u16 x, y;
pascal@20652 628 + u16 w, h;
pascal@20652 629 + u32 enc;
pascal@20652 630 + /* rect bytes */
pascal@20652 631 +};
pascal@20652 632 +
pascal@20652 633 +struct vnc_server_fbup {
pascal@20652 634 + u8 type;
pascal@20652 635 + u8 pad;
pascal@20652 636 + u16 n;
pascal@20652 637 + /* struct vnc_rect rects[n]; */
pascal@20652 638 +};
pascal@20652 639 +
pascal@20652 640 +struct vnc_server_cuttext {
pascal@20652 641 + u8 type;
pascal@20652 642 + u8 pad1;
pascal@20652 643 + u16 pad2;
pascal@20652 644 + u32 len;
pascal@20652 645 + /* char text[length] */
pascal@20652 646 +};
pascal@20652 647 +
pascal@20652 648 +struct vnc_server_colormap {
pascal@20652 649 + u8 type;
pascal@20652 650 + u8 pad;
pascal@20652 651 + u16 first;
pascal@20652 652 + u16 n;
pascal@20652 653 + /* u8 colors[n * 3 * 2]; */
pascal@20652 654 +};
pascal@20652 655 +
pascal@20652 656 +struct vnc_client_pixelfmt {
pascal@20652 657 + u8 type;
pascal@20652 658 + u8 pad1;
pascal@20652 659 + u16 pad2;
pascal@20652 660 + struct vnc_pixelfmt format;
pascal@20652 661 +};
pascal@20652 662 +
pascal@20652 663 +struct vnc_client_fbup {
pascal@20652 664 + u8 type;
pascal@20652 665 + u8 inc;
pascal@20652 666 + u16 x;
pascal@20652 667 + u16 y;
pascal@20652 668 + u16 w;
pascal@20652 669 + u16 h;
pascal@20652 670 +};
pascal@20652 671 +
pascal@20652 672 +struct vnc_client_keyevent {
pascal@20652 673 + u8 type;
pascal@20652 674 + u8 down;
pascal@20652 675 + u16 pad;
pascal@20652 676 + u32 key;
pascal@20652 677 +};
pascal@20652 678 +
pascal@20652 679 +struct vnc_client_ratevent {
pascal@20652 680 + u8 type;
pascal@20652 681 + u8 mask;
pascal@20652 682 + u16 x;
pascal@20652 683 + u16 y;
pascal@20652 684 +};