Spice下命令spicy的USB重定向过程分析

Python实战:超分辨率图像质量评估全攻略——PSNR、SSIM、LPIPS与NIQE的代码实现与优化 本文详细介绍了在Python中实现超分辨率图像质量评估的完整方案,涵盖PSNR、SSIM、LPIPS和NIQE四大核心指标。通过模块化代码设计、多进程并行处理和GPU加速优化,帮助开发者构建高效、可扩展的评估系统,并提供了实战避坑指南与结果解读方法。 阅读详情

在spice-gtk-0.30内部有一个spicy命令用于链接远程的虚拟机,
例如spicy -h 172.16.3.4 -p 6700 这样就可以链接到虚拟桌面
其客户端有个USB 设备重定向管理功能,在spicy内有个Input选项卡,其子项有个“Select USB Devices for redirection”。选择重定向USB 设备,点开后就会出现列有USB设备的对话矿对话框,就可以选择USB 设备进行重定向。其如下图所示:
这里写图片描述
弹出的对话况如下所示:
这里写图片描述
可以看到所有的USB设备都一GTK CheckButton的形式列出来了,那么当选中里面的USB设备时,本地的USB设备就会被重定向到虚拟桌面Win7下面:
其实现的流程如下:
这里写图片描述

相关源文件:spicy.c、usb-device-manager.c、channel-usbredir.c、usb-device-widget.c
在usb-device-widget.c中的代码如下:

static GObject *spice_usb_device_widget_constructor(
    GType gtype, guint n_properties, GObjectConstructParam *properties)
{
    GObject *obj;
    SpiceUsbDeviceWidget *self;
    SpiceUsbDeviceWidgetPrivate *priv;
    GPtrArray *devices = NULL;
    GError *err = NULL;
    GtkWidget *label;
    gchar *str;
    int i;
printf("spice_usb_device_widget_constructor-------------usb-device-widget.c\n");
    {
        /* Always chain up to the parent constructor */
        GObjectClass *parent_class;
        parent_class = G_OBJECT_CLASS(spice_usb_device_widget_parent_class);
        obj = parent_class->constructor(gtype, n_properties, properties);
    }

    self = SPICE_USB_DEVICE_WIDGET(obj);
    priv = self->priv;
    if (!priv->session)
        g_error("SpiceUsbDeviceWidget constructed without a session");

    label = gtk_label_new(NULL);//创建lable控件
    str = g_strdup_printf("<b>%s</b>", _("Select USB devices to redirect"));//控件的内容
    gtk_label_set_markup(GTK_LABEL (label), str);//设置lable字体属性
    g_free(str);
    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);//设置对齐
    gtk_box_pack_start(GTK_BOX(self), label, FALSE, FALSE, 0);//启动容器

    priv->manager = spice_usb_device_manager_get(priv->session, &err);//从session中获取manager
    if (err) {
        spice_usb_device_widget_show_info_bar(self, err->message,
                                              GTK_MESSAGE_WARNING,
                                              GTK_STOCK_DIALOG_WARNING);
        g_clear_error(&err);
        return obj;
    }

    g_signal_connect(priv->manager, "device-added",
                     G_CALLBACK(device_added_cb), self);//设置回调函数用于处理USB热插拔
    g_signal_connect(priv->manager, "device-removed",
                     G_CALLBACK(device_removed_cb), self);
    g_signal_connect(priv->manager, "device-error",
                     G_CALLBACK(device_error_cb), self);
//从manager内获取device列表是根据filter去获取过滤USB设备规则,但是此处是将所有的USB设备都呈现,因此filter为空
    devices = spice_usb_device_manager_get_devices(priv->manager);
    if (!devices)
        goto end;

    for (i = 0; i < devices->len; i++)//以gtk内checkbutton控件的模式列出所有设备
      {  device_added_cb(NULL, g_ptr_array_index(devices, i), self);
        printf("xxxxxxxxxxxxxxx--usb-device-widget.c\n");

       } 
    g_ptr_array_unref(devices);//清空devices

end:
    spice_usb_device_widget_update_status(self);//更新控件状态

    return obj;
}

