<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: 【OpenFDE】ying xu</title>
    <description>The latest articles on DEV Community by 【OpenFDE】ying xu (@ying_xu_0f8a58231902eb42b).</description>
    <link>https://dev.to/ying_xu_0f8a58231902eb42b</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4043455%2Fa1b9cc73-0046-4723-b2b6-24d100edfbd5.png</url>
      <title>DEV Community: 【OpenFDE】ying xu</title>
      <link>https://dev.to/ying_xu_0f8a58231902eb42b</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ying_xu_0f8a58231902eb42b"/>
    <language>en</language>
    <item>
      <title>Our Latest Technical Articles🎉</title>
      <dc:creator>【OpenFDE】ying xu</dc:creator>
      <pubDate>Thu, 03 Sep 2026 10:05:56 +0000</pubDate>
      <link>https://dev.to/ying_xu_0f8a58231902eb42b/our-latest-technical-articles-3f0o</link>
      <guid>https://dev.to/ying_xu_0f8a58231902eb42b/our-latest-technical-articles-3f0o</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/ying_xu_0f8a58231902eb42b/break-free-from-vnc-and-unlock-a-true-multi-window-linux-experience-on-android-4j0m" class="crayons-story__hidden-navigation-link"&gt;Break free from VNC and unlock a true multi-window Linux experience on Android.&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/ying_xu_0f8a58231902eb42b" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4043455%2Fa1b9cc73-0046-4723-b2b6-24d100edfbd5.png" alt="ying_xu_0f8a58231902eb42b profile" class="crayons-avatar__image" width="96" height="96"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/ying_xu_0f8a58231902eb42b" class="crayons-story__secondary fw-medium m:hidden"&gt;
              【OpenFDE】ying xu
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                【OpenFDE】ying xu
                
                
              
              &lt;div id="story-author-preview-content-4564207" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/ying_xu_0f8a58231902eb42b" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4043455%2Fa1b9cc73-0046-4723-b2b6-24d100edfbd5.png" class="crayons-avatar__image" alt="" width="96" height="96"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;【OpenFDE】ying xu&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/ying_xu_0f8a58231902eb42b/break-free-from-vnc-and-unlock-a-true-multi-window-linux-experience-on-android-4j0m" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Sep 3&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/ying_xu_0f8a58231902eb42b/break-free-from-vnc-and-unlock-a-true-multi-window-linux-experience-on-android-4j0m" id="article-link-4564207"&gt;
          Break free from VNC and unlock a true multi-window Linux experience on Android.
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/linux"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;linux&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ubuntu"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ubuntu&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/android"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;android&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/software"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;software&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/ying_xu_0f8a58231902eb42b/break-free-from-vnc-and-unlock-a-true-multi-window-linux-experience-on-android-4j0m" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt;&amp;nbsp;reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/ying_xu_0f8a58231902eb42b/break-free-from-vnc-and-unlock-a-true-multi-window-linux-experience-on-android-4j0m#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Break free from VNC and unlock a true multi-window Linux experience on Android.</title>
      <dc:creator>【OpenFDE】ying xu</dc:creator>
      <pubDate>Thu, 03 Sep 2026 09:47:23 +0000</pubDate>
      <link>https://dev.to/ying_xu_0f8a58231902eb42b/break-free-from-vnc-and-unlock-a-true-multi-window-linux-experience-on-android-4j0m</link>
      <guid>https://dev.to/ying_xu_0f8a58231902eb42b/break-free-from-vnc-and-unlock-a-true-multi-window-linux-experience-on-android-4j0m</guid>
      <description>&lt;h5&gt;
  
  
  &lt;strong&gt;Effect Comparison：&lt;/strong&gt;
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb4ok4d6vf3mm5cc2rs7b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb4ok4d6vf3mm5cc2rs7b.png" alt="Comparison of Results" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Those who have read our previous technical article should already know that we used to run Linux applications on the desktop with the VNC solution，but this solution has a flaw：because it directly projects the Linux screen，there is always only one window during use，no matter how many pages you open，they are all confined within that frame，which is quite inconvenient.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbh1mfk9qnd3jivkv9i8o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbh1mfk9qnd3jivkv9i8o.png" alt="Comparison of Results" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So after research and exploration，we adopted a new technical solution—xserver，which can directly deliver program display content without screen image forwarding；the biggest change in practice is that you can open multiple windows，and the overall interaction is no different from Linux（for example，you can merge and split windows directly by dragging，and you are prompted whether to save when closing a document，etc.）。&lt;/p&gt;

&lt;h5&gt;
  
  
  &lt;strong&gt;Principle Explanation：&lt;/strong&gt;
&lt;/h5&gt;

&lt;p&gt;In case anyone does not know，before explaining the principle，let me mention that we are actually a Linux desktop based on AOSP，with the underlying layer based on Waydroid，so it is somewhat like an Android desktop that can run on Linux&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5hadj9wpba9289evb8lb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5hadj9wpba9289evb8lb.png" alt="Architecture Diagram" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a comparison of the technical structures of the two：you can see that VNC forwards operations and images through vncserver，while the xserver process is much simplified，performing better in aspects such as performance，compatibility，and user experience；next，we will explain the xserver solution in detail：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdpn5trb5e2wvtcgyrnoy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdpn5trb5e2wvtcgyrnoy.png" alt="Architecture Diagram" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a detailed structure diagram of xserver. Let me first briefly introduce the background：Xserver is a core component of the X Window System，and X Window is actually one of the foundations of the graphical environments of Linux distributions；popular Linux desktop environments such as the well-known GNOME and KDE Plasma are all built on the X Window System. So what you can see is that we ported the xserver originally used in Linux systems to our FDE desktop，where it is responsible for managing display devices and processing requests from X clients，allowing Linux applications to run directly on our desktop through this approach.&lt;/p&gt;

&lt;p&gt;Next，let us explain this structure in detail：the orange part on the left consists of the two modules responsible for display in Linux，which pass all display information，including window information，to the ported xserver；our Xserver runs in an Android service（XWindowService）in an independent process，and in this service native functions start a TCP server or a Unix socket server，so that Linux programs supporting the X11 protocol can connect to this server，send drawing instructions to it，and receive input events from it.&lt;/p&gt;

&lt;p&gt;Many extensions and supplementary protocols on Xserver make it still the most compatible and efficient display solution on Linux，supporting both local and remote connections with very small memory usage. Compiling and debugging in the Android NDK is also quite convenient，with no redundant dependencies，and there are many mature solutions we can learn from.&lt;/p&gt;

&lt;p&gt;Below XWindowService there is another module，which is &lt;strong&gt;WindowManager（window manager）&lt;/strong&gt;，a program used to manage and control X Window System (X11) windows. It handles operations such as opening，closing，moving，and resizing windows，and determines the appearance and behavior of windows. On OpenFDE，the Xserver connects to a custom-developed basic window manager，which runs in FDE-X11，has no window decoration function，and additionally implements functions such as a compositor，window property synchronization，and clipboard synchronization.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frs6k2go8kzusqb2zblnh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frs6k2go8kzusqb2zblnh.png" alt="Architecture Diagram" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the window manager，there is a relatively innovative point of ours called**Compositor（compositor）image redirection，**the Compositor extension is enabled in the window manager. Composite allows redirecting the output content of windows during the creation and display of all windows，redirecting the rendering of all windows in a window tree to internal storage，and then finally obtaining the image buffer of the window through the window pointer. The principle by which the compositor implements window effects is also based on this.&lt;/p&gt;

