Function keys are now working
In a previous post, I mentioned that didn't have any function keys working. Well, since I got out of this semester, I fixed this problem. Long ago, I found instructions for making the function keys work on the Gentoo forums. I had to read through them and took out the parts that I didn't need. After paring down all that discussion, I ended up with a much quicker and easier procedure that works.
First, I put the following code into a file called sonyfn.c This code was submitted to the Gentoo forums by Pijalu. If this code is helpful to you, please let him know.
#include
#include
#include
#include
#include
#include
// input thing
#include
// sound stuff
#include
// keys
#define FN_F2 1 // cut sound
#define FN_F3 2 // volume -
#define FN_F4 4 // volume +
#define FN_F5 8 // Brightness -
#define FN_F6 16 // Brightness +
#define FN_F7 32 // LCD/SCREEN
#define FN_F10 128 // Zoom in
#define FN_F12 64 // Suspend
#define S1_BTN 4096 // S1 custom button
#define S2_BTN 8192 // S2 custom button
#define FN_INPUT_VALUE 245 // Fn key generate a 245 value
#define FN_INPUT_TYPE 4 // a 4 type
#define FN_INPUT_CODE 4 // and a 4 code
// config hard coded :p
#define MIXER_DEV "/dev/mixer"
// SOUND HANDLER
int get_volume(int *value)
{
int mixer = open(MIXER_DEV, O_RDONLY);
if (mixer) {
ioctl(mixer, SOUND_MIXER_READ_VOLUME, value);
close(mixer);
return 0;
}
else
return 1;
}
int set_volume(int *value)
{
int mixer = open(MIXER_DEV, O_RDWR);
if (mixer) {
ioctl(mixer, SOUND_MIXER_WRITE_VOLUME, value);
close(mixer);
return 0;
}
else
return 1;
}
int volume_up()
{
int value = 0;
get_volume(&value);
if (value < 0x5a5a)
value += 0x0a0a;
else
value = 0x6464;
set_volume(&value);
return 0;
}
int volume_down()
{
int value = 0;
get_volume(&value);
if (value > 0x0a0a)
value -= 0x0a0a;
else
value = 0;
set_volume(&value);
return 0;
}
int oldvalue;
int mute()
{
int value;
get_volume(&value);
if (value) {
oldvalue=value;
value=0;
set_volume(&value);
}
else {
if (!oldvalue) {
volume_up();
}
else {
set_volume(&oldvalue);
}
}
return 0;
}
// END OF SOUND
/* Return current brightness of the screen */
int getBrightness() {
FILE* handle;
char buffer[2];
int ret;
if ((handle=fopen("/proc/acpi/sony/brightness","rb"))==NULL) {
perror("Error opening /proc/acpi/sony/brightness");
exit(-1);
}
if (fscanf(handle,"%d",&ret)!=1) {
perror("Error reading /proc/acpi/sony/brightness");
exit(-1);
}
fclose(handle);
return ret;
}
/* Set the current brightness of the screen */
void setBrightness(int b) {
FILE* handle;
char buffer[2];
// validate values
if (b>8) {
b=8;
}
else if (b<1) {
b=1;
}
if ((handle=fopen("/proc/acpi/sony/brightness","wb"))==NULL) {
perror("Error opening /proc/acpi/sony/brightness");
exit(-1);
}
if (fprintf(handle,"%d",b)!=1) {
perror("Error writing /proc/acpi/sony/brightness");
exit(-1);
}
fclose(handle);
}
// Pool the fnkey status
int getCodes() {
FILE* handle;
char buffer[10];
int ret;
if ((handle=fopen("/proc/acpi/sony/fnkey","rb"))==NULL) {
perror("Error opening /proc/acpi/sony/fnkey");
exit(-1);
}
if (fscanf(handle,"%d",&ret)!=1) {
perror("Error reading /proc/acpi/sony/fnkey");
exit(-1);
}
fclose(handle);
return ret;
}
// main and loop
int main(int argc, char **argv) {
// event interface
int fd = -1; /* the file descriptor for the device */
int i; /* loop counter */
size_t read_bytes; /* how many bytes were read */
struct input_event ev[64]; /* the events (up to 64 at once) */
/* key code */
int key;
/* used if event hit fn */
int hasSomething;
/* open event interface*/
if (argc != 2) {
/* i don't like outputs...
fprintf(stderr, "Using /dev/input/event0 for input\n");
fprintf(stderr, "Overide with %s event-device\n", argv[0]);
*/
if ((fd = open("/dev/input/event0", O_RDONLY)) < 0) {
perror("event interface open failed");
exit(1);
}
}
else {
if ((fd = open(argv[1], O_RDONLY)) < 0) {
perror("event interface open failed");
exit(1);
}
}
nice(10); // be a nice dirty code (less dirty but keep nice)
while(1) { /* loop */
hasSomething=0; /* nothing yet */
/* read the event interface */
read_bytes = read(fd, ev, sizeof(struct input_event) * 64);
if (read_bytes < (int) sizeof(struct input_event)) {
perror("sonyfn: short read");
exit (1);
}
/* Loop for all readed events until we have something interesting.. */
for (i = 0;! hasSomething && ( i < (int) (read_bytes / sizeof(struct input_event)) ); i++) {
hasSomething= (ev[i].type == FN_INPUT_TYPE)
&& (ev[i].code == FN_INPUT_CODE)
&& (ev[i].value == FN_INPUT_VALUE);
}
/* If we got a FN event, plz do something...*/
if ( hasSomething && (key=getCodes()) ) {
if ((key & FN_F5)==FN_F5) { // lower brightness
setBrightness(getBrightness()-1);
}
if ((key & FN_F6)==FN_F6) { // higher brightness
setBrightness(getBrightness()+1);
}
if ((key & FN_F2)==FN_F2){
mute();
}
if ((key & FN_F3)==FN_F3) {
volume_down();
}
if ((key & FN_F4)==FN_F4) {
volume_up();
}
if ((key & FN_F12)==FN_F12) {
if (fork()==0) {
/* that's my home made script for swsusp
#!/bin/sh
sync
echo "disk" > /sys/power/state
*/
if (execv("/bin/hibernate",NULL)==-1) {
perror("Cannot run hibernate");
}
}
}
/* rest i still don't care */
}
}// while
close(fd);
return 0;
}
Then I had to compile this by doing a:
$ gcc sonyfn.c -o sonyfn
$ mv sonyfn /usr/bin
$ sudo chown root /usr/bin/sonyfn
$ sudo chmod 4755 /usr/bin/sonyfn
Then to manually run this, you call the program and provide the path to the keyboard. In my case, the keyboard is /dev/input/event0.
So now I need it to launch at boot time, so I'm using the Session GUI to add it to the start up programs.
sonyfn /dev/input/event0 &
I rebooted and it launches just fine.