在对话框构建constructor内会为每个USB设备建立CheckButton控件,如下:

static void device_added_cb(SpiceUsbDeviceManager *manager,
    SpiceUsbDevice *device, gpointer user_data)
{
    SpiceUsbDeviceWidget *self = SPICE_USB_DEVICE_WIDGET(user_data);
    SpiceUsbDeviceWidgetPrivate *priv = self->priv;
    GtkWidget *align, *check;
    gchar *desc;
printf("device_added_cb-----usb-device-widget.c\n");
    desc = spice_usb_device_get_description(device,//获取usb设备描述符
                                            priv->device_format_string);
    check = gtk_check_button_new_with_label(desc);//创建checkbutton
    g_free(desc);//创建完毕后就释放掉

    if (spice_usb_device_manager_is_device_connected(priv->manager,//检测usb设备是否链接状态如果是连接的就设置checkbutton为真
                                                     device))
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);//设置checkbutton为Ture

    g_object_set_data_full(//设置数据和回调函数
            G_OBJECT(check), "usb-device",
            g_boxed_copy(spice_usb_device_get_type(), device),
            checkbox_usb_device_destroy_notify);
    g_signal_connect(G_OBJECT(check), "clicked",//注册点击checkbutton事件
                     G_CALLBACK(checkbox_clicked_cb), self);//当点击事件触发时调用回调函数checkbox_clicked_cb

    align = gtk_alignment_new(0, 0, 0, 0);//创建对齐控件
    gtk_alignment_set_padding(GTK_ALIGNMENT(align), 0, 0, 12, 0);
    gtk_container_add(GTK_CONTAINER(align), check);//在checkbutton中添加对齐方式
    gtk_box_pack_end(GTK_BOX(self), align, FALSE, FALSE, 0);
    spice_usb_device_widget_update_status(self);//更新usb控件状态
    gtk_widget_show_all(align);
}

在建立成功后注册CheckButton的选中点击事件:

static void checkbox_clicked_cb(GtkWidget *check, gpointer user_data)
{
    SpiceUsbDeviceWidget *self = SPICE_USB_DEVICE_WIDGET(user_data);
    SpiceUsbDeviceWidgetPrivate *priv = self->priv;
    SpiceUsbDevice *device;

    device = g_object_get_data(G_OBJECT(check), "usb-device");//获取数据

    if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check))) {//获取checkbutton的状态,为Ture
        connect_cb_data *data = g_new(connect_cb_data, 1);
        data->check = g_object_ref(check);
        data->self  = g_object_ref(self);
        printf("checkbox_clicked_cb---true-------usb-device-widget.c\n");
        spice_usb_device_manager_connect_device_async(priv->manager,//重定向设备
                                                      device,
                                                      NULL,
                                                      connect_cb,
                                                      data);
    } else {//如果状态为False则断开链接

      printf("checkbox_clicked_cb---false-------usb-device-widget.c\n");
        spice_usb_device_manager_disconnect_device(priv->manager,//断开channel与device
                                                   device);
    }
    spice_usb_device_widget_update_status(self);
}

到此两个事件,一个选中事件则调用spice_usb_device_manager_connect_device_async对该USB 设备俄进行重定向
另一个取消选中,就会掉用spice_usb_device_manager_disconnect_device,断开channel和device的链接,取消重定向,

一先看看简单的取消的过程:这个函数在usb-device-manager.c文件内定义如下:

void spice_usb_device_manager_disconnect_device(SpiceUsbDeviceManager *self,
                                                SpiceUsbDevice *device)
{
    g_return_if_fail(SPICE_IS_USB_DEVICE_MANAGER(self));
    g_return_if_fail(device != NULL);//device为空退出

    SPICE_DEBUG("disconnecting device %p", device);
printf("spice_usb_device_manager_disconnect_device,disconnecting device %p ------usb-device-manager.c\n",device);
#ifdef USE_USBREDIR
    SpiceUsbredirChannel *channel;

    channel = spice_usb_device_manager_get_channel_for_dev(self, device);//根据device获取channel
    if (channel)
        spice_usbredir_channel_disconnect_device(channel);//清空channel内的相关device并设置状态
   #ifdef G_OS_WIN32
   //没有在windows下使用,因此代码省略注销     
   #endif     
 #endif
}