&lt;p&gt;In this way，the image buffer of each window can be separated out and handed over to Android for drawing，that is，directly taking the image data from the Linux window into the Android window.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdu0s86e89erhjul8pvws.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdu0s86e89erhjul8pvws.png" alt="Architecture Diagram" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the green part on the far right is &lt;strong&gt;SurfaceManager and Activity，responsible for displaying content and receiving events&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Among them，SurfaceManager is a module abstracted out by FDE-X11，used to manage all Surfaces that draw buffers. Different Surfaces are passed into the EGL environment of Xserver so that different Surfaces correctly draw different buffers. For some OverrideRedirect windows，no new Surface will be created，and they will be drawn on the window they depend on.&lt;/p&gt;

&lt;p&gt;As for the Activity part，it is mainly used as the window corresponding one-to-one with Linux. In the Android window system，the level handled by an APP window is confined to one level range，and only windows within this level range will have the same interaction behavior as windows of other APPs；currently，the only selectable Android components are Activity and Dialog. Their role is to create a SurfaceView to display the output image，receive Android input events，and send them to Xserver. Under the Android freeform mode used by FDE，the behavior is roughly equivalent to a Linux desktop，and in theory it can even be completely identical.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8fjinrhtc4e9mo1orqfn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8fjinrhtc4e9mo1orqfn.png" alt="Architecture Diagram" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a Linux window is created，an Activity is created in Android，and the image of the Linux window is displayed on the SurfaceView of this Activity；if the Activity receives keyboard or mouse input，it is sent to the corresponding coordinates of Xserver. There are many problems to handle in this process，such as lifecycle synchronization，window types，event redirection，window icon and title bar operations，and so on.&lt;/p&gt;

&lt;p&gt;In addition to what is mentioned above，we also did related work such as &lt;strong&gt;Android and Linux window property synchronization，Android and Linux clipboard synchronization&lt;/strong&gt;，which I will not elaborate on here.&lt;/p&gt;

&lt;p&gt;In summary，unlike the current Xserver implementations on various platforms，because FDE-X11 itself is a desktop environment，with the power of AOSP and the ideas of some open-source solutions（such as Termux:X11），this innovative solution has been realized. The research and development of this solution took quite a long time，but there are still many immature aspects：for example，only part of the complex features of X windows have been implemented；in addition，Android windows are limited by the original design of the framework，and modifying them requires a huge amount of work，especially since the lifecycle overhead is one or two orders of magnitude higher than that of X windows；there is also the more efficient Wayland protocol. All of these leave a lot of room for optimizing user experience.&lt;/p&gt;

&lt;p&gt;Hope this can give you all some reference and inspiration～The code of this solution is also placed in our code repository，and you can take it as you need. If you have any other questions，feel free to leave a message，and they will all be answered one by one.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>ubuntu</category>
      <category>android</category>
      <category>software</category>
    </item>
    <item>
      <title>A step-by-step guide to running Linux applications on your Android desktop</title>
      <dc:creator>【OpenFDE】ying xu</dc:creator>
      <pubDate>Wed, 26 Aug 2026 07:17:12 +0000</pubDate>
      <link>https://dev.to/ying_xu_0f8a58231902eb42b/a-step-by-step-guide-to-running-linux-applications-on-your-android-desktop-53f4</link>
      <guid>https://dev.to/ying_xu_0f8a58231902eb42b/a-step-by-step-guide-to-running-linux-applications-on-your-android-desktop-53f4</guid>
      <description>&lt;p&gt;As those who read our previous article likely know, OpenFDE is a Linux desktop environment built upon the AOSP graphics stack. While it is essentially an Android-based desktop, we have adapted the display and control mechanisms for Linux applications within the AOSP environment. This enables the seamless, integrated display of both Linux and Android applications, allowing users to run programs from different platforms—and leverage their respective software ecosystems—without even noticing the underlying differences. The result is OpenFDE: a Linux desktop environment that integrates seamlessly with Android.&lt;/p&gt;

&lt;p&gt;Of course, this technology is not limited to the OpenFDE desktop; it can also be applied to other Android systems, such as smartphones and tablets. Let’s take a look at the underlying principles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Explanation of Principles
&lt;/h3&gt;

&lt;p&gt;Our concept for OpenFDE involves providing an entry point to launch Linux applications directly; therefore, after careful consideration, we initially adopted VNC technology to handle Linux input and output management.&lt;/p&gt;

&lt;p&gt;VNC (Virtual Network Computing) is essentially a remote desktop control technology that enables users to access and control other computers remotely via the Internet or a local area network (LAN). It works by running a VNC server program on the remote computer; the user connects to this server using a VNC client program, allowing them to view and interact with the remote computer's desktop from their own machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv7pb54x1xaqre8fvpu93.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv7pb54x1xaqre8fvpu93.png" alt="principle" width="799" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The core principle involves the VNC app communicating with the VNC server via the RFB protocol; mouse and keyboard actions are transmitted to the VNC server as input. The VNC server utilizes the Xvnc module to implement the X protocol and communicate with Linux applications, while simultaneously forwarding text (in both Chinese and English) generated by the app to the IBus input method framework for processing (the specifics of the input method mechanism will be detailed later). Keyboard and mouse inputs are passed directly to the Linux application, which returns display data to the VNC server; finally, the display frames are sent back to the app as output.&lt;/p&gt;

&lt;p&gt;It is worth noting that VNC relies on the RFB (Remote Frame Buffer) protocol for screen sharing between the client and server. It operates by rendering images locally and then transmitting them remotely to the client for decoding and display; this architecture ensures platform independence and cross-platform compatibility.&lt;/p&gt;

&lt;p&gt;We selected this solution due to the technology's maturity and short development cycle, which allow for rapid requirement implementation and a product-grade user experience. However, there are drawbacks: VNC is primarily designed for remote control and imposes specific demands regarding efficiency and bandwidth (though latency remains within a few frames when running locally), and there are certain limitations regarding user interaction.&lt;/p&gt;

&lt;p&gt;Let me now explain the key points in detail.&lt;/p&gt;

&lt;h3&gt;
  
  
  VNC server and client
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Resulting Effect
&lt;/h4&gt;

&lt;p&gt;When using the TigerVNC server, the actual parameters used to start &lt;code&gt;vnc server&lt;/code&gt; after installation via &lt;code&gt;apt&lt;/code&gt; are as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/usr/bin/Xtigervnc :2 &lt;span class="nt"&gt;-desktop&lt;/span&gt; firefox_web_browser &lt;span class="nt"&gt;-auth&lt;/span&gt; /home/warlice/.Xauthority &lt;span class="nt"&gt;-geometry&lt;/span&gt; 1900x1200 &lt;span class="nt"&gt;-depth&lt;/span&gt; 24 &lt;span class="nt"&gt;-rfbwait&lt;/span&gt; 30000 &lt;span class="nt"&gt;-rfbport&lt;/span&gt; 5902 &lt;span class="nt"&gt;-pn&lt;/span&gt; &lt;span class="nt"&gt;-SecurityTypes&lt;/span&gt; None &lt;span class="nt"&gt;-BlacklistThreshold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10000000 &lt;span class="nt"&gt;-BlacklistTimeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;firefox_web_browser The script content is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
fde-set-ime-engine firefox_web_browser &amp;amp;   &lt;span class="c"&gt;# Start input method, explained later&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GDK_BACKEND&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;x11
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;QT_QPA_PLATFORM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xcb
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GTK_IM_MODULE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ibus
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;QT_IM_MODULE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ibus
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;QT4_IM_MODULE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ibus
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;im&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ibus
firefox &amp;amp;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The details regarding the input method are described later; here, the startup parameter configuration for &lt;code&gt;vncserver&lt;/code&gt; specifies the layout dimensions (width and height), port, and connection timeout. Additionally, it specifies the startup program—Firefox—which is the application the user intends to launch and use. On OpenFDE, the implementation logic is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  List all available programs on the Linux system and provide launch entry points.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1k775luf4ixxq5d1lcrf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1k775luf4ixxq5d1lcrf.png" alt="example" width="800" height="498"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  When the user clicks the Linux program icon:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First, start the &lt;code&gt;vncserver&lt;/code&gt; using the parameters mentioned above and launch the corresponding Linux application. Once startup is complete, open a new window within the FDE Android application and establish a VNC connection to display the frame data transmitted via the RFB protocol, while simultaneously sending input events—such as keyboard and mouse actions—to the server in accordance with the protocol.&lt;/p&gt;

