1、控制键盘灯入口
1.1、SPICE服务器通过信号" inputs-modifiers"改变键盘灯
static void guest_modifiers_changed(SpiceInputsChannel *inputs, gpointer data)//信号改变键盘灯
{SpiceGtkSession *self = data;spice_gtk_session_sync_keyboard_modifiers_for_channel(self, inputs, FALSE);
}static void spice_inputs_channel_class_init(SpiceInputsChannelClass *klass)
{.../*** SpiceInputsChannel::inputs-modifiers:* @display: the #SpiceInputsChannel that emitted the signal** The #SpiceInputsChannel::inputs-modifiers signal is emitted when* the guest keyboard locks are changed. You can read the current* state from #SpiceInputsChannel:key-modifiers property.**//* TODO: use notify instead? */signals[SPICE_INPUTS_MODIFIERS] =g_signal_new("inputs-modifiers",G_OBJECT_CLASS_TYPE(gobject_class),G_SIGNAL_RUN_FIRST,G_STRUCT_OFFSET(SpiceInputsChannelClass, inputs_modifiers),NULL, NULL,g_cclosure_marshal_VOID__VOID,G_TYPE_NONE,0);channel_set_handlers(SPICE_CHANNEL_CLASS(klass));
}//在spice-gtk-session.c层进行连接,qt也需要连接
static void channel_new(SpiceSession *session, SpiceChannel *channel,gpointer user_data)
{...if (SPICE_IS_INPUTS_CHANNEL(channel)) {spice_g_signal_connect_object(channel, "inputs-modifiers",G_CALLBACK(guest_modifiers_changed), self, 0); //信号改变键盘灯spice_gtk_session_sync_keyboard_modifiers_for_channel(self, SPICE_INPUTS_CHANNEL(channel), TRUE); //立即改变键盘灯}
}
1.1.1、输入通道收到SPICE服务器初始化的时候,发信号改变键盘灯
/* coroutine context */
static void inputs_handle_init(SpiceChannel *channel, SpiceMsgIn *in)
{SpiceInputsChannelPrivate *c = SPICE_INPUTS_CHANNEL(channel)->priv;SpiceMsgInputsInit *init = spice_msg_in_parsed(in);c->modifiers = init->keyboard_modifiers;g_coroutine_signal_emit(channel, signals[SPICE_INPUTS_MODIFIERS], 0);
}
1.1.2、输入通道收到SPICE服务器改变键盘灯,发信号改变键盘灯
static void inputs_handle_modifiers(SpiceChannel *channel, SpiceMsgIn *in)
{SpiceInputsChannelPrivate *c = SPICE_INPUTS_CHANNEL(channel)->priv;SpiceMsgInputsKeyModifiers *modifiers = spice_msg_in_parsed(in);c->modifiers = modifiers->modifiers;g_coroutine_signal_emit(channel, signals[SPICE_INPUTS_MODIFIERS], 0);
}
1.2、gtk层外部调用接口
void spice_gtk_session_sync_keyboard_modifiers(SpiceGtkSession *self)
{GList *l = NULL, *channels = spice_session_get_channels(self->priv->session);for (l = channels; l != NULL; l = l->next) {if (SPICE_IS_INPUTS_CHANNEL(l->data)) {SpiceInputsChannel *inputs = SPICE_INPUTS_CHANNEL(l->data);spice_gtk_session_sync_keyboard_modifiers_for_channel(self, inputs, TRUE);//同步键盘灯}}g_list_free(channels);
}
1.3、new_channel时调用同步键盘灯
static void channel_new(SpiceSession *session, SpiceChannel *channel,gpointer user_data)
{g_return_if_fail(SPICE_IS_GTK_SESSION(user_data));SpiceGtkSession *self = user_data;SpiceGtkSessionPrivate *s = self->priv;if (SPICE_IS_MAIN_CHANNEL(channel)) {SPICE_DEBUG("Changing main channel from %p to %p", s->main, channel);s->main = SPICE_MAIN_CHANNEL(channel);g_signal_connect(channel, "main-clipboard-selection-grab",G_CALLBACK(clipboard_grab), self);g_signal_connect(channel, "main-clipboard-selection-request",G_CALLBACK(clipboard_request), self);g_signal_connect(channel, "main-clipboard-selection-release",G_CALLBACK(clipboard_release_delay), self);}if (SPICE_IS_INPUTS_CHANNEL(channel)) {spice_g_signal_connect_object(channel, "inputs-modifiers",G_CALLBACK(guest_modifiers_changed), self, 0); //信号改变键盘灯spice_gtk_session_sync_keyboard_modifiers_for_channel(self, SPICE_INPUTS_CHANNEL(channel), TRUE); //立即改变键盘灯}
}
2、键盘灯实际处理函数
//通过gtk设置键盘灯,qt需要重写
static void spice_gtk_session_sync_keyboard_modifiers_for_channel(SpiceGtkSession *self,SpiceInputsChannel* inputs,gboolean force)
{guint32 guest_modifiers = 0, client_modifiers = 0;g_return_if_fail(SPICE_IS_INPUTS_CHANNEL(inputs));if (SPICE_IS_GTK_SESSION(self) && !self->priv->sync_modifiers) {SPICE_DEBUG("Syncing modifiers is disabled");return;}g_object_get(inputs, "key-modifiers", &guest_modifiers, NULL);client_modifiers = get_keyboard_lock_modifiers();//获取本地键盘灯if (force || client_modifiers != guest_modifiers) {CHANNEL_DEBUG(inputs, "client_modifiers:0x%x, guest_modifiers:0x%x", client_modifiers, guest_modifiers);spice_inputs_channel_set_key_locks(inputs, client_modifiers);}
}//通过gtk获取本地键盘灯,qt需要重写
static guint32 get_keyboard_lock_modifiers(void)
{guint32 modifiers = 0;GdkKeymap *keyboard = gdk_keymap_get_for_display(gdk_display_get_default());//获取大小写灯if (gdk_keymap_get_caps_lock_state(keyboard)) {modifiers |= SPICE_INPUTS_CAPS_LOCK;}//获取小数字键盘灯if (gdk_keymap_get_num_lock_state(keyboard)) {modifiers |= SPICE_INPUTS_NUM_LOCK;}//获取滚轮灯if (gdk_keymap_get_scroll_lock_state(keyboard)) {modifiers |= SPICE_INPUTS_SCROLL_LOCK;}return modifiers;
}/**
* spice_inputs_channel_set_key_locks:
* @channel: a #SpiceInputsChannel
* @locks: #SpiceInputsLock modifiers flags
* 设置guest系统中的键盘灯(Caps大写灯, Num数字灯, Scroll滚动灯)
**/
void spice_inputs_channel_set_key_locks(SpiceInputsChannel *channel, guint locks)
{SpiceMsgOut *msg;if (spice_channel_get_read_only(SPICE_CHANNEL(channel)))return;msg = set_key_locks(channel, locks);if (!msg) /* you can set_key_locks() even if the channel is not ready */return;spice_msg_out_send(msg); /* main -> coroutine */
}