在这个函数内部首先根据device获取相匹配的Channel,在对Channel内的device进行清空:

static SpiceUsbredirChannel *spice_usb_device_manager_get_channel_for_dev(
    SpiceUsbDeviceManager *manager, SpiceUsbDevice *device)
{
#ifdef USE_USBREDIR
    SpiceUsbDeviceManagerPrivate *priv = manager->priv;
    guint i;

    for (i = 0; i < priv->channels->len; i++) {//获取device相对应的channel
        SpiceUsbredirChannel *channel = g_ptr_array_index(priv->channels, i);//获取channel
        libusb_device *libdev = spice_usbredir_channel_get_device(channel);
        if (spice_usb_device_equal_libdev(device, libdev))//如果两者匹配就返回channel
            return channel;//返回device对应的channel
    }
#endif
    return NULL;
}

清空函数spice_usbredir_channel_disconnect_device在channel-usbredir.c内部

void spice_usbredir_channel_disconnect_device(SpiceUsbredirChannel *channel)
{
    SpiceUsbredirChannelPrivate *priv = channel->priv;

    CHANNEL_DEBUG(channel, "disconnecting device from usb channel %p", channel);
    printf("spice_usbredir_channel_disconnect_device, priv->state=%d---------channel-usbredir.c\n",priv->state);
    switch (priv->state) {
    case STATE_DISCONNECTED:
    case STATE_DISCONNECTING:
        break;
#if USE_POLKIT
    case STATE_WAITING_FOR_ACL_HELPER:
        priv->state = STATE_DISCONNECTING;
        /* We're still waiting for the acl helper -> cancel it */
        spice_usb_acl_helper_close_acl(priv->acl_helper);
        break;
#endif
    case STATE_CONNECTED://设备处于链接状态
        /*
         * This sets the usb event thread run condition to FALSE, therefor
         * it must be done before usbredirhost_set_device NULL, as
         * usbredirhost_set_device NULL will interrupt the
         * libusb_handle_events call in the thread.
         */
        printf("STATE_CONNECTED --------channel-usbredir.c\n");
        {
            SpiceSession *session = spice_channel_get_session(SPICE_CHANNEL(channel));//从SpiceChannel中获取session
            if (session != NULL)
                spice_usb_device_manager_stop_event_listening(//停止监听
                 spice_usb_device_manager_get(session, NULL));//获取USBmanager即从SpiceSession获取SpiceUsbDeviceManager
        }
        /* This also closes the libusb handle we passed from open_device */
        usbredirhost_set_device(priv->host, NULL);//清空usbhost
        libusb_unref_device(priv->device);//去掉引用计数
        priv->device = NULL;//清空设备
        g_boxed_free(spice_usb_device_get_type(), priv->spice_device);//清空
        priv->spice_device = NULL;
        priv->state  = STATE_DISCONNECTED;//设置状态为断开状态
        break;
    }
}

可以看到在该channel内的device被清空了,首先就是要告知manager停止对该device的事件监听,退出这个device的事件线程,

spice_usb_device_manager_stop_event_listening如下:

void spice_usb_device_manager_stop_event_listening(
    SpiceUsbDeviceManager *self)
{
    SpiceUsbDeviceManagerPrivate *priv = self->priv;

    g_return_if_fail(priv->event_listeners > 0);

      priv->event_listeners--;//运行监听计数减1
      printf("priv->event_listeners--= %d-----usb-device-manager.c\n",priv->event_listeners);
    if (priv->event_listeners == 0)
        priv->event_thread_run = FALSE;//设置线程运行开关为FALSE用来关闭该线程
}
GD32 I2C中断通信实战:主机与从机高效数据交换方案 本文详细解析了GD32微控制器I2C中断通信的实战方案,通过配置I2C0为主机、I2C1为从机,实现高效的双向数据交换。文章深入剖析了中断服务程序(ISR)的核心配置、关键状态标志位处理以及事件驱动机制,帮助开发者避免常见陷阱,提升系统响应速度与资源利用率,适用于传感器连接、多机通信等嵌入式场景。 阅读详情

