3 Copyright (C) 2013 Proxmox Server Solutions GmbH
5 Copyright: spiceterm is under GNU GPL, the GNU General Public License.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; version 2 dated June, 1991.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 Author: Dietmar Maurer <dietmar@proxmox.com>
29 #include <sys/types.h>
33 #include "spiceterm.h"
38 #include <spice/enums.h>
39 #include <spice/macros.h>
40 #include <spice/qxl_dev.h>
42 #include "event_loop.h"
46 #define DPRINTF(x, format, ...) { \
48 printf("%s: " format "\n" , __FUNCTION__, ## __VA_ARGS__); \
53 my_kbd_get_leds(SpiceKbdInstance
*sin
)
58 #define MOD_MASK_SHIFT (1<<0)
59 #define MOD_MASK_ALTGR (1<<1)
60 #define MOD_MASK_NUMLOCK (1<<2)
63 typedef struct keymap_entry
{
64 gint hkey
; //(mask << 8 || keycode)
65 guint8 mask
; // MOD_MASK_*
71 static GHashTable
*keymap
= NULL
;
73 #define KBD_MOD_CONTROL_L_FLAG (1<<0)
74 #define KBD_MOD_CONTROL_R_FLAG (1<<1)
75 #define KBD_MOD_SHIFT_L_FLAG (1<<2)
76 #define KBD_MOD_SHIFT_R_FLAG (1<<3)
77 #define KBD_MOD_ALTGR_FLAG (1<<4)
78 #define KBD_MOD_NUMLOCK (1<<5)
79 #define KBD_MOD_SHIFTLOCK (1<<6)
81 static int kbd_flags
= 0;
83 static const name2keysym_t
*
84 lookup_keysym(const char *name
)
86 const name2keysym_t
*p
;
87 for(p
= name2keysym
; p
->name
!= NULL
; p
++) {
88 if (!strcmp(p
->name
, name
))
95 my_kbd_push_key(SpiceKbdInstance
*sin
, uint8_t frag
)
97 spiceTerm
*vt
= SPICE_CONTAINEROF(sin
, spiceTerm
, keyboard_sin
);
99 char *esc
= NULL
; // used to send special keys
101 static int e0_mode
= 0;
103 DPRINTF(1, "enter frag=%02x flags=%08x", frag
, kbd_flags
);
108 case 0x1d: // press Control_R
109 kbd_flags
|= KBD_MOD_CONTROL_R_FLAG
;
111 case 0x9d: // release Control_R
112 kbd_flags
&= ~KBD_MOD_CONTROL_R_FLAG
;
114 case 0x38: // press ALTGR
115 kbd_flags
|= KBD_MOD_ALTGR_FLAG
;
117 case 0xb8: // release ALTGR
118 kbd_flags
&= ~KBD_MOD_ALTGR_FLAG
;
120 case 0x47: // press Home
123 case 0x4f: // press END
126 case 0x48: // press UP
129 case 0x50: // press DOWN
132 case 0x4b: // press LEFT
135 case 0x4d: // press RIGHT
138 case 0x52: // press INSERT
141 case 0x53: // press Delete
144 case 0x49: // press PAGE_UP
145 if (kbd_flags
& (KBD_MOD_SHIFT_L_FLAG
|KBD_MOD_SHIFT_R_FLAG
)) {
146 spiceterm_virtual_scroll(vt
, -vt
->height
/2);
149 case 0x51: // press PAGE_DOWN
150 if (kbd_flags
& (KBD_MOD_SHIFT_L_FLAG
|KBD_MOD_SHIFT_R_FLAG
)) {
151 spiceterm_virtual_scroll(vt
, vt
->height
/2);
160 case 0x1d: // press Control_L
161 kbd_flags
|= KBD_MOD_CONTROL_L_FLAG
;
163 case 0x9d: // release Control_L
164 kbd_flags
&= ~KBD_MOD_CONTROL_L_FLAG
;
166 case 0x2a: // press Shift_L
167 kbd_flags
|= KBD_MOD_SHIFT_L_FLAG
;
169 case 0xaa: // release Shift_L
170 kbd_flags
&= ~KBD_MOD_SHIFT_L_FLAG
;
172 case 0x36: // press Shift_R
173 kbd_flags
|= KBD_MOD_SHIFT_R_FLAG
;
175 case 0xb6: // release Shift_R
176 kbd_flags
&= ~KBD_MOD_SHIFT_R_FLAG
;
178 case 0x52: // press KP_INSERT
179 if (!(kbd_flags
& KBD_MOD_NUMLOCK
))
182 case 0x53: // press KP_Delete
183 if (!(kbd_flags
& KBD_MOD_NUMLOCK
))
186 case 0x45: // press Numlock
187 if (kbd_flags
& KBD_MOD_NUMLOCK
) {
188 kbd_flags
&= ~KBD_MOD_NUMLOCK
;
190 kbd_flags
|= KBD_MOD_NUMLOCK
;
193 case 0x3a: // press Shiftlock
194 if (kbd_flags
& KBD_MOD_SHIFTLOCK
) {
195 kbd_flags
&= ~KBD_MOD_SHIFTLOCK
;
197 kbd_flags
|= KBD_MOD_SHIFTLOCK
;
200 case 0x47: // press KP_Home
201 if (!(kbd_flags
& KBD_MOD_NUMLOCK
))
204 case 0x4f: // press KP_END
205 if (!(kbd_flags
& KBD_MOD_NUMLOCK
))
208 case 0x48: // press KP_UP
209 if (!(kbd_flags
& KBD_MOD_NUMLOCK
))
212 case 0x50: // press KP_DOWN
213 if (!(kbd_flags
& KBD_MOD_NUMLOCK
))
216 case 0x4b: // press KP_LEFT
217 if (!(kbd_flags
& KBD_MOD_NUMLOCK
))
220 case 0x4d: // press KP_RIGHT
221 if (!(kbd_flags
& KBD_MOD_NUMLOCK
))
224 case 0x3b: // press F1
227 case 0x3c: // press F2
230 case 0x3d: // press F3
233 case 0x3e: // press F4
236 case 0x3f: // press F5
239 case 0x40: // press F6
242 case 0x41: // press F7
245 case 0x42: // press F8
248 case 0x43: // press F9
251 case 0x44: // press F10
254 case 0x57: // press F11
257 case 0x58: // press F12
264 DPRINTF(1, "escape=%s", esc
);
265 spiceterm_respond_esc(vt
, esc
);
267 if (vt
->y_displ
!= vt
->y_base
) {
268 vt
->y_displ
= vt
->y_base
;
269 spiceterm_refresh(vt
);
272 spiceterm_update_watch_mask(vt
, TRUE
);
273 } else if (frag
< 128) {
276 if (kbd_flags
& (KBD_MOD_SHIFT_L_FLAG
|KBD_MOD_SHIFT_R_FLAG
)) {
277 mask
|= MOD_MASK_SHIFT
;
279 if (kbd_flags
& KBD_MOD_SHIFTLOCK
) {
280 if (mask
& MOD_MASK_SHIFT
) {
281 mask
&= ~MOD_MASK_SHIFT
;
283 mask
|= MOD_MASK_SHIFT
;
286 if (kbd_flags
& KBD_MOD_ALTGR_FLAG
) {
287 mask
|= MOD_MASK_ALTGR
;
289 if (kbd_flags
& KBD_MOD_NUMLOCK
) {
290 mask
|= MOD_MASK_NUMLOCK
;
294 gint hkey
= mask
<< 8 | (frag
& 127);
295 keymap_entry
*e
= (keymap_entry
*)g_hash_table_lookup(keymap
, &hkey
);
296 if (!e
&& (kbd_flags
& KBD_MOD_NUMLOCK
)) {
297 mask
&= ~ MOD_MASK_NUMLOCK
;
298 hkey
= mask
<< 8 | (frag
& 127);
299 e
= (keymap_entry
*)g_hash_table_lookup(keymap
, &hkey
);
302 if (e
&& e
->unicode
) {
303 guint32 uc
= e
->unicode
;
306 if (uc
&& ((len
= g_unichar_to_utf8(uc
, buf
)) > 0)) {
307 if (kbd_flags
& (KBD_MOD_CONTROL_L_FLAG
|KBD_MOD_CONTROL_R_FLAG
)) {
308 if (buf
[0] >= 'a' && buf
[0] <= 'z') {
309 uint8_t ctrl
[1] = { buf
[0] - 'a' + 1 };
310 spiceterm_respond_data(vt
, 1, ctrl
);
311 spiceterm_update_watch_mask(vt
, TRUE
);
312 } else if (buf
[0] >= 'A' && buf
[0] <= 'Z') {
313 uint8_t ctrl
[1] = { buf
[0] - 'A' + 1 };
314 spiceterm_respond_data(vt
, 1, ctrl
);
315 spiceterm_update_watch_mask(vt
, TRUE
);
318 spiceterm_respond_data(vt
, len
, (uint8_t *)buf
);
319 spiceterm_update_watch_mask(vt
, TRUE
);
325 DPRINTF(1, "leave frag=%02x flags=%08x", frag
, kbd_flags
);
329 static SpiceKbdInterface my_keyboard_sif
= {
330 .base
.type
= SPICE_INTERFACE_KEYBOARD
,
331 .base
.description
= "spiceterm keyboard device",
332 .base
.major_version
= SPICE_INTERFACE_KEYBOARD_MAJOR
,
333 .base
.minor_version
= SPICE_INTERFACE_KEYBOARD_MINOR
,
334 .push_scan_freg
= my_kbd_push_key
,
335 .get_leds
= my_kbd_get_leds
,
339 /* vdagent interface - to get mouse/clipboard support */
341 #define VDAGENT_WBUF_SIZE (1024*50)
342 static unsigned char vdagent_write_buffer
[VDAGENT_WBUF_SIZE
];
343 static int vdagent_write_buffer_pos
= 0;
344 static int agent_owns_clipboard
[256] = { 0, };
347 vdagent_reply(spiceTerm
*vt
, uint32_t type
, uint32_t error
)
351 size
= sizeof(VDAgentReply
);
353 int msg_size
= sizeof(VDIChunkHeader
) + sizeof(VDAgentMessage
) + size
;
354 g_assert((vdagent_write_buffer_pos
+ msg_size
) < VDAGENT_WBUF_SIZE
);
356 unsigned char *buf
= vdagent_write_buffer
+ vdagent_write_buffer_pos
;
357 vdagent_write_buffer_pos
+= msg_size
;
359 memset(buf
, 0, msg_size
);
361 VDIChunkHeader
*hdr
= (VDIChunkHeader
*)buf
;
362 VDAgentMessage
*msg
= (VDAgentMessage
*)&hdr
[1];
363 VDAgentReply
*reply
= (VDAgentReply
*)&msg
[1];
365 reply
->error
= error
;
367 hdr
->port
= VDP_CLIENT_PORT
;
368 hdr
->size
= sizeof(VDAgentMessage
) + size
;
370 msg
->protocol
= VD_AGENT_PROTOCOL
;
371 msg
->type
= VD_AGENT_REPLY
;
375 spice_server_char_device_wakeup(&vt
->vdagent_sin
);
379 dump_message(unsigned char *buf
, int size
)
383 for (i
= 0; i
< size
; i
++) {
384 printf("%d %02X\n", i
, buf
[i
]);
391 vdagent_send_capabilities(spiceTerm
*vt
, uint32_t request
)
393 VDAgentAnnounceCapabilities
*caps
;
396 size
= sizeof(*caps
) + VD_AGENT_CAPS_BYTES
;
397 caps
= calloc(1, size
);
398 g_assert(caps
!= NULL
);
400 caps
->request
= request
;
401 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_MOUSE_STATE
);
402 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_MONITORS_CONFIG
);
403 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_REPLY
);
404 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND
);
405 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_CLIPBOARD_SELECTION
);
406 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_SPARSE_MONITORS_CONFIG
);
407 VD_AGENT_SET_CAPABILITY(caps
->caps
, VD_AGENT_CAP_GUEST_LINEEND_LF
);
409 int msg_size
= sizeof(VDIChunkHeader
) + sizeof(VDAgentMessage
) + size
;
410 g_assert((vdagent_write_buffer_pos
+ msg_size
) < VDAGENT_WBUF_SIZE
);
412 unsigned char *buf
= vdagent_write_buffer
+ vdagent_write_buffer_pos
;
413 vdagent_write_buffer_pos
+= msg_size
;
415 VDIChunkHeader
*hdr
= (VDIChunkHeader
*)buf
;
416 VDAgentMessage
*msg
= (VDAgentMessage
*)&hdr
[1];
418 hdr
->port
= VDP_CLIENT_PORT
;
419 hdr
->size
= sizeof(VDAgentMessage
) + size
;
420 msg
->protocol
= VD_AGENT_PROTOCOL
;
421 msg
->type
= VD_AGENT_ANNOUNCE_CAPABILITIES
;
425 memcpy(buf
+ sizeof(VDIChunkHeader
) + sizeof(VDAgentMessage
), (uint8_t *)caps
, size
);
427 if (0) dump_message(buf
, msg_size
);
429 spice_server_char_device_wakeup(&vt
->vdagent_sin
);
435 vdagent_owns_clipboard(spiceTerm
*vt
)
437 return !!agent_owns_clipboard
[VD_AGENT_CLIPBOARD_SELECTION_PRIMARY
];
441 vdagent_grab_clipboard(spiceTerm
*vt
)
445 uint8_t selection
= VD_AGENT_CLIPBOARD_SELECTION_PRIMARY
;
447 agent_owns_clipboard
[selection
] = 1;
451 int msg_size
= sizeof(VDIChunkHeader
) + sizeof(VDAgentMessage
) + size
;
452 g_assert((vdagent_write_buffer_pos
+ msg_size
) < VDAGENT_WBUF_SIZE
);
454 unsigned char *buf
= vdagent_write_buffer
+ vdagent_write_buffer_pos
;
455 vdagent_write_buffer_pos
+= msg_size
;
457 memset(buf
, 0, msg_size
);
459 VDIChunkHeader
*hdr
= (VDIChunkHeader
*)buf
;
460 VDAgentMessage
*msg
= (VDAgentMessage
*)&hdr
[1];
461 uint8_t *grab
= (uint8_t *)&msg
[1];
462 *((uint8_t *)grab
) = selection
;
463 *((uint32_t *)(grab
+ 4)) = VD_AGENT_CLIPBOARD_UTF8_TEXT
;
465 hdr
->port
= VDP_CLIENT_PORT
;
466 hdr
->size
= sizeof(VDAgentMessage
) + size
;
468 msg
->protocol
= VD_AGENT_PROTOCOL
;
469 msg
->type
= VD_AGENT_CLIPBOARD_GRAB
;
473 if (0) dump_message(buf
, msg_size
);
475 spice_server_char_device_wakeup(&vt
->vdagent_sin
);
479 vdagent_request_clipboard(spiceTerm
*vt
)
483 uint8_t selection
= VD_AGENT_CLIPBOARD_SELECTION_PRIMARY
;
485 size
= 4 + sizeof(VDAgentClipboardRequest
);
487 int msg_size
= sizeof(VDIChunkHeader
) + sizeof(VDAgentMessage
) + size
;
488 g_assert((vdagent_write_buffer_pos
+ msg_size
) < VDAGENT_WBUF_SIZE
);
490 unsigned char *buf
= vdagent_write_buffer
+ vdagent_write_buffer_pos
;
491 vdagent_write_buffer_pos
+= msg_size
;
493 memset(buf
, 0, msg_size
);
495 VDIChunkHeader
*hdr
= (VDIChunkHeader
*)buf
;
496 VDAgentMessage
*msg
= (VDAgentMessage
*)&hdr
[1];
497 uint8_t *data
= (uint8_t *)&msg
[1];
498 *((uint32_t *)data
) = 0;
500 ((uint32_t *)data
)[1] = VD_AGENT_CLIPBOARD_UTF8_TEXT
;
502 hdr
->port
= VDP_CLIENT_PORT
;
503 hdr
->size
= sizeof(VDAgentMessage
) + size
;
505 msg
->protocol
= VD_AGENT_PROTOCOL
;
506 msg
->type
= VD_AGENT_CLIPBOARD_REQUEST
;
510 if (0) dump_message(buf
, msg_size
);
512 spice_server_char_device_wakeup(&vt
->vdagent_sin
);
516 vdagent_send_clipboard(spiceTerm
*vt
, uint8_t selection
)
520 if (selection
!= VD_AGENT_CLIPBOARD_SELECTION_PRIMARY
) {
521 fprintf(stderr
, "clipboard select %d is not supported\n", selection
);
528 sel_data
= g_utf16_to_utf8(vt
->selection
, vt
->selection_len
, NULL
, &sel_len
, NULL
);
530 sel_len
= vt
->selection_len
;
531 sel_data
= g_malloc(sel_len
);
533 for (i
= 0; i
< sel_len
; i
++) { sel_data
[i
] = (char)vt
->selection
[i
]; }
534 sel_data
[sel_len
] = 0;
539 int msg_size
= sizeof(VDIChunkHeader
) + sizeof(VDAgentMessage
) + size
;
540 g_assert((vdagent_write_buffer_pos
+ msg_size
) < VDAGENT_WBUF_SIZE
);
542 unsigned char *buf
= vdagent_write_buffer
+ vdagent_write_buffer_pos
;
543 vdagent_write_buffer_pos
+= msg_size
;
545 memset(buf
, 0, msg_size
);
547 VDIChunkHeader
*hdr
= (VDIChunkHeader
*)buf
;
548 VDAgentMessage
*msg
= (VDAgentMessage
*)&hdr
[1];
549 uint8_t *data
= (uint8_t *)&msg
[1];
550 *((uint8_t *)data
) = selection
;
552 *((uint32_t *)data
) = VD_AGENT_CLIPBOARD_UTF8_TEXT
;
555 memcpy(data
, sel_data
, sel_len
);
558 hdr
->port
= VDP_CLIENT_PORT
;
559 hdr
->size
= sizeof(VDAgentMessage
) + size
;
561 msg
->protocol
= VD_AGENT_PROTOCOL
;
562 msg
->type
= VD_AGENT_CLIPBOARD
;
566 spice_server_char_device_wakeup(&vt
->vdagent_sin
);
570 vmc_write(SpiceCharDeviceInstance
*sin
, const uint8_t *buf
, int len
)
572 spiceTerm
*vt
= SPICE_CONTAINEROF(sin
, spiceTerm
, vdagent_sin
);
574 VDIChunkHeader
*hdr
= (VDIChunkHeader
*)buf
;
575 VDAgentMessage
*msg
= (VDAgentMessage
*)&hdr
[1];
577 //g_assert(hdr->port == VDP_SERVER_PORT);
578 g_assert(msg
->protocol
== VD_AGENT_PROTOCOL
);
580 DPRINTF(1, "%d %d %d %d", len
, hdr
->port
, msg
->protocol
, msg
->type
);
583 case VD_AGENT_MOUSE_STATE
: {
584 VDAgentMouseState
*info
= (VDAgentMouseState
*)&msg
[1];
585 spiceterm_motion_event(vt
, info
->x
, info
->y
, info
->buttons
);
588 case VD_AGENT_ANNOUNCE_CAPABILITIES
: {
589 VDAgentAnnounceCapabilities
*caps
= (VDAgentAnnounceCapabilities
*)&msg
[1];
590 DPRINTF(1, "VD_AGENT_ANNOUNCE_CAPABILITIES %d", caps
->request
);
593 int caps_size
= VD_AGENT_CAPS_SIZE_FROM_MSG_SIZE(hdr
->size
);
594 for (i
= 0; i
< VD_AGENT_END_CAP
; i
++) {
595 DPRINTF(1, "CAPABILITIES %d %d", i
, VD_AGENT_HAS_CAPABILITY(caps
->caps
, caps_size
, i
));
598 vdagent_send_capabilities(vt
, 0);
601 case VD_AGENT_CLIPBOARD_GRAB
: {
602 VDAgentClipboardGrab
*grab
= (VDAgentClipboardGrab
*)&msg
[1];
603 uint8_t selection
= *((uint8_t *)grab
);
604 DPRINTF(1, "VD_AGENT_CLIPBOARD_GRAB %d", selection
);
605 agent_owns_clipboard
[selection
] = 0;
606 spiceterm_clear_selection(vt
);
609 case VD_AGENT_CLIPBOARD_REQUEST
: {
610 uint8_t *req
= (uint8_t *)&msg
[1];
611 uint8_t selection
= *((uint8_t *)req
);
612 uint32_t type
= *((uint32_t *)(req
+ 4));
614 DPRINTF(1, "VD_AGENT_CLIPBOARD_REQUEST %d %d", selection
, type
);
616 vdagent_send_clipboard(vt
, selection
);
620 case VD_AGENT_CLIPBOARD
: {
621 uint8_t *data
= (uint8_t *)&msg
[1];
622 uint8_t selection
= data
[0];
623 uint32_t type
= *(uint32_t *)(data
+ 4);
624 int size
= msg
->size
- 8;
625 DPRINTF(1, "VD_AGENT_CLIPBOARD %d %d %d", selection
, type
, size
);
627 if (type
== VD_AGENT_CLIPBOARD_UTF8_TEXT
) {
628 spiceterm_respond_data(vt
, size
, data
+ 8);
629 spiceterm_update_watch_mask(vt
, TRUE
);
633 case VD_AGENT_CLIPBOARD_RELEASE
: {
634 uint8_t *data
= (uint8_t *)&msg
[1];
635 uint8_t selection
= data
[0];
637 DPRINTF(1, "VD_AGENT_CLIPBOARD_RELEASE %d", selection
);
641 case VD_AGENT_MONITORS_CONFIG
: {
642 VDAgentMonitorsConfig
*list
= (VDAgentMonitorsConfig
*)&msg
[1];
643 g_assert(list
->num_of_monitors
> 0);
644 DPRINTF(1, "VD_AGENT_MONITORS_CONFIG %d %d %d", list
->num_of_monitors
,
645 list
->monitors
[0].width
, list
->monitors
[0].height
);
647 spiceterm_resize(vt
, list
->monitors
[0].width
, list
->monitors
[0].height
);
649 vdagent_reply(vt
, VD_AGENT_MONITORS_CONFIG
, VD_AGENT_SUCCESS
);
653 DPRINTF(1, "got uknown vdagent message type %d\n", msg
->type
);
660 vmc_read(SpiceCharDeviceInstance
*sin
, uint8_t *buf
, int len
)
662 DPRINTF(1, "%d %d", len
, vdagent_write_buffer_pos
);
665 if (!vdagent_write_buffer_pos
) {
669 int size
= (len
>= vdagent_write_buffer_pos
) ? vdagent_write_buffer_pos
: len
;
670 memcpy(buf
, vdagent_write_buffer
, size
);
671 if (size
< vdagent_write_buffer_pos
) {
672 memmove(vdagent_write_buffer
, vdagent_write_buffer
+ size
,
673 vdagent_write_buffer_pos
- size
);
675 vdagent_write_buffer_pos
-= size
;
677 DPRINTF(1, "RET %d %d", size
, vdagent_write_buffer_pos
);
682 vmc_state(SpiceCharDeviceInstance
*sin
, int connected
)
687 static SpiceCharDeviceInterface my_vdagent_sif
= {
688 .base
.type
= SPICE_INTERFACE_CHAR_DEVICE
,
689 .base
.description
= "spice virtual channel char device",
690 .base
.major_version
= SPICE_INTERFACE_CHAR_DEVICE_MAJOR
,
691 .base
.minor_version
= SPICE_INTERFACE_CHAR_DEVICE_MINOR
,
698 add_keymap_entry(guint8 mask
, guint8 keycode
, guint keysym
, guint unicode
)
700 keymap_entry
*e
= g_new0(keymap_entry
, 1);
703 e
->unicode
= unicode
;
704 e
->keycode
= keycode
;
705 e
->hkey
= mask
<< 8 | (keycode
& 255);
707 // only insert first mapping (other are most likely dead keys)
708 if (!g_hash_table_lookup(keymap
, &e
->hkey
)) {
709 g_hash_table_insert(keymap
, &e
->hkey
, e
);
714 parse_keymap(const char *language
)
719 printf("parse keymap %s\n", language
);
721 char *filename
= g_strdup_printf("/usr/share/kvm/keymaps/%s", language
);
722 FILE *f
= fopen(filename
, "r");
725 fprintf(stderr
, "Could not read keymap file: '%s'\n", language
);
730 if (fgets(line
, 1024, f
) == NULL
)
733 if (len
> 0 && line
[len
- 1] == '\n')
734 line
[len
- 1] = '\0';
735 if (line
[0] == '#' || line
[0] == '\0')
737 if (!strncmp(line
, "map ", 4))
739 if (!strncmp(line
, "include ", 8)) {
740 parse_keymap(line
+ 8);
742 printf("LINE: %s\n", line
);
743 char *tok
= strtok(line
, " ");
745 fprintf(stderr
, "Warning: unknown keysym\n");
746 g_assert_not_reached();
748 const name2keysym_t
*map
= lookup_keysym(tok
);
750 fprintf(stderr
, "Warning: unknown keysym '%s'\n", tok
);
751 g_assert_not_reached();
756 gboolean addupper
= FALSE
;
758 while ((tok
= strtok(NULL
, " "))) {
759 if (!strcmp(tok
, "shift")) {
760 mask
|= MOD_MASK_SHIFT
;
761 } else if (!strcmp(tok
, "numlock")) {
762 mask
|= MOD_MASK_NUMLOCK
;
763 } else if (!strcmp(tok
, "altgr")) {
764 mask
|= MOD_MASK_ALTGR
;
765 } else if (!strcmp(tok
, "addupper")) {
767 } else if (!strcmp(tok
, "inhibit")) {
769 } else if (!strcmp(tok
, "localstate")) {
774 keycode
= strtol(tok
, &endptr
, 0);
775 if (errno
!= 0 || *endptr
!= '\0' || keycode
>= 255) {
776 printf("got unknown modifier '%s' %d\n", tok
, keycode
);
777 g_assert_not_reached();
783 printf("got keycode %u ==> %02x:%d\n", map
->keysym
, mask
, keycode
);
785 add_keymap_entry(mask
, keycode
, map
->keysym
, map
->unicode
);
787 gchar uc
= g_ascii_toupper(line
[0]);
789 char ucname
[] = { uc
, '\0' };
790 if ((map
= lookup_keysym(ucname
))) {
791 add_keymap_entry(mask
|MOD_MASK_SHIFT
, keycode
,
792 map
->keysym
, map
->unicode
);
801 spiceterm_create(uint32_t width
, uint32_t height
, SpiceTermOptions
*opts
)
803 SpiceCoreInterface
*core
= basic_event_loop_init();
804 SpiceScreen
*spice_screen
= spice_screen_new(core
, width
, height
, opts
);
806 keymap
= g_hash_table_new(g_int_hash
, g_int_equal
);
807 parse_keymap(opts
->keymap
? opts
->keymap
: "en-us");
809 spice_screen
->image_cache
= g_hash_table_new(g_int_hash
, g_int_equal
);
811 spiceTerm
*vt
= (spiceTerm
*)calloc (sizeof(spiceTerm
), 1);
813 vt
->keyboard_sin
.base
.sif
= &my_keyboard_sif
.base
;
814 spice_server_add_interface(spice_screen
->server
, &vt
->keyboard_sin
.base
);
816 vt
->vdagent_sin
.base
.sif
= &my_vdagent_sif
.base
;
817 vt
->vdagent_sin
.subtype
= "vdagent";
818 spice_server_add_interface(spice_screen
->server
, &vt
->vdagent_sin
.base
);
819 vt
->screen
= spice_screen
;
821 init_spiceterm(vt
, width
, height
);