3 #include "kvm/framebuffer.h"
6 #include <linux/types.h>
7 #include <rfb/keysym.h>
11 #define VESA_QUEUE_SIZE 128
15 * This "6000" value is pretty much the result of experimentation
16 * It seems that around this value, things update pretty smoothly
18 #define VESA_UPDATE_TIME 6000
21 * We can map the letters and numbers without a fuss,
22 * but the other characters not so much.
24 static char letters
[26] = {
25 0x1c, 0x32, 0x21, 0x23, 0x24, /* a-e */
26 0x2b, 0x34, 0x33, 0x43, 0x3b, /* f-j */
27 0x42, 0x4b, 0x3a, 0x31, 0x44, /* k-o */
28 0x4d, 0x15, 0x2d, 0x1b, 0x2c, /* p-t */
29 0x3c, 0x2a, 0x1d, 0x22, 0x35, /* u-y */
33 static char num
[10] = {
34 0x45, 0x16, 0x1e, 0x26, 0x2e, 0x23, 0x36, 0x3d, 0x3e, 0x46,
38 * This is called when the VNC server receives a key event
39 * The reason this function is such a beast is that we have
40 * to convert from ASCII characters (which is what VNC gets)
41 * to PC keyboard scancodes, which is what Linux expects to
42 * get from its keyboard. ASCII and the scancode set don't
43 * really seem to mesh in any good way beyond some basics with
44 * the letters and numbers.
46 static void kbd_handle_key(rfbBool down
, rfbKeySym key
, rfbClientPtr cl
)
50 if (key
>= 0x41 && key
<= 0x5a)
51 key
+= 0x20; /* convert to lowercase */
53 if (key
>= 0x61 && key
<= 0x7a) /* a-z */
54 tosend
= letters
[key
- 0x61];
56 if (key
>= 0x30 && key
<= 0x39)
57 tosend
= num
[key
- 0x30];
60 case XK_Insert
: kbd_queue(0xe0); tosend
= 0x70; break;
61 case XK_Delete
: kbd_queue(0xe0); tosend
= 0x71; break;
62 case XK_Up
: kbd_queue(0xe0); tosend
= 0x75; break;
63 case XK_Down
: kbd_queue(0xe0); tosend
= 0x72; break;
64 case XK_Left
: kbd_queue(0xe0); tosend
= 0x6b; break;
65 case XK_Right
: kbd_queue(0xe0); tosend
= 0x74; break;
66 case XK_Page_Up
: kbd_queue(0xe0); tosend
= 0x7d; break;
67 case XK_Page_Down
: kbd_queue(0xe0); tosend
= 0x7a; break;
68 case XK_Home
: kbd_queue(0xe0); tosend
= 0x6c; break;
69 case XK_BackSpace
: tosend
= 0x66; break;
70 case XK_Tab
: tosend
= 0x0d; break;
71 case XK_Return
: tosend
= 0x5a; break;
72 case XK_Escape
: tosend
= 0x76; break;
73 case XK_End
: tosend
= 0x69; break;
74 case XK_Shift_L
: tosend
= 0x12; break;
75 case XK_Shift_R
: tosend
= 0x59; break;
76 case XK_Control_R
: kbd_queue(0xe0);
77 case XK_Control_L
: tosend
= 0x14; break;
78 case XK_Alt_R
: kbd_queue(0xe0);
79 case XK_Alt_L
: tosend
= 0x11; break;
80 case XK_quoteleft
: tosend
= 0x0e; break;
81 case XK_minus
: tosend
= 0x4e; break;
82 case XK_equal
: tosend
= 0x55; break;
83 case XK_bracketleft
: tosend
= 0x54; break;
84 case XK_bracketright
: tosend
= 0x5b; break;
85 case XK_backslash
: tosend
= 0x5d; break;
86 case XK_Caps_Lock
: tosend
= 0x58; break;
87 case XK_semicolon
: tosend
= 0x4c; break;
88 case XK_quoteright
: tosend
= 0x52; break;
89 case XK_comma
: tosend
= 0x41; break;
90 case XK_period
: tosend
= 0x49; break;
91 case XK_slash
: tosend
= 0x4a; break;
92 case XK_space
: tosend
= 0x29; break;
95 * This is where I handle the shifted characters.
96 * They don't really map nicely the way A-Z maps to a-z,
97 * so I'm doing it manually
99 case XK_exclam
: tosend
= 0x16; break;
100 case XK_quotedbl
: tosend
= 0x52; break;
101 case XK_numbersign
: tosend
= 0x26; break;
102 case XK_dollar
: tosend
= 0x25; break;
103 case XK_percent
: tosend
= 0x2e; break;
104 case XK_ampersand
: tosend
= 0x3d; break;
105 case XK_parenleft
: tosend
= 0x46; break;
106 case XK_parenright
: tosend
= 0x45; break;
107 case XK_asterisk
: tosend
= 0x3e; break;
108 case XK_plus
: tosend
= 0x55; break;
109 case XK_colon
: tosend
= 0x4c; break;
110 case XK_less
: tosend
= 0x41; break;
111 case XK_greater
: tosend
= 0x49; break;
112 case XK_question
: tosend
= 0x4a; break;
113 case XK_at
: tosend
= 0x1e; break;
114 case XK_asciicircum
: tosend
= 0x36; break;
115 case XK_underscore
: tosend
= 0x4e; break;
116 case XK_braceleft
: tosend
= 0x54; break;
117 case XK_braceright
: tosend
= 0x5b; break;
118 case XK_bar
: tosend
= 0x5d; break;
119 case XK_asciitilde
: tosend
= 0x0e; break;
124 * If this is a "key up" event (the user has released the key, we
125 * need to send 0xf0 first.
127 if (!down
&& tosend
!= 0x0)
134 /* The previous X and Y coordinates of the mouse */
135 static int xlast
, ylast
= -1;
138 * This function is called by the VNC server whenever a mouse event occurs.
140 static void kbd_handle_ptr(int buttonMask
, int x
, int y
, rfbClientPtr cl
)
145 /* The VNC mask and the PS/2 button encoding are the same */
148 if (xlast
>= 0 && ylast
>= 0) {
149 /* The PS/2 mouse sends deltas, not absolutes */
153 /* Set overflow bits if needed */
159 /* Set negative bits if needed */
172 rfbDefaultPtrAddEvent(buttonMask
, x
, y
, cl
);
175 static void *vnc__thread(void *p
)
177 struct framebuffer
*fb
= p
;
179 * Make a fake argc and argv because the getscreen function
182 char argv
[1][1] = {{0}};
185 rfbScreenInfoPtr server
;
187 server
= rfbGetScreen(&argc
, (char **) argv
, fb
->width
, fb
->height
, 8, 3, 4);
188 server
->frameBuffer
= fb
->mem
;
189 server
->alwaysShared
= TRUE
;
190 server
->kbdAddEvent
= kbd_handle_key
;
191 server
->ptrAddEvent
= kbd_handle_ptr
;
192 rfbInitServer(server
);
194 while (rfbIsActive(server
)) {
195 rfbMarkRectAsModified(server
, 0, 0, fb
->width
, fb
->height
);
196 rfbProcessEvents(server
, server
->deferUpdateTime
* VESA_UPDATE_TIME
);
201 static int vnc__start(struct framebuffer
*fb
)
205 if (pthread_create(&thread
, NULL
, vnc__thread
, fb
) != 0)
211 static struct fb_target_operations vnc_ops
= {
215 void vnc__init(struct framebuffer
*fb
)
217 fb__attach(fb
, &vnc_ops
);