相关推荐

创客学院嵌入式驱动开发——学习资料汇总

1.创客学院知识巩固-01C语言回顾_C/C++_Set_Mode的博客-优快云博客https://blog.youkuaiyun.com/Set_Mode/article/details/94431050 2.创客学院知识巩固-02数据结构_Set_Mode的博客-优快云博客https://blog.youkuaiyun.com/Set_Mode/article/details/94431087 3.创客学院知...

snaking616 5118

SPICE 协议 USB 重定向

SPICE 协议 USB 重定向 用SPICE协议来进行USB透传的介绍,在SPICE官网上有:Spice 官网 kvm xml配置 <device> <controller type='usb' index='0' model='ich9-ehci1'/> <controller type='usb' index='0' model='ich9-uhci1'>...

WEi的博客 4231

Kali Linux下John the Ripper实战:从识别yescrypt哈希到破解zip压缩包(保姆级避坑指南)

本文详细介绍了在Kali Linux中使用John the Ripper工具从识别yescrypt哈希到破解zip压缩包的全过程。针对常见的'No password hashes loaded'报错,提供了两种解决方案,并扩展讲解了哈希识别、zip文件破解及性能优化技巧,是安全测试人员的实用指南。

weixin_29323365的博客 237

SPICE源码笔记

SPICE 源码笔记

qq_33190216的博客 2197

MounRiver Studio实战:像管理个人项目一样整理沁恒MCU的EVT例程(附文件结构图)

本文详细介绍了如何使用MounRiver Studio重构沁恒MCU的EVT例程,实现工程化管理。通过分析官方EVT设计的局限性,提出标准化的目录结构和迁移步骤,帮助开发者提升代码可维护性和团队协作效率。文章还提供了MounRiver Studio的关键配置参数和常见问题排查指南,适用于沁恒MCU开发者。

weixin_33940469的博客 356

深入解析DisplayPort(DP)接口:从主链路到辅助通道的全方位技术剖析

本文深入解析DisplayPort(DP)接口的核心技术架构,重点剖析了其三大功能模块:承载视频/音频数据洪流的Main-Link主链路、负责链路训练与设备控制的AUX CH辅助通道,以及实现智能交互的HPD热插拔检测。文章详细阐述了主链路的可伸缩Lane配置、嵌入式时钟与数据成帧机制,以及辅助通道在设备发现、动态优化信号质量(链路训练)中的关键作用,揭示了DP接口实现高效率与灵活性的设计哲学。

weixin_29267307的博客 492

USB重定向

  第一期中,我们一起简要的看了下传统PC和桌面云下USB重定向和USB设备重定向方式的差异,了解了桌面云下外设兼容性问题来源的根源-USB设备本身驱动不规范/不支持,   或者虚拟机驱动实现上与USB设备对接存在疏漏。   本期我们来详细的了解下传统PC和桌面云的外设工作原理   目前,在通用操作系统上,USB外设占主流,下面就以USB摄像头举例说明其两种重定向技术的区别。  传统PC ...

weixin_30783913的博客 2830

Cadence IC618/Spectre231安装避坑指南:详解环境变量配置与License管理那些事儿

本文深入解析Cadence IC618/Spectre231安装过程中的环境变量配置与License管理难题,提供从变量冲突解决到高效License管理的实用方案。针对常见的64位标识冲突、路径污染及License服务器连接问题,给出具体诊断步骤和优化建议,帮助用户构建稳定可靠的EDA环境。

weixin_33737134的博客 616

云计算疑难杂症解决方案 - USB重定向

不用spice协议,自有开发的远程桌面协议,那么可以将usb重定向的逻辑整理成一个模块,具体私信。在办公环境下,如何将推流客户机、瘦终端...上的usb设备重定向到虚拟机内。客户机系统,虚拟机系统是Windows或者Linux。应用 spice 协议开源项目,这个协议已经支持了。

li_jiejun的专栏 5830

