Ubuntu command line to change input source on a display monitor?

The command you are looking for is ddccontrol, available from the regular Ubuntu repository.

WARNING! ddccontrol sends data over the i2c bus, which is inherently a dangerous thing to do. Most i2c devices are very low-level and very dumb, one misplaced command can be enough to brick them or at least freeze the computer. That said, DDC/CI is a somewhat standardized, quite established and quite old technology, so the risks is not too high.

For this reason, by default, i2c devices are only accessible to root. You will most likely need to prefix all commands below with sudo. (I have voluntarily not done it to ensure you read the instructions and not blindly copy/paste them.)

Probing your monitor

The first thing to do is to probe the various i2c buses in your computer (mine has 11 such buses...), searching for the one that is actually on the graphics card, connected to the screen.

The ddccontrol -p command does that, and shows what it found. Sample output from my computer:

Detected monitors :
 - Device: dev:/dev/i2c-4
   DDC/CI supported: Yes
   Monitor Name: VESA standard monitor
   Input type: Digital
  (Automatically selected)
Reading EDID and initializing DDC/CI at bus dev:/dev/i2c-4...
I/O warning : failed to load external entity "/usr/share/ddccontrol-db/monitor/DELD070.xml"
Document not parsed successfully.

EDID readings:
        Plug and Play ID: DELD070 [VESA standard monitor]
        Input type: Digital

Note the I/O warning: it merely means that your monitor is unknown to ddccontrol, so it does not know the description of all the non-standard commands and values it may support. This does not prevent you from issuing the commands, but this may be a trials and errors process.

Note also the detected bus name: dev:/dev/i2c-4 in my example.

Listing all commands

The ddccontrol -d dev:/dev/i2c-4 command reads all the possible controls (from 0x00 to 0xff) and shows the values it found. Of course, you should use the bus found when probing.

ddccontrol also shows a description for the controls and values that are known to it; either standard ones, or ones described in XML files. In my example, there is no XML file for my monitor (see the I/O warning above).

Querying a value

The ddccontrol -r 0x10 dev:/dev/i2c-4 queries the current value of the 0x10 control. Example output:

Reading 0x10...
Control 0x10: +/21/100 C [Brightness]

The current value is the number in the middle, 21 in my example. The value after that is supposed to be the maximum, but this seem to only work for ranged values (such as brightness and contrast), not so much for list items.

Setting a value

The ddccontrol -r 0x10 -w 25 dev:/dev/i2c-4 sets the value of the 0x10 control. Example output:

Writing 0x10, 0x19(25)...
Control 0x10: +/25/100 C [Brightness]

Note that you can set values in hexadecimal or decimal formats. In my example, I used decimal.

Changing monitor input source

I found the command and values to use to switch my monitor inputs. It works well, by you will of course need to experiment to find the values for your monitor. Mine is a Dell UltraSharp U2515H.

Control 0x60 [Input Source Select]

  • Value 15: DP
  • Value 16: mDP
  • Value 17: HDMI (MHL) 1
  • Value 18: HDMI (MHL) 2

The values are in the same order as the Input Source menu in the monitor.

For example, switching to DP: ddccontrol -r 0x60 -w 15 dev:/dev/i2c-4


In addition to Adrien Beau answer.

Changing monitor input source

Standard change input source command is 0x60. So you want to use such command:

ddccontrol -r 0x60 -w $some_value dev:/dev/i2c-X

Determining values to pass to monitor

But how do you know which values are responsible for which input source? I do not know if vendors provide such information, but I have found a way how you can know it without asking vendor.

Just read current value of 0x60 command (using sudo ddccontrol -r 0x60 dev:/dev/i2c-X). It will return something like this:

Case when your monitor is in ddccontrol database

EDID readings:
        Plug and Play ID: DELA0D7 [DELL P2217H (VGA)]
        Input type: Analog

Reading 0x60...
Control 0x60: +/257/4626 C [Input Source Select]

Case when your monitor is not in ddccontrol database

EDID readings:
        Plug and Play ID: DELA0D9 [VESA standard monitor]
        Input type: Digital
=============================== WARNING ===============================
There is no support for your monitor in the database, but ddccontrol is
using a basic generic profile. Many controls will not be supported, and
some controls may not work as expected.
Please update ddccontrol-db, or, if you are already using the latest
version, please send the output of the following command to
[email protected]:

LANG= LC_ALL= ddccontrol -p -c -d

Thank you.
=============================== WARNING ===============================

Reading 0x60...
Control 0x60: +/4369/4626 C [Input Source Select]

Let's assume your monitor is not in ddccontrol database. Note this 4369 value. This is a value that you will use to switch monitor back to current state via cable you are currently speak to monitor. Note, that this value will be different when you use another transport cable (I mean port which you use to speak to monitor, for example via vga and via hdmi values will be different even for same input source).

Now, disable auto selecting input source using monitor's osd menu, because we do not want it for now. Now switch input source using your monitor's osd menu, and then read current value. For this example, I switched monitor to use vga source (source is coming from another computer), while still speaking to monitor via hdmi using first computer, and returned value is 4353. Do the same for all inputs which you are planning to use for switching.

Ok, so now you know values of monitor in different source states. Now you can switch input source for monitor using:

sudo ddccontrol -r 0x60 -w 4353 dev:/dev/i2c-X # switch to vga input using hdmi cable on Dell P2217H
sudo ddccontrol -r 0x60 -w 4369 dev:/dev/i2c-X # switch to hdmi input using hdmi cable on Dell P2217H

Values are presented in decimal, however you can use hexadecimal values like this:

sudo ddccontrol -r 0x60 -w 0x1101 dev:/dev/i2c-X # 0x1101 is 4353
sudo ddccontrol -r 0x60 -w 0x1111 dev:/dev/i2c-X # 0x1111 is 4369

Adding your monitor to ddccontrol database

Now you want your monitor to be in ddccontrol-db. You need to explore values for all functions of your monitor and which values are applied to which state. Then you should create xml file describing all these values. Note, there will be several xml files, due to different ports use different monitor Plug and Play id. For example, for my DELL P2217H monitor I will create two files: DELA0D7.xml (this id is used when connecting via vga) and DELA0D9.xml (this id is used when connecting via hdmi). Dell P2217H has one vga, one hdmi and one displayport. Because I have not got displayport devices, I cannot make explorations to create DELA0D8.xml (this id is used when connecting via displayport).

Some description of xml parameters could be found at Monitor Database Structure page (file:///usr/share/doc/ddccontrol/html/apes02.html).
Capabilities (caps) and Plug and Play ID could be recieved using
sudo ddccontrol -c dev:/dev/i2c-X.
When you are ready, contribute to https://github.com/ddccontrol/ddccontrol-db repository.

Detect monitor by serial number

Let's assume you have connected several monitors of the same model to a single computer. Then you need to differentiate monitors somehow. For this purpose, I have created a script, which determines i2c bus number by monitor serial number. I do it using
sudo get-edid -b $X 2>/dev/null | grep $TARGET_SERIAL
See my repository for more details: https://github.com/Ashark/Ashark-bin/blob/master/i2c-bus-by-monitor-serial

Final script for keyboard binding

Now, see this script: https://github.com/Ashark/Ashark-bin/blob/master/switch-monitor-source You can use it as following:

switch-monitor-source -s 0G2TG7360DXB -u # get and cache i2c-id number for monitor with specified s/n
switch-monitor-source -s 0G2TG7360DXB -v # switch that monitor to vga input
switch-monitor-source -s 0G2TG7360DXB -h # switch that monitor to hdmi input

Now you can bind two last commands to keyboard shortcut and use them for fast switching. Amazing!