Sunday, May 15, 2016

How to fix a USB audio device that interferes with mouse clicks in Linux

(This post includes an overview of how to solve similar problems to the one I encountered.  If you're looking for just the solution?  Skip to "The solution" below.)

I recently got a Jabra USB headset.  It's a very nice headset with active noise cancelling, a decent microphone, and a USB audio controller that includes a few buttons to control the audio volume.  These buttons work directly with the OS by presenting as a USB keyboard and sending the same keystrokes that the volume up/down buttons on a real keyboard would.

Unfortunately, it also presents itself as a USB mouse with 12 buttons and takes precedence over any actual pointing devices attached to the system.  Why a USB audio device needs to present itself to the system as a mouse is beyond me.  (The only theory I've heard that makes any sense at all is that there's some Windows-specific driver that would intercept mouse events and do some sort of deeper OS integration.)  Whatever the reason, it's a terrible "feature" and an abuse of the USB HID specification.

But rant over. Fortunately because X (the graphics engine of desktop Linux systems) allows the user fine control over the system, this is pretty easy to fix.  I'm including the steps I used to troubleshoot and fix this so that if anyone runs into similar issues in the future they know what to do.

Narrowing the issue down to X

As soon as I started using this headset I noticed something strange: I couldn't click the mouse anywhere outside of the window that I had on top when I plugged it in.  This persisted until I unplugged the USB cable, when suddenly mouse clicks worked again.  When I plugged the USB cable back in, mouse clicks stopped working again.  Weird, but at least consistent!

Knowing that it had something to do with the USB device I started looking at a few system logs.  I ran 'dmesg', which shows the device driver logs for the system, but didn't seem anything unusual.  So it wasn't a Linux issue, which meant it had to be in X.

Diagnosing in X

The first thing I did was to see what X saw when I had the device plugged in.  I ran 'xinput', which shows a list of all of the input devices attached to the system.  Before plugging in the device I saw:

⎡ Virtual core pointer                     id=2 [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer               id=4 [slave  pointer  (2)]
⎜   ↳ ELAN Touchscreen                         id=10 [slave  pointer  (2)]
⎜   ↳ DLL0665:01 06CB:76AD Touchpad           id=12 [slave  pointer  (2)]
⎣ Virtual core keyboard                   id=3 [master keyboard (2)]
    ↳ Virtual core XTEST keyboard             id=5 [slave  keyboard (3)]
    ↳ Power Button                             id=6 [slave  keyboard (3)]
    ↳ Video Bus                               id=7 [slave  keyboard (3)]
    ↳ Power Button                             id=8 [slave  keyboard (3)]
    ↳ Sleep Button                             id=9 [slave  keyboard (3)]
    ↳ Integrated_Webcam_HD                     id=11 [slave  keyboard (3)]
    ↳ AT Translated Set 2 keyboard             id=13 [slave  keyboard (3)]
    ↳ Dell WMI hotkeys                         id=14 [slave  keyboard (3)]

and afterwards I saw:

⎡ Virtual core pointer                     id=2 [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer               id=4 [slave  pointer  (2)]
⎜   ↳ ELAN Touchscreen                         id=10 [slave  pointer  (2)]
⎜   ↳ DLL0665:01 06CB:76AD Touchpad           id=12 [slave  pointer  (2)]
⎜   ↳ GN Netcom A/S Jabra EVOLVE LINK MS       id=15 [slave  pointer  (2)]
⎣ Virtual core keyboard                   id=3 [master keyboard (2)]
    ↳ Virtual core XTEST keyboard             id=5 [slave  keyboard (3)]
    ↳ Power Button                             id=6 [slave  keyboard (3)]
    ↳ Video Bus                               id=7 [slave  keyboard (3)]
    ↳ Power Button                             id=8 [slave  keyboard (3)]
    ↳ Sleep Button                             id=9 [slave  keyboard (3)]
    ↳ Integrated_Webcam_HD                     id=11 [slave  keyboard (3)]
    ↳ AT Translated Set 2 keyboard             id=13 [slave  keyboard (3)]
    ↳ Dell WMI hotkeys                         id=14 [slave  keyboard (3)]

The highlighted line shows the change: this was the device I had plugged in.  (It appears that GN Netcom A/S is the actual manufacturer and Jabra the brand.)

This told me I was on the right track: the USB headset was showing up as an input device.  This could be why it was interfering with the mouse!  But I needed more information.  Fortunately, xinput has a more verbose mode, 'xinput list --long':

⎜   ↳ GN Netcom A/S Jabra EVOLVE LINK MS       id=15 [slave  pointer  (2)]
Reporting 16 classes:
Class originated from: 15. Type: XIButtonClass
Buttons supported: 12
Button labels: "Button 0" "Button 1" "Button 2" "Button Wheel Up" "Button Wheel Down" "Button Horiz Wheel Left" "Button Horiz Wheel Right" "Button 3" "Button 4" "Button 5" "Button 6" "Button 7"
Button state:
Class originated from: 15. Type: XIKeyClass
Keycodes supported: 248
Class originated from: 15. Type: XIValuatorClass
Detail for Valuator 0:
 Label: Abs X
 Range: 0.000000 - 1000.000000
 Resolution: 0 units/m
 Mode: absolute
 Current value: 1600.000000

(I've trimmed this down quite a bit; 'xinput list --long' really is long.)

From this I saw that it was reporting itself as a mouse device.  (Why does a USB headset need to pretend to the OS to be a mouse?  I still don't know.)  Something in that list of mouse buttons was messing with my actual mouse.  So I needed to disable that functionality while leaving the rest unchanged.

Fine-grained device control in X

The X device control system allows you to make a lot of tweaks to how devices work.  You can change how a keyboard or mouse work, how quickly the pointer moves when you move the mouse, how it accelerates based on the direction you are moving... all sorts of things.  But for my purposes I needed to use the functionality to change the order of mouse buttons.  This is normally for doing things like making a mouse more comfortable for left-handed users (e.g. changing the button order on the mouse from "1 2 3" to "3 2 1" so the left-hand index finger is the primary button).  But you can also map physical buttons to "button 0", which means disabled.  So I just disabled all 12 (why 12‽) mouse buttons.

I did this with the help of the X device control manual here:

The device control system looks in a special location for files that contain instructions  to change how devices work.  On Ubuntu this location is /usr/share/X11/xorg.conf.d/ but may be different on other Linux distributions.

The solultion

I created /usr/share/X11/xorg.conf.d/50-jabra.conf with the following contents:

Section "InputClass"
Identifier "Jabra"
        MatchProduct "GN Netcom A/S Jabra EVOLVE LINK MS"
Option "ButtonMapping" "0 0 0 0 0 0 0 0 0 0 0 0"

I then restarted the X system to make sure the changes would take effect.  (A reboot is the simplest way to do this if you're unsure how.)

Once that was finished I could plug and unplug my USB headset with no issues!


I submitted a bug report to the Ubuntu bug tracking system with my fix attached.  Hopefully it will be picked up and added to the distribution.  In the meantime I'll leave this post up in case anyone else has similar issues.

Saturday, May 7, 2016

Communicating internationally and being understood

English is the language of international business.  It's used as the default language of international conferences, technical papers, and contracts.  I've lost count of the number of conversations I've overheard where, say, a German and French speaker are communicating with each other in English rather than trying to use either of their native languages.

But unfortunately there's a group of people that often makes communication more difficult than it needs to be: native English speakers!  Too often a native speaker will forget that other people are working much harder than they are in a conversation and will slip into bad habits that make it even harder.

I've noticed some simple things that native speakers can do to fix this.  In my experience, these have a dramatic impact on how easily others are able to understand spoken English.  Think of these as a way to help your listener.  You're not meeting them halfway (as they are speaking your language, after all!) but at least you're removing some roadblocks in their path.

Keys to being more easily understood

  • Speak slowly.
  • Face your listener.
  • Keep your mouth clear.
  • Don't laugh while speaking.
  • Keep your sentences clear and direct.

Speak slowly

This should almost go without saying, but is easily forgotten, especially if you are speaking with someone who speaks English nearly fluently.

Consciously make an effort to slow your speech down a bit more than normal.  Not so slowly that others will think you're making fun of them, but enough to ensure that you are not running words together or moving so fast that your listener can't keep up.  I usually mentally aim to speak at about 85-90% of my normal pace -- enough to remind me to take my time and not rush.

Face your listener

This too is common sense.  Partially this is to help you be heard clearly.  But more importantly, keeping your focus on your listener will help you see if they are getting lost or confused.  It's better to slow down and get everyone on the same page as soon as there's an issue rather than realizing that you haven't been understood for several minutes.

If you your listener starts to look confused or anxious, it might be a good idea to check in with them to make sure there aren't any communications issues.  It can be embarrassing to stop someone who is obviously on a roll to say "Slow down!" or "I'm having trouble understanding you."  Take responsibility for being understood yourself -- it really goes a long way.

Keep your mouth clear

We all know that it's rude to talk with your mouth full.  It also makes it harder to make out what you are saying, so don't do it.

But there's more to this.  Try not to cover your mouth when speaking.  You might have a habit of hiding your smile behind your hand or stroking your chin thoughtfully when speaking.  Be aware of these and make sure you avoid them!  Not only do they muffle your voice, but they hide your lips.  Visual information (in the form of mouth movement and shape) is extremely important in understanding speech.

Don't laugh while speaking

This goes along with the previous point, but is so easy to forget that I wanted to call it out specifically.  If you are laughing, stop speaking while doing so.  It's fine to laugh (or cough, or clear your throat, etc.) but don't mix it with speech.  If you need to wait a few extra seconds to keep going, that's fine -- much better to take a breath than to make your listener try to decipher something like "and then ha-heh-the-heh bar-heh-ten-ha-ha-der says 'why-he-he the-ha lo-ha-ong-heh fay-hay-hay-ce?'".

Keep your sentences clear and direct

I put this one last because I think it's the hardest technique in the list, so starting with the others will get you more effect for less effort.  But that doesn't mean it's not important!

What I mean is to try to use a consistent structure in your sentences.  Aim for the typical subject-verb-object word order.  Don't use too many dependent clauses.  Avoid dangling modifiers.  Basically, all the stuff you learned in grade school English classes and then promptly forgot.

Avoid run-on sentences and "filler" words.  Listen to your own speech.  Do you find yourself saying "ummmmmm" when looking for the right word?  Or things like "and then I saw the man and then he walked over to me and then we shook hands and then we started to talk and then..."?  This nonstop wall of sound is really cognitively taxing -- you're loading up a lot of extra work on your listener, forcing them to determine which words they need to mentally filter out and which words they actively need to translate.

So take pauses!  Breathe between sentences and let them sink in a bit.  If you need to think of a word, just think rather than filling the space.  You'll be much easier and more pleasant to listen to.

Be a better speaker

This advice applies to when speaking to native listeners too, by the way.  Listen to some TED talks or other really good speakers.  You'll note that they take pauses, speak at a moderate pace with clear syntax and diction, and don't "ummmm" or "uhhhh".  Learning and internalizing these techniques will make you easier to understand and a more compelling speaker.

(Of course, you could always try the opposite but I wouldn't recommend it.)