SAP-ABAP:SAP HANA性能神器FDA:是极速查询的引擎,也是CPU过载的元凶

在SAP S/4HANA的世界里,有一个被ABAP开发者们既爱又怕的特性——Fast Data Access(FDA),它能将性能提升百倍,也能让CPU瞬间飙升。本文将带您全面解剖这一核心机制。

baidu_35680696的博客 849

[Python图像识别] 五十二.水书图像识别 (2)基于机器学习的濒危水书古文字识别研究

上一篇文章详细讲解如何利用数据增强方法实现图像数据集的扩充,并以濒危水书作为案例讲解。这篇文章将详细讲解基于机器学习的水书图像识别方法,以图像像素统计为特征开展图像分类讲解,这是最基础的方法,也为后续深度学习图像分类描述提供支撑。基础性文章,希望对您有所帮助!让我们开始吧,且看且珍惜。

杨秀璋的专栏 990

客户端通过spice-gtk实现USB重定向

1.安装必要的工具: sudo apt-get install build-essential autoconf git-core intltool 2.安装必要的依赖包: sudo apt-get install libtool liblog4cpp5-dev libavcodec-dev libssl-dev xlibmesa-glu-dev libasound-dev li...

weixin_30297281的博客 645

C++多线程 task--std::promise和std::future

本文主要讲解C++11/14/17中所提供的应用于多线程编程中的Task机制。Task可由如下几部分取得而本文主要讲解std::promise和std::future相关的内容。std::promise和std::future通过一个数据管道进行交流,可以将std::promise看作生产者,std::future看作消费者,其两者形成如下的方式交互std::promise本身是一个模版类,通过std::promise可以像数据管道中设置value,异常和相应的通知信息。std::promise提供了如下接

qls315的博客 1819

SPICE源码分析(十四):设备重定向(USB与智能卡)

通道类型用途协议SMARTCARD智能卡重定向VSCUSBREDIRUSB重定向usbredirWEBDAV文件共享WebDAVPORT通用端口自定义设计特点:统一框架:RedCharDevice提供通用字符设备抽象压缩优化:LZ4压缩减少网络开销背压控制:防止数据堆积和DoS迁移支持:设备状态随VM迁移安全传输:依赖TLS加密。

@ 576

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

spice-gtk之usb相关代码(2)

回顾 在上一篇关于usb的代码分析https://blog.youkuaiyun.com/FlayHigherGT/article/details/85261810中,我们聊到了一些关于usb插入拔出之后spicy回应的某些回调函数,也聊到了如何实现连接虚拟机时自动重定向已经插着的usb,但是经过最近的研究,发现这个功能其实是在spicy里面是有功能实现的,下面细说。 spicy两个功能参数 1、spi...

FlayHigherGT的博客 1071

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

spice-gtk 之usb相关代码(1)

spice-gtk是里面有一个spicy的测试工具,可以直接用来远程连接虚拟机代替remote-viewer,但是spicy远程连接的虚拟机却不能自动加载插入的usb设备,下面简单解析一下spice-gtk中关于usb的代码. usb-device-manager.c 下面是usb-device-manager.c中几个重要的函数调用:spice_usb_device_manager_init...

FlayHigherGT的博客 1366

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

spicy client usbredir 参数说明

-spice-usbredir-auto-redirect-filter

dns007 2037

Ubuntu12.10 下搭建基于KVM-QEMU的虚拟机环境(十九)

Spice 客户端和spice 服务端通常运行在不同的机器上,运行spice服务端的主机通常有着多颗多核的CPU以及几十G以上的内存,通过底层支持虚拟化的KVM+qemu环境虚拟出几台到几十台虚拟机,供运行Spice客户端的终端连接使用,这些终端通常配置较低,仅仅充当虚拟桌面的显示之用,当然还有键盘、鼠标的输入和声音的输出等基本功能,这些在我们之前介绍的spice连接中都已经具备。       

hbsong75的专栏 7715

ppt-master 中的 brutalist 粗野主义风格:如何为高密度 PPT 落地报纸式排版完整指南

