LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Slackware (https://www.linuxquestions.org/questions/slackware-14/)
-   -   Is it possible to use the Dell AC511 volume knob under Slackware? (https://www.linuxquestions.org/questions/slackware-14/is-it-possible-to-use-the-dell-ac511-volume-knob-under-slackware-4175700430/)

mathwhiz 09-15-2021 03:30 PM

There's an xfce plugin
 
https://docs.xfce.org/panel-plugins/...o-plugin/start
This plugin has a settable option
"Enable keyboard shortcuts for volume control"
As noted in an earlier post, turning the knob generates X KeyPress events.

https://github.com/lxqt/pavucontrol-qt
doesn't say whether pavucontrol-qt has the equivalent feature.

SavoTU 09-17-2021 08:07 AM

Did you try using /etc/acpi/acpi_handler.sh

From Gazl's post I linked before.

Code:

test@magrathea:/$ cat /etc/acpi/acpi_handler.sh
#!/bin/sh
# Default acpi script that takes an entry for all actions

IFS=${IFS}/
set $@

case "$1" in
  button)
    case "$2" in
      power) /sbin/init 0
        ;;
      mute ) /usr/bin/amixer sset 'Master' toggle
        ;;
      volumedown ) /usr/bin/amixer sset 'Master' '5%-'
        ;;
      volumeup ) /usr/bin/amixer sset 'Master' '5%+'
        ;;
      *) logger "ACPI action $2 is not defined"
        ;;
    esac
    ;;
  *)
    logger "ACPI group $1 / action $2 is not defined"
    ;;
esac


mathwhiz 09-17-2021 11:05 AM

Still working on C program
 
Out of stubbornness I'm still trying to get a C program running. My first attempt had to run as superuser and opened /dev/input/event10. It turns out that this was the reason that the alsa library call to get the player_volume was returning incorrect values. Opening the device is probably a bad idea for other reasons, for example it might interfere with evdev. So I need to get a report of an event from some server. It seems you can't get it directly from evdev. You can undoubtedly get it from the X server. This requires coding a minimal Xlib program to read any KeyPress events, and I'm in the process of trying to figure out how to do this. It might be worth looking at the acpid source code to see how it does it.

mathwhiz 09-19-2021 03:59 PM

It seems to be well-known that a standard method for handling volume
key events is to use window manager key bindings. I use fvwm; the
following can be added to ~/.fvwm/.fvwm2rc:
Key XF86AudioRaiseVolume A N exec amixer -q set Master 3%+
Key XF86AudioLowerVolume A N exec amixer -q set Master 3%-

I got a C program working, by grabbing the volume adjust keys using Xlib.
I used the Xlib input extension, so only events from the SoundBar are
grabbed. They are consumed. It's might be possible to pass them on to
the focus window; see
https://stackoverflow.com/questions/46288251/
capture-button-events-in-xlib-then-passing-the-event-to-the-client
However, the window manager probably consumes them, and there doesn't
seem to be any reason to pass them on.

My C program follows.

Code:

/*
  Monitor Dell AC511 USB Soundbar volume knob.
  Grabs Soundbar keys and consumes events.
  To terminate, kill process.
*/

#include <stdio.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/XF86keysym.h>
#include <X11/extensions/XInput.h>
#include <alsa/asoundlib.h>

/*The following keycodes were determined using xev*/
#define VUP_KC 123
#define VDN_KC 122
/* The following absolute delta is based on a 0-65536 range (~2.5%)*/
#define VDLTA 1600

/*print error message*/
static const char *erms[]={
 "can't open X display",
 "can't find AC511 device",
};
void erm(unsigned n)
{fputs(erms[n],stderr); fputc('\n',stderr);}