&lt;p&gt;This provides a seamless user experience, just like launching a Linux program directly on Android.&lt;/p&gt;

&lt;h4&gt;
  
  
  Source Code Solution
&lt;/h4&gt;

&lt;p&gt;When chaining these functions together, modifications inevitably become necessary, requiring customization. After extensive comparative research, the project source code used is as follows.&lt;/p&gt;

&lt;p&gt;APP: &lt;a href="https://github.com/iiordanov/remote-desktop-clients" rel="noopener noreferrer"&gt;GitHub - iiordanov/remote-desktop-clients: VNC, RDP, SPICE, and oVirt/RHEV/Proxmox Clients for Android and Blackberry 10&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This project involves the source code for bVNC, aRDP, aSPICE, and Opaque—four Android remote desktop clients. We are using the bVNC module; although there is a paid "Pro" version available, the documentation indicates that it merely adds encryption capabilities.&lt;/p&gt;

&lt;p&gt;Server: &lt;a href="https://github.com/TigerVNC/tigervnc" rel="noopener noreferrer"&gt;GitHub - TigerVNC/tigervnc: High performance, multi-platform VNC client and server&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source code handling on the server side is somewhat more complex. The server must manage Linux applications and handle actual input and output—specifically, the graphical interfaces of these Linux programs. It utilizes the Xorg X server; VNC Server invokes Xorg via platform-specific libraries (such as Xvnc) and, following its own internal logic, converts the data into the RFB protocol for interaction with the client.&lt;/p&gt;

&lt;p&gt;When compiling libraries on Linux that depend on xorg-xserver, you can compile &lt;em&gt;x0vncserver&lt;/em&gt; if you only need to perform debugging.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;x0vncserver - an inefficient VNC server which continuously polls any X&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;He cannot use all &lt;code&gt;vncserver&lt;/code&gt; startup parameters; the result of launching it is a desktop output. You can refer to&lt;a href="https://github.com/TigerVNC/tigervnc" rel="noopener noreferrer"&gt;GitHub - TigerVNC/tigervnc: High performance, multi-platform VNC client and server&lt;/a&gt; to explore the implementation logic of the server.&lt;/p&gt;

&lt;h4&gt;
  
  
  Compiling TigerVNC Server
&lt;/h4&gt;

&lt;p&gt;FDE uses the apt source code to modify and compile the TigerVNCServer deb package. The specific steps are as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Open /etc/apt/sources.list and uncomment all deb-src entries.&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;source &lt;/span&gt;tigervnc-standalone-server
// After entering the &lt;span class="nb"&gt;source &lt;/span&gt;code directory
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;equivs devscripts &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;mk-build-deps &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="s2"&gt;"apt-get"&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;&lt;span class="nv"&gt;DEB_BUILD_OPTIONS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"parallel=8"&lt;/span&gt; dpkg-buildpackage &lt;span class="nt"&gt;-b&lt;/span&gt; &lt;span class="nt"&gt;-uc&lt;/span&gt; &lt;span class="nt"&gt;-us&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The source code is managed using the quilt tool. For specific usage, please refer to:&lt;/p&gt;

&lt;p&gt;[&lt;strong&gt;quilt Tool Usage Guide&lt;/strong&gt;]  &lt;a href="https://openfde.atlassian.net/wiki/spaces/OpenFDE1/pages/15138835" rel="noopener noreferrer"&gt;f. quilt Tool Usage Guide&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;After successful compilation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;dpkg &lt;span class="nt"&gt;-i&lt;/span&gt;  tigervnc-standalone-server_1.10.1+dfsg-3_arm64.deb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Input Processing and Input Methods
&lt;/h4&gt;