本文面向 [ppt-master](https://link.gitcode.com/i/735c022b75e9e7057fa46fd046c1f0e5) 的新手读者,拆解仓库里 [brutalist.md](https://link.gitcode.com/i/0fa113b1701c3181efb3104e70037781) 这份视觉风格规范:什么是"报纸式粗野主义",它管形状、排版、色彩、

gitblog_00420的博客 444

终端里的“Playwright“:TTT 的 --exec 脚本化交互与 --listen 远程控制完全指南

TTT(Terminal Text Tool)是一款运行在终端里的完整 IDE,而它内置的 **`--exec` 脚本化交互**与 **`--listen` 远程控制**,让它成了终端界的 "Playwright":你可以用一行命令模拟鼠标点击、按键输入、执行命令面板操作,还能随时截图、导出调试状态。无论是给 AI Agent 编程接口、做自动化回归测试,还是在正在运行的编辑器上远程抓 bug,这

gitblog_00858的博客 1077

一套Web UI驾驭3大AI代理:OpenPortal切换OpenCode/Codex/Claude多后端实践

OpenPortal 是一款移动端优先的 Web UI,用一个浏览器界面即可同时驾驭 OpenCode、Codex、Claude 三大 AI 编码代理,支持会话管理、Git 集成和多实例切换。它把三个后端的启动、端口分配、实例管理都收敛到一条 `openportal` 命令里,让你在手机、平板或任何设备的浏览器中随时指挥 AI 写代码。 [![OpenPortal 多后端 AI 代理 Web U

gitblog_00027的博客 170

Spice Usbredirect 性能改进

虚拟桌面,其便于管理和部署以及安全可靠

somyjun的专栏 3243

QEMU/KVM用Virt-Manager启用SPICE显示服务器并使用USB热插拔重定向和剪切板共享

摘要:本文介绍了在Virt-Manager中将虚拟机显示服务器从VNC更换为SPICE的方法。SPICE提供更流畅的远程画面和方便的USB热插拔功能。配置步骤包括:1)设置显卡为qxl;2)变更显示协议为SPICE;3)添加USB重定向设备。文中特别提醒Arch Linux用户需安装完整qemu-desktop包,并强调需在虚拟机中安装SPICE客户机工具和USB重定向驱动。最后说明通过Virt-Manager界面可便捷实现USB设备重定向,但默认仅支持一个设备。

观象的博客 2128

Spice Windows Client 利用 USBDk 实现USB重定向

Spice Windows Client 利用 USBDk 实现USB重定向

张在兴 从蜗牛到大牛 奋斗 1万+

spice在桌面虚拟化中的应用系列之三(USB映射实现,SSL加密,密码认证,多客户端支持)...

本系列其它文章 spice在桌面虚拟化中的应用系列之一(spice简介,性能优化等) spice在桌面虚拟化中的应用系列之二(Linux平台spice客户端的编译安装,支持USB映射) 1.spice的USB重定向 1.1 介绍 使用usb重定向,在client上插入的U盘会被重定向到虚拟机中. 其有两种实现方式,自动重定向(所有插入client中的U盘都被重定向),或者手动选择需要重定...

weixin_33850015的博客 895

PXVDI企业级免费PVE桌面虚拟化SPICE模式部署教程ProxmoxVE

PXVDI是基于Proxmox VE为底层的免费桌面虚拟化软件。PXVDI企业级免费桌面虚拟化部署教程PXVDI是一款基于Proxmox VE为底层的可商用的免费云桌面套件。首先是PVE是免费的,其次PVE的免费云桌面方案也极为少数。根据官方提出的价格清单,免费版和商业版在功能上主要的区别是2点。是否有支持。免费版没有技术支持,适合有技术人员的公司。是否支持horizon。RDP协议在基本的云桌面环境中已经很好了。

weixin_43770811的博客 1万+
上一篇: 增加Android下spinner控件的点击下拉列表自动更新事件并实例应用--USB摄像头在spinner内下拉更新(二)
下一篇: VGA GPU passthrough 虚拟桌面pci穿透--Ubuntu与centos的内核升级步骤
葫芦娃二娃
博客等级 码龄15年 1850粉丝 69原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值