【智体OS】官方上新发布智体电视:基于rtpc和rttouchpad实现智体电视的手机遥控-可安装任意PC应用用于智体电视
dtns.network是一款主要由JavaScript编写的智体世界引擎(内嵌了three.js编辑器的定制版-支持以第一视角浏览3D场馆),可以在浏览器和node.js、deno、electron上运行,它是一个跨平台的软件,支持多个操作系统使用!
dtns.connector是dtns.network的客户端软件,允许多用户方便自由地连接dtns.network的智体设备。支持使用内置的poplang智体编程语言实现3D组件的智能化编程——语法超简单,一句话语法,人人轻松上手!通过poplang智体编程,可轻松创建、编辑、分发xverse-3D智体应用。
本次上新的主要内容为:使用rtpc实时分布式PC远程访问和实时控制智体电视,并基于rttouchpad实现智体电视遥控器(rtpc3.3.dpkg版本)
更新内容
1、使用dpkg机制,集成和拓展dtns-rtpc-api,开发了rtpc分布式远程访问和实时控制的DPKG插件rtpc3.3.dpkg(dtns.top官网下载)
2、rtpc和rttouchpad共同支持屏幕同步功能、鼠标点击功能、文字输入功能
3、支持访问内网算力设备,主要是依赖于dtns-api来进行访问(分布式设备终端远程访问),可取代大部分的代理访问机制。
4、可方便集成到了dtns.os的系统应用面板中。
5、可使用poplang调用dtns-rtpc-api,实现桌面操作系统和智体电视的控制机器人
6、可在手机上安装dtns.connector智体OS的客户端,打开rtpc3.3dpkg,点击在上角的【触屏】以激活遥控器功能,实现鼠标移动、点击、鼠标滚动、方向键操作(手机触控版浏览器)
7、利用dtns.network的智体OS操作系统,安装rtpc和rttouchpad智体应用,可以方便地将PC电脑(macos、windows)升级为智体电视机。可以安装数以千万计的第三方应用,并且方便地手机-PC电脑共享视频应用会员等等诸多好处。
完全开源:rtpc和rttouhpad开源、dtns.os和dtns.network等项目均开源。详见文末、或访问dtns.top智体OS官网。
使用教程
一、打开dtns.connector的dweb头榜界面,点击上传了的rtpc3.3.dpkg(或任意其它最新版本)

二、进入rtpc远程访问和实时管理的智体应用,可以看到最新的macos桌面内容(点击锁屏可见到输入密码提示框,使用右上角的功能-input可以输入文本密码)

三、点击右上角的“功能”,再点击input输入密码*****

四、输入完密码,点击->登录箭头登录

五、进入macos系统后,可以看到视频应用界面

六、点击右上角的【画面】后,可见状态为【触屏】,可使用移动鼠标、上下滚动鼠标、进行运作操作(前后左右的移动来控制键盘上的前后左右键——用于调整音量、前进后退等)

Input的poplang代码如下:
set tips 请输入:
$.prompt tips
= keystr $ret
$.g_rtpc.hideTools
#发送键盘输入内容
set p **{"string":""}
object.set p.string keystr
/rtpc/string/type p
 
