Using Mi TV (numeric) remote receiver in MiBox

Many users of the IPTV services may complain about the remote receivers of the modern TV boxes – Xiaomi, Amazon or Google adds only the basic remote control with the D-Pad, nothing else. What in the case, if you would like to use another remote controller – the traditional one with the numeric keys? In this case you might be forced to use the remote USB or Bluetooth keyboards which looks like an IR receiver (like G20BTS), but there is one problem – turning the box on. If your TV is not the best one in the HDMI CEC communication, then you are stuck.

I have a MiBox 4K and my idea was to use the Mi TV (XMRM-19) remote controller as I thought it would work natively. You know: Xiaomi devices should work great with each other. Not in this case. In my case only the buttons: Power, D-Pad, Google Assistant, Back, Home and Volume+/- work natively – even Netflix or Amazon Prime Video not.

The workaround I found is to use great Android tool – Tasker – to replace the XMRM-19’s actions by proper tasks. I had been inspired by that Reddit post, however it is not completely valid.

This post is not for the describing how to use the Tasker (there are many tutorials for that). It is just for bringing an overview how to deal with the remote controller. It would contain two parts: the general logic and the exported XML file to use.

However, the Tasker need some tuning:

  • you cannot install Tasker from Google Play Store for this device. The APK available on the website is just a 7-day demo. Be fair, buy Tasker for your phone (it’s worth every single penny), but look for modded (pirated) version in Internet to use on the MiBox.
  • give some system permissions in the Android settings:
    accesibility, write secure (system) settings, display over other apps
  • give some more permissions using ADB:
    adb shell pm grant net.dinglisch.android.taskerm android.permission.WRITE_SECURE_SETTINGS
    adb shell pm grant net.dinglisch.android.taskerm android.permission.READ_LOGS
    adb shell am force-stop net.dinglisch.android.taskerm

Do not worry – the root user is not needed.

Logic

Tasker was not designed for Android TV. It is great to install Bluetooth Keyboard & Mouse application on your smartphone before – it simulates the physical keyboard and mouse behavior, so you will be able to click on the floating buttons. Connect via Bluetooth to your MiBox device.

Be careful when doing any action – sometimes if you are stuck you need to restart the application, also the „hamburger” (three dot) menu is not available.

At first, create a new profile in Tasker. Collect the event – and select the logcat entry in the event category. Click on the floating button to start collecting the logs, then push the button on the remote and stop collecting the logs. You will see the entries collected at that time. Some of them would be like:
WindowManager ... android.tvlauncher action=0, flags=8, keycode=0, scanCode=2, ...

The crucial thing here is the scanCode. That is the value of the button pressed, which is recognized by MiBox and parsed to the Android TV launcher, which MiBox does not have (it is installed on the Mi TV devices).

I collected the most important scan codes in my remote – here is the list:

So, the Tasker profile for the key „Info” is scanCode=358, – please mark the comma at the end – otherwise it could interfer with scanCode 3 and 392.

Then it’s a time to create a task (action). The task should be a „Keyboard” type. You can use that type in this case in two ways: by providing just the value of the key (Tab, Enter, 1, 2, 3 etc.) or – if in 'apostrophes’ – the Android API keycode – for example, the Channel Down (403 in our remote controller) should call the action KEYCODE_CHANNEL_DOWN, which has a number '167′.

I have tried different solutions (such as self-connecting via ADB to run the commands) but these methods are slow. Using getevent/sendevent methods could be faster, but the „Keyboard” type is the easiest one to use.

Creating an XML file

Doing such actions using Tasker UI sometimes could be impossible – for example, I was stuck when I wanted to confirm the action by going back from „Keyboard” task to main Tasker screen. It is also monotonous.

The workaround I done here is – I installed the X-Plore application on MiBox, run the WiFi file share server option, connect via my PC web browser to that server and send the XML file. The XML file is imported as a project on the Tasker application.

The basic structure of the XML file is described in this link. However, I will describe it in detail from the other side.
By the way: sorry, but our WordPress has some problems with interpreting the tab indents.

<TaskerData sr="" dvi="1" tv="5.14.7"><Project sr="proj0" ve="2"><name>Pilot</name>
<pids>10,1,2</pids>
<scenes>Popup</scenes>
<tids>10,1,2</tids>
</Project>

The <pids> stands for the profile IDs (<id>), the <scenes> for scene’s names, the <tids> for task IDs. Every time you add something, you must provide an ID there. I marked such fields as bolded ones.