&lt;p&gt;After starting the server and client and establishing a connection, communication follows the RFB protocol. The output is frame data, and what frame data to display is determined by the server side, which basically does not need to be modified. Most of the client's business logic is focused on handling input, i.e., mouse and keyboard events. The simplest approach is to pass all events directly to the server side in the activity's dispatchKeyEvent, which is how bVNC handles it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    @Override
    public boolean dispatchKeyEvent&lt;span class="o"&gt;(&lt;/span&gt;KeyEvent event&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;canvas.getKeyboard&lt;span class="o"&gt;()&lt;/span&gt;.keyEvent&lt;span class="o"&gt;(&lt;/span&gt;event.getKeyCode&lt;span class="o"&gt;()&lt;/span&gt;, event&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Send data packets according to the message format:&lt;/p&gt;

&lt;p&gt;Protocol message - mouse event message is as follows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  +--------------+--------------+--------------+
  | No. of bytes | Type &lt;span class="o"&gt;[&lt;/span&gt;Value] | Description  |
  +--------------+--------------+--------------+
  | 1            | U8 &lt;span class="o"&gt;[&lt;/span&gt;5]       | message-type |
  | 1            | U8           | button-mask  |
  | 2            | U16          | x-position   |
  | 2            | U16          | y-position   |
  +--------------+--------------+--------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Protocol message - keyboard event message is as follows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  +--------------+--------------+--------------+
  | No. of bytes | Type &lt;span class="o"&gt;[&lt;/span&gt;Value] | Description  |
  +--------------+--------------+--------------+
  | 1            | U8 &lt;span class="o"&gt;[&lt;/span&gt;4]       | message-type |
  | 1            | U8           | down-flag    |
  | 2            |              | padding      |
  | 4            | U32          | key          |
  +--------------+--------------+--------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For details, please refer to&lt;/p&gt;

&lt;p&gt;[&lt;strong&gt;RFB Protocol Documentation&lt;/strong&gt;]  &lt;a href="https://www.babeler.cn/transfer/input/" rel="noopener noreferrer"&gt;Input Protocol · RFB Remote Framebuffer Protocol&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It should be noted whether the keyboard keysym used by Android is consistent with the keyboard layout recognized by Linux, that is, whether the keysym of sent events can be correctly recognized on the server side.&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Input Method Requirements
&lt;/h4&gt;

&lt;p&gt;In the use of VNC, there is one requirement that has never been well resolved: text input. English characters are relatively easy to handle—you can directly use key presses to output the desired characters. However, for Chinese characters and other characters in the unicode character set, Linux cannot directly generate them. It has been verified that Linux can receive a small number of Chinese characters in xkeysyms; you can bind a Chinese character to a keyboard key, but the number is also limited by the number of keyboard keys.&lt;/p&gt;

&lt;p&gt;Therefore, if you want to input Chinese, the best approach is to add /usr/bin/ibus-daemon -d &amp;amp; to the startup script and then set the input method to the desired one. However, this also has a problem: the input method running on Linux is disconnected from the FDE desktop usage. How to handle the installation and uninstallation of input methods on Linux? Additionally, the display of the candidate word box is also an issue—if compatibility is not handled well, it will not be displayed in VNC.&lt;/p&gt;

&lt;p&gt;For these reasons, FDE's VNC application integration solution adopts a more complete implementation. Modifications have been made to each stage of the input chain, though it ends at the ibus input method; X programs only serve as the text-receiving party.&lt;/p&gt;

&lt;p&gt;The result is that using the Android input method on the Android VNC client side allows Chinese characters to be output to Linux programs opened on the server side.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F22dlsqcvvlel1ogdzrpr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F22dlsqcvvlel1ogdzrpr.png" alt="example" width="799" height="850"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This involves modifications in three stages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The VNC APP can invoke the input method, intercept and forward characters generated by the input method to the vncserver, without affecting the original normal pathway;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The VNC server can forward received characters to the ibus input method, without affecting the original normal pathway;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The ibus input method can be normally invoked, receive character input into X programs, and does not affect the original normal input.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  VNC APP
&lt;/h4&gt;

&lt;p&gt;To implement input method invocation in the APP, EditText.request() suffices. However, to intercept and obtain the input method content, you need to override EditText, inject a custom InputConnection, and then obtain the input text through the commitText interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;@Override
public boolean commitText&lt;span class="o"&gt;(&lt;/span&gt;CharSequence text, int newCursorPosition&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;DEBUG&lt;span class="o"&gt;){&lt;/span&gt;
        Log.d&lt;span class="o"&gt;(&lt;/span&gt;TAG, &lt;span class="s2"&gt;"commitText() called with: text = ["&lt;/span&gt; + text + &lt;span class="s2"&gt;"], mTextView = ["&lt;/span&gt; + detectEventEditText + &lt;span class="s2"&gt;"]"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;detectEventEditText &lt;span class="o"&gt;==&lt;/span&gt; null&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;super.commitText&lt;span class="o"&gt;(&lt;/span&gt;text, newCursorPosition&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;text instanceof Spanned&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        Spanned spanned &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;Spanned&lt;span class="o"&gt;)&lt;/span&gt; text&lt;span class="p"&gt;;&lt;/span&gt;
        SuggestionSpan[] spans &lt;span class="o"&gt;=&lt;/span&gt; spanned.getSpans&lt;span class="o"&gt;(&lt;/span&gt;0, text.length&lt;span class="o"&gt;()&lt;/span&gt;, SuggestionSpan.class&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        Reflector.invokeMethodExceptionSafe&lt;span class="o"&gt;(&lt;/span&gt;mIMM, &lt;span class="s2"&gt;"registerSuggestionSpansForNotification"&lt;/span&gt;,
                new Reflector.TypedObject&lt;span class="o"&gt;(&lt;/span&gt;spans, SuggestionSpan[].class&lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    Reflector.invokeMethodExceptionSafe&lt;span class="o"&gt;(&lt;/span&gt;detectEventEditText, &lt;span class="s2"&gt;"resetErrorChangedFlag"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    Reflector.invokeMethodExceptionSafe&lt;span class="o"&gt;(&lt;/span&gt;detectEventEditText, &lt;span class="s2"&gt;"hideErrorIfUnchanged"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;mInputModeFlag &lt;span class="o"&gt;==&lt;/span&gt; INPUT_MODE_ONLY_KEYBOARD&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(!&lt;/span&gt;TextUtils.isEmpty&lt;span class="o"&gt;(&lt;/span&gt;text&lt;span class="o"&gt;)){&lt;/span&gt;
        detectEventEditText.getCanvas&lt;span class="o"&gt;()&lt;/span&gt;.getKeyboard&lt;span class="o"&gt;()&lt;/span&gt;.keyEvent&lt;span class="o"&gt;(&lt;/span&gt;0xff, null, text.toString&lt;span class="o"&gt;())&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Actually, you could directly use com.android.internal.inputmethod.EditableInputConnection, but it is an internal final class. The author integrated it into the APP by copying the source code, and used reflection for some functions that cannot be called directly.&lt;/p&gt;

&lt;p&gt;Key events not generated by the input method are sent directly via the RFB protocol by calling the interface in the activity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;@Override
public boolean dispatchKeyEvent&lt;span class="o"&gt;(&lt;/span&gt;KeyEvent event&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;canvas.getKeyboard&lt;span class="o"&gt;()&lt;/span&gt;.keyEvent&lt;span class="o"&gt;(&lt;/span&gt;event.getKeyCode&lt;span class="o"&gt;()&lt;/span&gt;, event&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference is that characters generated by the input method use 0xff as the keycode, and are handled separately in RfbProto.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// Normal key press
public synchronized void writeKeyEvent&lt;span class="o"&gt;(&lt;/span&gt;int keySym, int metaState, boolean down&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;viewOnly&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    eventBufLen &lt;span class="o"&gt;=&lt;/span&gt; 0&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;down&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        writeModifierKeyEvents&lt;span class="o"&gt;(&lt;/span&gt;metaState, down&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;keySym &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 0&lt;span class="o"&gt;)&lt;/span&gt;
        writeKeyEvent&lt;span class="o"&gt;(&lt;/span&gt;keySym, down&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    // Always release all modifiers after an &lt;span class="s2"&gt;"up"&lt;/span&gt; event
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(!&lt;/span&gt;down&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        writeModifierKeyEvents&lt;span class="o"&gt;(&lt;/span&gt;metaState, down&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    try &lt;span class="o"&gt;{&lt;/span&gt;
        os.write&lt;span class="o"&gt;(&lt;/span&gt;eventBuf, 0, eventBufLen&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; catch &lt;span class="o"&gt;(&lt;/span&gt;IOException e&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        Log.e&lt;span class="o"&gt;(&lt;/span&gt;TAG, &lt;span class="s2"&gt;"Failed to write key event to VNC server."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        e.printStackTrace&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;// Input character
public synchronized void writeKeyStringEvent&lt;span class="o"&gt;(&lt;/span&gt;int keycode, char c, boolean down&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;viewOnly &lt;span class="o"&gt;||&lt;/span&gt; os &lt;span class="o"&gt;==&lt;/span&gt; null &lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        int keySym &lt;span class="o"&gt;=&lt;/span&gt; c&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;keySym &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 0xff&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            keySym +&lt;span class="o"&gt;=&lt;/span&gt; 0x1000000&lt;span class="p"&gt;;&lt;/span&gt; //out of keyboard
        &lt;span class="o"&gt;}&lt;/span&gt;
        Log.d&lt;span class="o"&gt;(&lt;/span&gt;TAG, &lt;span class="s2"&gt;"writeKeyStringEvent() called with: keySym = ["&lt;/span&gt; + keySym + &lt;span class="s2"&gt;"], down = ["&lt;/span&gt; + down + &lt;span class="s2"&gt;"]"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        eventBufLen &lt;span class="o"&gt;=&lt;/span&gt; 0&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;keySym &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 0&lt;span class="o"&gt;)&lt;/span&gt;
            writeSpacialKeyEvent&lt;span class="o"&gt;(&lt;/span&gt;keycode, keySym, down&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        try &lt;span class="o"&gt;{&lt;/span&gt;
            os.write&lt;span class="o"&gt;(&lt;/span&gt;eventBuf, 0, eventBufLen&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; catch &lt;span class="o"&gt;(&lt;/span&gt;IOException e&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            Log.e&lt;span class="o"&gt;(&lt;/span&gt;TAG, &lt;span class="s2"&gt;"Failed to write key event to VNC server."&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            e.printStackTrace&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See the code at:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gitee.com/openfde/remote-desktop-clients/blob/fde_w/bVNC/src/main/java/com/iiordanov/bVNC/DetectEventEditText.java" rel="noopener noreferrer"&gt;bVNC/src/main/java/com/iiordanov/bVNC/DetectEventEditText.java · OpenFDE/remote-desktop-clients - Gitee&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gitee.com/openfde/remote-desktop-clients/blob/fde_w/bVNC/src/main/java/com/iiordanov/bVNC/DetectInputConnection.java" rel="noopener noreferrer"&gt;bVNC/src/main/java/com/iiordanov/bVNC/DetectInputConnection.java · OpenFDE/remote-desktop-clients - Gitee&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gitee.com/openfde/remote-desktop-clients/blob/fde_w/bVNC/src/main/java/com/iiordanov/bVNC/RfbProto.java" rel="noopener noreferrer"&gt;bVNC/src/main/java/com/iiordanov/bVNC/RfbProto.java · OpenFDE/remote-desktop-clients - Gitee&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  VNC server
&lt;/h4&gt;

&lt;p&gt;Upon receiving a KeyEvent from the VNC APP, according to the original protocol, the reserved bits are used as a flag to distinguish between input characters and key presses.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gitee.com/openfde/fde_tigervncserver/blob/fde_w/common/rfb/SMsgReader.cxx" rel="noopener noreferrer"&gt;common/rfb/SMsgReader.cxx · OpenFDE/fde_tigervncserver - Gitee&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;void SMsgReader::readKeyEvent&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  // bool down &lt;span class="o"&gt;=&lt;/span&gt; is-&amp;gt;readU8&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  // is-&amp;gt;skip&lt;span class="o"&gt;(&lt;/span&gt;2&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  // rdr::U32 key &lt;span class="o"&gt;=&lt;/span&gt; is-&amp;gt;readU32&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  // handler-&amp;gt;keyEvent&lt;span class="o"&gt;(&lt;/span&gt;key, 0, down&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  bool down &lt;span class="o"&gt;=&lt;/span&gt; is-&amp;gt;readU8&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  rdr::U32 keycode &lt;span class="o"&gt;=&lt;/span&gt; is-&amp;gt;readU16&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
//    is-&amp;gt;skip&lt;span class="o"&gt;(&lt;/span&gt;2&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; Use this reserved bit to distinguish between input characters and key presses 0xff
  rdr::U32 key &lt;span class="o"&gt;=&lt;/span&gt; is-&amp;gt;readU32&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  handler-&amp;gt;keyEvent&lt;span class="o"&gt;(&lt;/span&gt;key, keycode, down&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other modifications on the server side use the quilt patch approach mentioned above; the main changes are all in this patch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gitee.com/openfde/fde_tigervncserver/blob/fde_w/debian/patches/fde_patch_001.diff" rel="noopener noreferrer"&gt;debian/patches/fde_patch_001.diff · OpenFDE/fde_tigervncserver - Gitee&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The key points are as follows. Simply put, a 4-digit unicode is split into 4 key press events. For example, to send "我" (unicode "6211"), it would send "6", "2", "1", "1" as 4 down/up events respectively. If there is a "0", a special keysym needs to be sent; otherwise, the ibus protocol will convert it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/&lt;span class="k"&gt;*&lt;/span&gt;
 &lt;span class="k"&gt;*&lt;/span&gt; vncKeyboardEvent&lt;span class="o"&gt;()&lt;/span&gt; - add X11 events &lt;span class="k"&gt;for &lt;/span&gt;the given RFB key event
 &lt;span class="k"&gt;*&lt;/span&gt;/
void vncKeyboardEvent&lt;span class="o"&gt;(&lt;/span&gt;KeySym keysym, unsigned xtcode, int down&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
    /&lt;span class="k"&gt;*&lt;/span&gt; Simple &lt;span class="k"&gt;case&lt;/span&gt;: the client has specified the key &lt;span class="k"&gt;*&lt;/span&gt;/
    //    xtcode &lt;span class="o"&gt;=&lt;/span&gt; 0xff&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;xtcode &lt;span class="o"&gt;==&lt;/span&gt; 0xff&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        //hardcode keysym &lt;span class="o"&gt;=&lt;/span&gt;  0xcccc , transfer IBUS_KEY_Adiaeresis maybe never used
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;down&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            vncKeysymKeyboardEvent&lt;span class="o"&gt;(&lt;/span&gt;0xcccc, down&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            int fakeSym &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;keysym &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; 12&lt;span class="o"&gt;)&lt;/span&gt; &amp;amp; 0xf&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;fakeSym &lt;span class="o"&gt;==&lt;/span&gt; 0&lt;span class="o"&gt;){&lt;/span&gt;
                fakeSendKeycode&lt;span class="o"&gt;(&lt;/span&gt;0xcccd, down, xtcode&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                fakeSendKeycode&lt;span class="o"&gt;(&lt;/span&gt;0xcccd, 0, xtcode&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
                fakeSendKeycode&lt;span class="o"&gt;(&lt;/span&gt;fakeSym, down, xtcode&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                fakeSendKeycode&lt;span class="o"&gt;(&lt;/span&gt;fakeSym, 0, xtcode&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            fakeSym &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;keysym &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; 8&lt;span class="o"&gt;)&lt;/span&gt; &amp;amp; 0xf&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;fakeSym &lt;span class="o"&gt;==&lt;/span&gt; 0&lt;span class="o"&gt;){&lt;/span&gt;
                fakeSendKeycode&lt;span class="o"&gt;(&lt;/span&gt;0xcccd, down, xtcode&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                fakeSendKeycode&lt;span class="o"&gt;(&lt;/span&gt;0xcccd, 0, xtcode&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
                fakeSendKeycode&lt;span class="o"&gt;(&lt;/span&gt;fakeSym, down, xtcode&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                fakeSendKeycode&lt;span class="o"&gt;(&lt;/span&gt;fakeSym, 0, xtcode&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            fakeSym &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;keysym &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; 4&lt;span class="o"&gt;)&lt;/span&gt; &amp;amp; 0xf&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;fakeSym &lt;span class="o"&gt;==&lt;/span&gt; 0&lt;span class="o"&gt;){&lt;/span&gt;
                fakeSendKeycode&lt;span class="o"&gt;(&lt;/span&gt;0xcccd, down, xtcode&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                fakeSendKeycode&lt;span class="o"&gt;(&lt;/span&gt;0xcccd, 0, xtcode&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
                fakeSendKeycode&lt;span class="o"&gt;(&lt;/span&gt;fakeSym, down, xtcode&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                fakeSendKeycode&lt;span class="o"&gt;(&lt;/span&gt;fakeSym, 0, xtcode&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            fakeSym &lt;span class="o"&gt;=&lt;/span&gt; keysym &amp;amp; 0xf&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;fakeSym &lt;span class="o"&gt;==&lt;/span&gt; 0&lt;span class="o"&gt;){&lt;/span&gt;
                fakeSendKeycode&lt;span class="o"&gt;(&lt;/span&gt;0xcccd, down, xtcode&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                fakeSendKeycode&lt;span class="o"&gt;(&lt;/span&gt;0xcccd, 0, xtcode&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
                fakeSendKeycode&lt;span class="o"&gt;(&lt;/span&gt;fakeSym, down, xtcode&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                fakeSendKeycode&lt;span class="o"&gt;(&lt;/span&gt;fakeSym, 0, xtcode&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            vncKeysymKeyboardEvent&lt;span class="o"&gt;(&lt;/span&gt;0xcccc, down&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
        fakeSendKeycode&lt;span class="o"&gt;(&lt;/span&gt;keysym, down, xtcode&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can be understood as an encoding process. The reason this treatment is necessary is due to the ibus protocol transmission process: it seems that keysym types are only not escaped when they are 1 byte, or some defined in X11's keysymdef.h.&lt;/p&gt;

&lt;h4&gt;
  
  
  Ibus Input Method
&lt;/h4&gt;

&lt;p&gt;Ultimately, text input still uses the input method on Linux. It is started via environment variables and serves no other purpose than to decode the content sent by vncserver and generate characters.&lt;/p&gt;

&lt;p&gt;Simply follow the ibus input method flow and register a key callback:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    g_signal_connect&lt;span class="o"&gt;(&lt;/span&gt;engine, &lt;span class="s2"&gt;"process-key-event"&lt;/span&gt;, G_CALLBACK&lt;span class="o"&gt;(&lt;/span&gt;engine_process_key_event_cb&lt;span class="o"&gt;)&lt;/span&gt;, NULL&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The keyval, keycode, and state sent by vncserver across 4 events are combined to generate a unicode character, which is then committed as text. Normal key presses do not have the flag bit 0xcccc used above, so they effectively bypass this input method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gboolean engine_process_key_event_cb&lt;span class="o"&gt;(&lt;/span&gt;IBusEngine &lt;span class="k"&gt;*&lt;/span&gt;engine,
                                     guint keyval,
                                     guint keycode,
                                     guint state&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    LOG_INFO&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"engine_process_key_event"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    ibus_engine_show_lookup_table&lt;span class="o"&gt;(&lt;/span&gt;engine&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    // ibus_engine_show_preedit_text&lt;span class="o"&gt;(&lt;/span&gt;engine&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    ibus_engine_show_auxiliary_text&lt;span class="o"&gt;(&lt;/span&gt;engine&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    std::thread::id t1_id &lt;span class="o"&gt;=&lt;/span&gt; std::this_thread::get_id&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    // char receiver[100]&lt;span class="p"&gt;;&lt;/span&gt; //
    // sprintf&lt;span class="o"&gt;(&lt;/span&gt;receiver, &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\r&lt;/span&gt;&lt;span class="s2"&gt;    Received data  keycode:%d keyval:%d flag:%d text:%d "&lt;/span&gt;,keycode, keyval, flag, text&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    // engine_commit_text&lt;span class="o"&gt;(&lt;/span&gt;engine, ibus_text_new_from_string&lt;span class="o"&gt;(&lt;/span&gt;receiver&lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    //1.unicode start
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;keyval &lt;span class="o"&gt;==&lt;/span&gt; 0xcccc &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!(&lt;/span&gt;state &amp;amp; IBUS_RELEASE_MASK&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        // sprintf&lt;span class="o"&gt;(&lt;/span&gt;receiver, &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\r&lt;/span&gt;&lt;span class="s2"&gt;   1.unicode start   keycode:%d maks:%d  "&lt;/span&gt;,keycode, state &amp;amp; IBUS_RELEASE_MASK&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        // engine_commit_text&lt;span class="o"&gt;(&lt;/span&gt;engine, ibus_text_new_from_string&lt;span class="o"&gt;(&lt;/span&gt;receiver&lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        flag &lt;span class="o"&gt;=&lt;/span&gt; 3&lt;span class="p"&gt;;&lt;/span&gt;
        text &lt;span class="o"&gt;=&lt;/span&gt; 0&lt;span class="p"&gt;;&lt;/span&gt;
        processing &lt;span class="o"&gt;=&lt;/span&gt; 1&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;TRUE&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    //2.add unicode
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;flag &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!(&lt;/span&gt;state &amp;amp; IBUS_RELEASE_MASK&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        // sprintf&lt;span class="o"&gt;(&lt;/span&gt;receiver, &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;    2.add unicode   flag:%d maks:%d  "&lt;/span&gt;,flag, state &amp;amp; IBUS_RELEASE_MASK&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        // engine_commit_text&lt;span class="o"&gt;(&lt;/span&gt;engine, ibus_text_new_from_string&lt;span class="o"&gt;(&lt;/span&gt;receiver&lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;keyval &lt;span class="o"&gt;==&lt;/span&gt; 0xcccd&lt;span class="o"&gt;){&lt;/span&gt;
            text +&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;0 &amp;lt;&amp;lt; &lt;span class="o"&gt;(&lt;/span&gt;flag &lt;span class="k"&gt;*&lt;/span&gt; 4&lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
            text +&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;keyval &amp;lt;&amp;lt; &lt;span class="o"&gt;(&lt;/span&gt;flag &lt;span class="k"&gt;*&lt;/span&gt; 4&lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        // char input_string[100]&lt;span class="p"&gt;;&lt;/span&gt; //1
        // sprintf&lt;span class="o"&gt;(&lt;/span&gt;input_string, &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\r&lt;/span&gt;&lt;span class="s2"&gt;   Generate character  bit flag:%d keyval:%d text:%d"&lt;/span&gt;,flag, keyval, text&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        // engine_commit_text&lt;span class="o"&gt;(&lt;/span&gt;engine, ibus_text_new_from_string&lt;span class="o"&gt;(&lt;/span&gt;input_string&lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        flag--&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;TRUE&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    //3.unicode over
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;keyval &lt;span class="o"&gt;==&lt;/span&gt; 0xcccc &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;state &amp;amp; IBUS_RELEASE_MASK&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        // sprintf&lt;span class="o"&gt;(&lt;/span&gt;receiver, &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\r&lt;/span&gt;&lt;span class="s2"&gt;    3.unicode over   keycode:%d maks:%d  flag:%d text:%d"&lt;/span&gt;,keycode, state &amp;amp; IBUS_RELEASE_MASK, flag, text&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        // engine_commit_text&lt;span class="o"&gt;(&lt;/span&gt;engine, ibus_text_new_from_string&lt;span class="o"&gt;(&lt;/span&gt;receiver&lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        flag &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        wchar_t unicodeChar &lt;span class="o"&gt;=&lt;/span&gt; static_cast&amp;lt;wchar_t&amp;gt;&lt;span class="o"&gt;(&lt;/span&gt;text&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        std::wstring_convert &amp;lt;std::codecvt_utf8_utf16&amp;lt;wchar_t&amp;gt;&amp;gt; converter&lt;span class="p"&gt;;&lt;/span&gt;
        std::string utf8Str &lt;span class="o"&gt;=&lt;/span&gt; converter.to_bytes&lt;span class="o"&gt;(&lt;/span&gt;unicodeChar&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        // char input_string[100]&lt;span class="p"&gt;;&lt;/span&gt; //
        // sprintf&lt;span class="o"&gt;(&lt;/span&gt;input_string, &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\r&lt;/span&gt;&lt;span class="s2"&gt;     Key press keyval:%d keycode:%d text:%d  final====&amp;gt; "&lt;/span&gt;, keyval, keycode, text&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        // engine_commit_text&lt;span class="o"&gt;(&lt;/span&gt;engine, ibus_text_new_from_string&lt;span class="o"&gt;(&lt;/span&gt;input_string&lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        engine_commit_text&lt;span class="o"&gt;(&lt;/span&gt;engine, ibus_text_new_from_string&lt;span class="o"&gt;(&lt;/span&gt;utf8Str.c_str&lt;span class="o"&gt;()))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        processing &lt;span class="o"&gt;=&lt;/span&gt; 0&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;TRUE&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;processing&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;TRUE&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    text &lt;span class="o"&gt;=&lt;/span&gt; 0&lt;span class="p"&gt;;&lt;/span&gt;
    flag &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    // sprintf&lt;span class="o"&gt;(&lt;/span&gt;receiver, &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\r&lt;/span&gt;&lt;span class="s2"&gt;     4.  maks:%d  "&lt;/span&gt; , state &amp;amp; IBUS_RELEASE_MASK&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    // engine_commit_text&lt;span class="o"&gt;(&lt;/span&gt;engine, ibus_text_new_from_string&lt;span class="o"&gt;(&lt;/span&gt;receiver&lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;state &amp;amp; IBUS_RELEASE_MASK&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;FALSE&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;FALSE&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Clipboard
&lt;/h4&gt;

&lt;p&gt;RFB has two versions of the clipboard protocol, &lt;a href="https://www.babeler.cn/transfer/input/clipboard.html" rel="noopener noreferrer"&gt;Clipboard · RFB Remote Framebuffer Protocol&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The old one does not support Chinese, so the extended clipboard pseudo-protocol needs to be used.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;RFB 3.8 protocol limitation: the clipboard can only transmit the Latin-1 character set. In 2016, Cendio Ossman merged the &lt;a href="https://github.com/rfbproto/rfbproto/commit/08018f655acd52970680b34021159924357efb5d" rel="noopener noreferrer"&gt;Extended Clipboard Pseudo-Encoding&lt;/a&gt; into the main protocol branch, supporting transmission of the unicode character set in clipboard messages. UltraVNC/TigerVNC/RealVNC servers all support this extended protocol, while x11vnc has not yet provided support (2021/8/11).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The extended clipboard pseudo-protocol requires support from both client and server software. The message extends &lt;code&gt;ServerCutText&lt;/code&gt; and &lt;code&gt;ClientCutText&lt;/code&gt;, as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  +--------------+--------------+--------------+
  | No. of bytes | Type &lt;span class="o"&gt;[&lt;/span&gt;Value] | Description  |
  +--------------+--------------+--------------+
  | 1            | U8 &lt;span class="o"&gt;[&lt;/span&gt;3/6]     | message-type |
  | 3            |              | padding      |
  | 4            | S32          | length       |
  | 4            | U32          | text-type    |
  | length-4     | U8 array     | text         |
  +--------------+--------------+--------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The remote-desktop-clients used in this project also does not implement this, &lt;a href="https://github.com/iiordanov/remote-desktop-clients/issues/285" rel="noopener noreferrer"&gt;VNC clipboard for utf8 text · Issue #285 · iiordanov/remote-desktop-clients&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The author implemented text copying through the extended clipboard pseudo-protocol. Since this protocol supports multiple formats, &lt;strong&gt;ZlibOutStream&lt;/strong&gt; was used to convert the copied content. See the following patch for code modifications:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gitee.com/openfde/remote-desktop-clients/commit/dd23ad0d01b409a10e973fdb6ccf19dc94d7f35f" rel="noopener noreferrer"&gt;Login - Gitee.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In fact, it can also implement file copying, but the author did not further implement it. remote-desktop-clients does not even implement Chinese (unicode) copying; the author speculates this is because clipboard usage scenarios on mobile are too rare, whereas OpenFDE has this requirement.&lt;/p&gt;

&lt;p&gt;In summary, most of the principles of the VNC-based Linux application integration solution for the OpenFDE desktop environment are as described above. There are many more details to handle. It has already been released as a mature product, and we are subsequently researching methods to directly use xserver to run Linux programs within the OpenFDE desktop.&lt;/p&gt;

&lt;h3&gt;
  
  
  Future Plans
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1dpu1nhdt08qg7r8zjl2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1dpu1nhdt08qg7r8zjl2.png" alt="principle" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are currently developing a new integration solution: porting xserver to our Android desktop. This way, starting an X Server within OpenFDE to connect to Linux programs allows direct transmission of the program's display content without going through screen image forwarding, greatly simplifying the flow. It offers better performance, compatibility, and user experience. At the same time, we will strive to achieve a window system that is as close as possible to that of Linux programs. Stay tuned.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F84e42un3eqvfjdixow79.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F84e42un3eqvfjdixow79.png" alt="example" width="799" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's all for this technical sharing session. Writing isn't easy, so if you found it helpful, please follow us for more~&lt;/p&gt;

</description>
      <category>linux</category>
      <category>opensource</category>
      <category>android</category>
      <category>ubuntu</category>
    </item>
    <item>
      <title>How to Run Android Apps Natively on Linux?</title>
      <dc:creator>【OpenFDE】ying xu</dc:creator>
      <pubDate>Mon, 27 Jul 2026 09:53:12 +0000</pubDate>
      <link>https://dev.to/ying_xu_0f8a58231902eb42b/technical-analysis-how-to-run-android-apps-natively-on-linux-acm</link>
      <guid>https://dev.to/ying_xu_0f8a58231902eb42b/technical-analysis-how-to-run-android-apps-natively-on-linux-acm</guid>
      <description>&lt;p&gt;It is well known that the Android system runs on the Linux kernel . However, Android's rich and mature software ecosystem stands in stark contrast to that of Linux ; given that they share the same kernel, why can't Android applications run directly on Linux? &lt;/p&gt;

&lt;p&gt;There are currently two main technical solutions for running Android on Linux: &lt;strong&gt;virtual machines&lt;/strong&gt; and &lt;strong&gt;containerization&lt;/strong&gt; . Virtual machines consume significant hardware resources and result in complete isolation—preventing interaction between the two systems—whereas containerization avoids these drawbacks, making it our preferred choice . Specifically, containerization effectively carves out a dedicated space for Android to run within the Linux environment while maintaining a channel for interaction between the two systems .&lt;/p&gt;

&lt;p&gt;Therefore, based on this, we decided to create an open-source desktop, &lt;strong&gt;OpenFDE&lt;/strong&gt;, which allows Android applications to run directly on Linux systems .&lt;/p&gt;

&lt;p&gt;To provide a better understanding of our open-source project, this article outlines OpenFDE's software architecture and display logic .&lt;/p&gt;




&lt;h2&gt;
  
  
  1. OpenFDE Overall Software Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌────────────────────────────────────────────────────────────────────────────────────────┐
│                                   Application Layer                                    │
│   ┌────────────────────────┬────────────────────────┐      ┌────────────┬──────────┐   │
│   │     Android App1       │      Android App2      │      │  X11 APP1  │ X11 APP1 │   │
│   └────────────────────────┴────────────────────────┘      └─────┬──────┴────┬─────┘   │
│                                                                  │           │         │
│                                                            ┌─────▼───────────▼──────┐  │
│                                                            │        XServer         │  │
│                                                            └────────────┬───────────┘  │
├─────────────────────────────────────────────────────────────────────────┼──────────────┤
│                                  API Framework Layer                    │              │
│   ┌────────────────────────┬────────────────────────┐  ┌────────────────▼───────────┐  │
│   │    Activity Manager    │     Window Manager     │  │   X11 Client (libX11, etc) │  │
│   ├────────────────────────┼────────────────────────┤  ├────────────────────────────┤  │
│   │    Content Providers   │      View System       │  │    DIX Driver (wiglamor)   │  │
│   ├────────────────────────┼────────────────────────┤  │            Glamor          │  │
│   │    Resource Manager    │    Location Manager    │  ├────────────────────────────┤  │
│   ├────────────────────────┴────────────────────────┤  │    EGL / GLX / OpenGL/ES   │  │
│   │             Android Runtime (ART)               │  ├────────────────────────────┤  │
│   └─────────────────────────────────────────────────┘  │   User-space Drivers       │  │
├────────────────────────────────────────────────────────┤   (libGL-Mesa-DRI, Mesa3D) │  │
│                                     Native Libs        │  ├────────────────────────────┤  │
│   ┌────────────────────────┬────────────────────────┐  │      LibDRM / GNU LibC     │  │
│   │          SSL           │        Graphics        │  └────────────────────────────┘  │
│   ├────────────────────────┴────────────────────────┤             ▲                    │
│   │   AOSP LibC with Modified Dynamic Libs Loader   │─────────────┘                    │
├─────────────────────────────────────────────────────┴──────────────────────────────────┤
│                           LXC Isolation and Fusion Layer                               │
│   ┌──────────────────┬──────────────────┬──────────────────┬──────────────────────┐    │
│   │ Filesystem Fusion│  Network Fusion  │  IPC Fusion &amp;amp;    │   Clipboard Fusion   │    │
│   │                  │                  │   Acceleration   │                      │    │
│   └──────────────────┴──────────────────┴──────────────────┴──────────────────────┘    │
├────────────────────────────────────────────────────────────────────────────────────────┤
│                           Standard Desktop Device Drivers                              │
├────────────────────────────────────────────────────────────────────────────────────────┤
│                                 Standard Linux Kernel                                  │
└────────────────────────────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The image above illustrates our current overall technical architecture . From the bottom up, the architecture comprises :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Standard Linux Kernel&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LXC Isolation and Integration Layer&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Framework Layer&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application Layer&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linux Desktop Graphics Stack&lt;/strong&gt; &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let us examine each of these components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Application Layer&lt;/strong&gt;: The FDE application layer primarily encompasses Android applications and Linux X11 applications . While Android applications run natively, Linux X11 applications operate within the Linux system; we integrate their display into the Android environment using a VNC client running within FDE, while simultaneously forwarding input events (such as keyboard/mouse signals and IME inputs) . We are currently developing an Android-based X Server to replace the Linux-based VNC X Server, aiming to achieve superior display performance and enhanced compatibility .&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;API Framework Layer&lt;/strong&gt;: It provides a set of standard API interfaces that enable applications to communicate and interact with the underlying system; these APIs cover functions such as accessing device drivers, managing file systems, and handling network communications . OpenFDE directly inherits the Android API design framework, ensuring that both adhere to a unified set of APIs for peripherals and power management . This significantly alleviates issues associated with the coexistence of different API generations, as well as the haphazard and chaotic nature of modifications during the usage and development of graphical interfaces .&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;LXC Isolation and Integration Layer&lt;/strong&gt;: The LXC isolation layer isolates the Linux and Android file systems and API layers while sharing the underlying Linux kernel . The integration layer leverages standard desktop protocols (such as Wayland) and the Linux desktop graphics stack to provide key functions like graphical display, input device management, and window management . Additionally, we are working to package the Linux desktop graphics stack's OpenGL/ES components into dynamic libraries that can be called directly by Android, thereby ensuring compatibility with a wider range of hardware .&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Display Integration Logic
&lt;/h2&gt;

&lt;p&gt;Having covered the overall software architecture of OpenFDE, let us now discuss how the display component is integrated—a particularly challenging aspect of the entire integration solution .&lt;/p&gt;

&lt;h3&gt;
  
  
  Standard Linux DRI Display Framework
&lt;/h3&gt;

&lt;p&gt;The logic of the DRI display framework on Linux (currently the most efficient display framework) is that the client directly invokes the GPU for rendering; once rendering is complete, the output is submitted to the compositor, which then performs composition and submits the result for display .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────┐    1. Render Request     ┌──────────────────┐
│ Client/App       ├─────────────────────────&amp;gt;│ GPU              │
└────────┬─────────┘                          └────────┬─────────┘
         │                                             │
         │ 2. Send Composition Request                 │ 3. Fetch Render Result
         ▼                                             ▼    for Composition
┌──────────────────┐                          ┌──────────────────┐
│ Compositor       ├─────────────────────────&amp;gt;│ DPU              │
└──────────────────┘    4. Send Composition   └──────────────────┘
                             Result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Native Android Display Logic
&lt;/h3&gt;

&lt;p&gt;Android's display logic involves the application requesting buffers from SurfaceFlinger; SurfaceFlinger invokes Gralloc to fulfill the request and synchronizes the result for the application's use . The rendering process is executed directly by the application using the GPU, and the final output is handed over to SurfaceFlinger, which invokes HWC (Hardware Composer) to perform composition .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                 ┌──────────────────────────┐
                 │ Application (Self-Render)│&amp;lt;──────────┐
                 └─────┬──────────────┬─────┘           │
                       │              │                 │
  Submit Rendering     │              │ Apply Buffer    │ Return
  Results              │              │                 │
                       ▼              ▼                 │
┌─────────────┐   ┌─────────────────────────┐     ┌─────┴──────────┐
│ Display     │&amp;lt;──┤     surfaceflinger      ├────&amp;gt;│    gralloc     │
└──────▲──────┘   └───────────┬─────────────┘     └────────────────┘
       │                      │ Call
       │                      ▼
       │          ┌─────────────────────────┐
       └──────────┤  hwcomposer (Composition│
                  └─────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  OpenFDE Merged Display Architecture
&lt;/h3&gt;

&lt;p&gt;Running Android on Linux allows these two workflows to be merged :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The initial stages follow the standard Android process .&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hwcomposer&lt;/code&gt; is modified to act as a Wayland client (thereby losing hardware composition capabilities) .&lt;/li&gt;
&lt;li&gt;When &lt;code&gt;SurfaceFlinger&lt;/code&gt; requests composition from &lt;code&gt;hwcomposer&lt;/code&gt;, the latter returns data indicating that the GPU should handle the entire composition task .&lt;/li&gt;
&lt;li&gt;Consequently, &lt;code&gt;SurfaceFlinger&lt;/code&gt; invokes the GPU to perform the composition and sends the result to &lt;code&gt;hwcomposer&lt;/code&gt; for submission .&lt;/li&gt;
&lt;li&gt;Finally, &lt;code&gt;hwcomposer&lt;/code&gt; transmits the buffer via the Wayland protocol to the Linux compositor (&lt;code&gt;mutter&lt;/code&gt;), which then sends it to the Linux DPU for display .
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;               ┌──────────────────────────┐
               │    App (Self-rendering)  │&amp;lt;──────────┐
               └─────┬──────────────┬─────┘           │
                     │              │                 │
Submit Rendering     │              │ Request Buffer  │ Allocate
Results              │              │                 │
                     ▼              ▼                 │
┌─────────────┐ Ask  ┌──────────────┴──────┐     ┌─────┴──────────┐
│ hwcomposer  │&amp;lt;────┤    surfaceflinger    ├────&amp;gt;│    gralloc     │
│ (wayland    │     └──────────────▲───────┘     └────────────────┘
│   client)   ├────────────────────┘
└──────┬──────┘ Respond: ALL DONE BY GPU
       │
       │ Transmit Buffer via Wayland
       ▼
┌─────────────┐
│   mutter    │
│(Composition)│
└──────┬──────┘
       │
       ▼
┌─────────────┐
│   Display   │
└─────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, this approach entails some performance overhead, but it effectively achieves our objective .&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Summary &amp;amp; What's Next
&lt;/h2&gt;

&lt;p&gt;These are the two core components of how FDE currently operates . Beyond this, we have also worked on integrating Linux applications into Android, upgrading the UI, fine-tuning interactions, and more . &lt;/p&gt;

&lt;p&gt;In the next installment, we'll dive into the technical principles behind FDE's Linux application integration .&lt;br&gt;
"""&lt;/p&gt;

</description>
      <category>android</category>
      <category>linux</category>
      <category>software</category>
    </item>
  </channel>
</rss>