/*Adjust volume c=+1 up, c=-1 down.
  Alsa call setup code is as in amixer source code.
*/
static int adj_vol(int c)
{
 snd_mixer_t *mix_h;
 snd_mixer_selem_id_t *sid;
 const char *card = "default";
 const char *selem_name = "Master";
 snd_mixer_elem_t* elem;
 int fdi=0;

 /*open an empty mixer handle*/
 if (snd_mixer_open(&mix_h, 0)<0) goto erxit;
 /*attach the card to it*/
 if (snd_mixer_attach(mix_h, card)<0) goto erxit;
 /*register it*/
 if (snd_mixer_selem_register(mix_h, NULL, NULL)<0) goto erxit;
 /*load its elements*/
 if (snd_mixer_load(mix_h)<0) goto erxit;

 /*allocate an element ID (on the stack)*/
 snd_mixer_selem_id_alloca(&sid);
 /*set its index part*/
 snd_mixer_selem_id_set_index(sid, 0);
 /*set its name part*/
 snd_mixer_selem_id_set_name(sid, selem_name);
 /*find the element*/
 if ((elem=snd_mixer_find_selem(mix_h, sid))<0) goto erxit;

 /*perform adjustment*/
 {snd_mixer_selem_channel_id_t chns[2]=
  {SND_MIXER_SCHN_FRONT_LEFT,SND_MIXER_SCHN_FRONT_RIGHT};
 long min,max,val; unsigned short x;
 if (snd_mixer_selem_get_playback_volume_range(elem,&min,&max)<0) goto erxit;
 for (x=0; x<2; x++)
 {if (snd_mixer_selem_get_playback_volume(elem,chns[x],&val)<0) goto erxit;
  if (c>0) {if ((val+=VDLTA)>max) val=max;}
  else {if ((val-=VDLTA)<min) val=min;}
  if (snd_mixer_selem_set_playback_volume(elem,chns[x],val)<0) goto erxit;
 }}

 /*exit*/
 snd_mixer_close(mix_h);
 return 0;
erxit:
 snd_mixer_close(mix_h);
 if (fdi) close(fdi);
 fputs("alsa library call returned an error",stderr); fputc('\n',stderr);
 return -1;
}

/*main loop*/
int main(void)
{Display *dsp;
 Window rtw;
 XID id;
 XDevice *dev=0;
 XEvent event;
 XEventClass evl[1];
 unsigned dkpet;

 /*connect to server*/
 if ((dsp=XOpenDisplay(0))==0) {erm(0); return 0;}
 rtw=RootWindow(dsp,DefaultScreen(dsp));

 /* Get SoundBar XDevice * */
 {int ndev,i; XDeviceInfo *devs;
 devs=XListInputDevices(dsp,&ndev);
 for (i=0; i<ndev; i++)
  if (strstr(devs[i].name,"Dell AC511 USB SoundBar")) break;
 XFreeDeviceList(devs);
 if (i==ndev) {erm(1); goto erx1;}
 id=devs[i].id;
 id=devs[i].id;
 dev=XOpenDevice(dsp,id);}

 /*set event selection list; also get type*/
 DeviceKeyPress(dev,dkpet,evl[0])

 /*set up for event loop*/
 XSelectExtensionEvent(dsp,rtw,evl,1);
 XGrabDeviceKey
 (dsp, dev, XF86XK_AudioRaiseVolume, 0, NULL, rtw, True,
  1, evl, GrabModeAsync, GrabModeAsync );
 XGrabDeviceKey
 (dsp, dev, XF86XK_AudioLowerVolume, 0, NULL, rtw, True,
  1, evl, GrabModeAsync, GrabModeAsync );

 /*event loop*/
 {unsigned kc;
 while (1)
 {XNextEvent(dsp,&event);
  if (event.type==dkpet)
  {kc=((XDeviceKeyEvent *)&event)->keycode;
  if (kc==VUP_KC) {if (adj_vol(+1)<0) break;}
  else if (kc==VDN_KC) {if (adj_vol(-1)<0) break;}
  }
 }}

erx2: XCloseDevice(dsp,dev); /*releasses grabs*/
erx1: XCloseDisplay(dsp);
 return 0;
}



All times are GMT -5. The time now is 07:15 AM.