<!-- key 0 -->
<Profile sr="prof10" ve="2"><flags>8</flags>
<id>10</id>
<mid0>10</mid0>
<nme>p_k0</nme><Event sr="con0" ve="2">
<code>2085</code><pri>0</pri>
<Bundle sr="arg0">
<Vals sr="val">
<net.dinglisch.android.tasker.RELEVANT_VARIABLES>&lt;StringArray sr=""&gt;&lt;_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES0&gt;%lc_textTextThe text that corresponds to the matched logcat entry&lt;/_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES0&gt;&lt;/StringArray&gt
</net.dinglisch.android.tasker.RELEVANT_VARIABLES>               <net.dinglisch.android.tasker.RELEVANT_VARIABLES-type>[Ljava.lang.String;</net.dinglisch.android.tasker.RELEVANT_VARIABLES-type>
</Vals>
</Bundle>
<Str sr="arg1" ve="3">WindowManager</Str><Str sr="arg2" ve="3">scanCode=11,</Str><Int sr="arg3" val="0"/>
</Event>
</Profile>
<Task sr="task10">
<id>10</id>
<nme>t_k0</nme
<pri>1</pri>
<Action sr="act0" ve="7">
<code>328</code>
<Bundle sr="arg0">
<Vals sr="val">
<net.dinglisch.android.tasker.RELEVANT_VARIABLES>&lt;StringArray sr=""&gt;&lt;_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES0&gt;%kb_text_selectedSelected TextText selected on the current input, if any&lt;/_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES0&gt;&lt;_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES1&gt;%kb_textTextText present on the current input, if any&lt;/_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES1&gt;&lt;_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES2&gt;%kb_text_after_cursorText After CursorText after the cursor on the current input, if any&lt;/_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES2&gt;&lt;_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES3&gt;%kb_text_before_cursorText Before CursorText before the cursor on the current input, if any&lt;/_array_net.dinglisch.android.tasker.RELEVANT_VARIABLES3&gt;&lt;/StringArray&gt;</net.dinglisch.android.tasker.RELEVANT_VARIABLES>               
<net.dinglisch.android.tasker.RELEVANT_VARIABLES-type>[Ljava.lang.String;</net.dinglisch.android.tasker.RELEVANT_VARIABLES-type>
</Vals>
</Bundle>
<Str sr="arg1" ve="3">0</Str
<Int sr="arg2" val="10"/>
<Int sr="arg3" val="0"/>
</Action>
<Action sr="act1" ve="7">
<code>550</code>
<on>false</on>
<Str sr="arg0" ve="3"/>
<Str sr="arg1" ve="3">debug</Str>
<Str sr="arg2" ve="3"/>
<Str sr="arg3" ve="3">Popup</Str>
<Int sr="arg4" val="1"/>
<Int sr="arg5" val="1"/>
</Action>
</Task>

That is an example for a key labeled „0”. Every profile and task must have different names and IDs. In this case I have named all of them mostly by the ID from the remote controller, except zero, as I was not sure if I am able to use ID of 0 (possibility of being out of scope), so it is ten.

In the <profile> the <id> stands for profile’s ID (used by <pids> described above), the <mid0> for the task ID to be used (assigned) in that project, the <nme> for a displayed name.

The subsection <event> contains information about the profile’s event. In our case it is action of type 2085, which stands for Logcat’s entry. The event 2085 contains a <str sr=”arg2″> which is a detail required by us from the Logcat. In that case, the scanCode=11, stands for the signal from the remote controller.

The <profile> is followed by <task>. The task has also its name (<nme>) and ID (directly in the <id> – this name is used in the <mid0> and <tids> described above) but has also the <pri> – priority. Every task contains a set of <action> – also described by the internal type (<code>). If the action is disabled, then the <on> is set to false.

In our case there are two actions: the first one, of type 328 is a keyboard action, which passes the keyboard input described in the <str sr=arg1″ ve=”3″>0</str> – the „0” stands just for „0” char (please remember about the names in the apostrophes which I described before). The <int sr=”arg2″ val=”10″ /> stands for the time between inputs – we set it up as a 10 ms.

Second action is just a simple popup for debugging purposes and it’s disabled.

The file ends with the </TaskerData> statement.

To collect such information (like action IDs), it is recommended to create a project skeleton on the device, then export the XML from Tasker and modify it on the computer.

Summary

I had an opinion that this remote should work out-of-the-box and I am disappointed. However, impossible is nothing and I implemented a solution that looks like a great workaround.

As I saw, there are still two errors to be solved:

  1. The IPTV application cannot receive three digits – the third digit is kept on the buffer and used in the next occurrence of a channel selection.
  2. Sometimes it does not work out of the box – I must wait some time (one minute?) after turning on the MiBox to use all the keys on remote receiver.

I would like to share a valid XML project file as soon as I solve the first problem. I was trying to make a workaround by making a popup (opened by pressing a TTX key) which is a key-channel input, however it does not work properly – it receives a full input for three digits, but the keyboard action task has some unrecognized problems to forward this input to the IPTV application.

I hope this description would help you in such cases and I am open for any suggestions of improvements.