注:使用了全局函数 . p r o m p t 来提示输入,并使用 .prompt来提示输入,并使用 .prompt来提示输入,并使用.g_rtpc.hideTools来隐藏功能栏,并最终调用dtns-rtpc-api:/rtpc/string/type来实现文本密码的输入。
rtpc3.3.dpkg的源码分享
/* eslint-disable */
<!--
 * @Description: RtPcClient
 * @Author: poplang
 * @Date: 2024-12-5
 * @LastEditors:
 * @LastEditTime:
 -->
 <template>
    <div style="width: 100%;height: 100%;padding:0px;margin: 0px;" >
      <div @click="back" style="color:black;position: fixed;left:8px;top:8px;z-index: 399;"> ❮返回 </div>
      <div style="color:black;position: fixed;left:0;right:0;top:8px;z-index: 359;text-align: center;  font-size: 18px;font-weight: 800;">{{ title }}</div>
      <div  style="color:black;position: fixed;right:8px;top:8px;z-index: 399;"><span @click="showTouchPadFlag=!showTouchPadFlag" style="margin-right: 8px">{{ showTouchPadFlag?'触屏':'画面' }}</span><span @click="syncScreen" style="margin-right: 8px">{{ syncScreenTips }}</span><span @click="showFlag=true" style="margin-right: 8px">功能</span>
        <!-- <span @click="queryScreen">刷新</span> -->
      </div>
      <!-- <div style="color:red;position: fixed;right:8px;top:8px;z-index: 399;"><b>[分数] {{ top_cnt }} : {{ success_cnt  }}</b></div> -->
      <!-- <div v-show="showInput" style="position: fixed;z-index: 199; display:flex;bottom: 5px;left:0;right: 0;height: auto;text-align: center;margin-bottom: 2px;padding:0px 10px 0px 10px;">
        <input @keydown.enter="keyDown" style="width:100%; height:28px; padding-left:5px; border:1px solid #eeeeee; font-size:13px;" v-model="msg" />
        <button @click="send" style="color: rgb(255, 255, 255);width:70px;border-radius: 0px; font-size: 13px; height: 28px; background-color: rgb(18, 173, 245); border: none;">发送</button>
      </div> -->
      <RtTouchPad v-if="showTouchPadFlag"/>
      <div v-else style="position:fixed;top: 50px;bottom: 0px;left: 0px;right: 0px;z-index: 9;overflow-x: auto;overflow-y: auto;">
        <img :src="base64" style="width: auto;height: auto;" @mousedown="mousedown"/>
      </div>
      <van-popup v-model="showFlag" position="top" :style="{ height: '35%' }" >
        <van-grid>
        <van-grid-item  @click="call(item)"  v-for="(item,index) in list" :key="index" icon="photo-o" :text="item.title"></van-grid-item>
        </van-grid>
      </van-popup>
    </div>
  </template>
  <script>
  import RtTouchPad from './RtTouchPad.vue';
  export default {
    name: "RtPcClient",
    props: ["value"],
    components: { RtTouchPad },
    data() {
      return {
        title:'RTPC客户端',
        // showInput:false,
        base64:null,
        // syncScreenId:0,
        syncScreenNowFlag:false,
        syncScreenTips:'同步',
        syncScreenTipsStart:'同步',
        syncScreenTipsStop:'静止',
        showFlag:false,
        list:[],
        popRutimes:[],
        showTouchPadFlag:false,
      }
    },
    async created()
    {
      this.user_id = localStorage.user_id
    //   setInterval(this.queryScreen,10000)
    },
    mounted(){
        // this.queryScreen()
        this.syncScreen()
 
        //允许使用poplang脚本进行功能拓展。
        this.queryPopPlugins()
        window.g_rtpc = {}
        g_rtpc.queryPopPlugins = this.queryPopPlugins
        g_rtpc.stopSyncScreen = this.stopSyncScreen
        g_rtpc.syncScreen = this.syncScreen
        g_rtpc.queryScreen = this.queryScreen
        g_rtpc.hideTools = this.hideTools
        g_rtpc.showTools = this.showTools
 
    },
    beforeRouteLeave(to,from,next){
      // if(this.syncScreenId) clearInterval(this.syncScreenId)
      console.log('beforeRouteLeave-to-from:',to,from)
      if(to.path != from.path)
      {
        this.stopSyncScreen()
        console.log('into beforeRouteLeave')
        next();
      }
    },
    methods: {
        back(){
          this.stopSyncScreen()
          this.$router.go(-1)
        },
        hideTools()
        {
          this.showFlag = false
        },
        showTools()
        {
          this.showFlag = true
        },
        stopSyncScreen()
        {
          if(this.syncScreenNowFlag)
          {
            // clearInterval(this.syncScreenId)
            this.syncScreenNowFlag = false
            this.syncScreenTips = this.syncScreenTipsStart
          }
 
          //对poplang进行资源回收
          if(this.popRutimes)
          {
            for(let i=0;i<this.popRutimes.length;i++)
            {
              this.popRutimes[i].quit() //退出所有循环和脚本。
              console.log('quit-poplang-',i)
            }
          }
        },
        async syncScreen()
        {
          if(this.syncScreenNowFlag) return this.stopSyncScreen()
          this.syncScreenNowFlag = true//setInterval(this.queryScreen,5000)
          this.syncScreenTips = this.syncScreenTipsStop
          while(this.syncScreenNowFlag)
          {
            await this.queryScreen() //得到查询结果(可能1-15s完成600kb的png截图下载)
            await new Promise((res)=>setTimeout(res,100))
          }
        },
        async queryScreen()
        {
            if(typeof g_dtnsManager =='undefined') return false
            let ret =  await g_dtnsManager.run('dtns://web3:'+rpc_client.roomid+'/rtpc/screen/cap')
            if(ret && ret.ret) this.base64 = ret.base64
            else console.log('query-screen-ret:',ret)
        },
        async mousedown(e)
        {
            if(this.click_event_now_flag) console.log('this.click_event_now_flag is true')
            console.log('RtPcClient.vue mousedown-event:',e)
            let x = e.offsetX , y = e.offsetY//e.layerX, y = e.layerY//e.clientX, y = e.clientY
            if(typeof g_dtnsManager =='undefined') return false
            this.click_event_now_flag = true
            let ret = await g_dtnsManager.run('dtns://web3:'+rpc_client.roomid+'/rtpc/mouse/move',{x,y,click:true})//,click:true
            if(!ret || !ret.ret) g_dchatManager.viewContext.$toast('移动鼠标失败,原因:'+(ret ? ret.msg:'未知网络原因'))
            // else{
            // ret = await g_dtnsManager.run('dtns://web3:'+rpc_client.roomid+'/rtpc/mouse/click')
            // if(!ret || !ret.ret) g_dchatManager.viewContext.$toast('点击屏幕执行失败,原因:'+(ret ? ret.msg:'未知网络原因'))
            // await new Promise((res)=>setTimeout(res,100))
            // await this.queryScreen()
            // }
            await new Promise((res)=>setTimeout(res,100))
            this.click_event_now_flag = false
        },
        async call(item)
        {
          let data = await g_dchatManager.goFile(item.fileid,true)
          if(!data) return false
          let binaryData = data.filedata
          let utf8decoder = new TextDecoder()
          let poplangStr  = utf8decoder.decode(binaryData)
          let poplang = new PopRuntime()
          this.popRutimes.push(poplang)
          console.log('run-item-popRuntimes:',item.title,item,data,poplangStr,this.popRutimes)
          let rets = await poplang.runScript(null,poplangStr) //注意while 循环
          console.log('run-item-result:',rets)
          return true
        },
        async queryPopPlugins()
        {
          if(typeof g_dtnsManager =='undefined') return false
          let ret = await g_dtnsManager.run('dtns://web3:'+rpc_client.roomid+'/rtpc/poplang/apps')
          if(ret && ret.ret)
          {
            return this.list = ret.list
          }
          return false
        },
        send()
        {
 
        },
        keyDown()
        {
 
        }
    }
  }
  </script>
<style scoped>
</style>
 
 
注:对比rtpc2.*版本,主要是引入了RtTouchPad组件,用于实现手机端的触控板遥控智体电视机(功能类似笔记本电脑键盘下方中间的touch-pad触控面板)。并且,调整了【功能】栏的能力,使得直接使用.pop代码可以轻松拓展任意的rtpc智体电视的控制代码(基于poplang构建的智体应用插件)。
总结:rtpc和rttouchpad的结合,使得智体电视变成了一个非常易于使用的智体设备。功能强大,应用丰富(千万级),并且支持poplang拓展智体电视机的功能插件,从而大大提升了智体电视的用户体验——内容极度丰富、使用超级简单。















![[NeurlPS 2022] STaR 开源代码实现解读](https://i-blog.csdnimg.cn/direct/6698f7be8b9845129bb5b482cc8a8964.png)

