[HOWTO]如何使用多媒体键

CPU/显卡/打印机/USB设备等硬件问题
回复
xiechy
帖子: 1074
注册时间: 2006-01-18 15:01

[HOWTO]如何使用多媒体键

#1

帖子 xiechy » 2007-01-17 15:45

原来写的东西现在看来有些错误。重改。

1、终端下scancode于keycode
键盘事件发生,核心会出来一个scancode,然后将这个scancode转换成keycode,,这个时候才知道这个键按下是什么意思。怎样知道自己的多媒体键是不是内核识别出来了呢?直白的说,只要你的scancode被识别了,那么就可以进行下面的操作,如果内核没有识别出来,那就白搭。

代码: 全选

showkey -s
这会检查出你的按键是否产生scancode。
注意,并不是没有产生scancode就说明这个键没有用,这只是说明内核不知道这个键。就拿我的dell 630m来说,调亮度就不会产生scancode,因为这个功能是直接由bios管理的,操作系统完全无法管理。

能够产生scancode,那么接着看这个键是不是有keycode map上了。

代码: 全选

showkey -k
还是按键尝试。

作为一种替代方法,也可以按键之后,

代码: 全选

dmesg |tail
这样不能识别的键的scancode会提示,要你人工设定keycode。

如果有keycode输出,可以直接跳过下面,进入2部分。
没有keycode,我们可以用setkeycodes工具将scancode映射上keycode。但之前首先要检查这个keycode是不是已经用上了。

代码: 全选

dumpkeys
其中没有占用的就是可以使用的keycode,可以在等下用上。

代码: 全选

setkeycodes e012 167
将scancode e012映射上keycode 167
这个指令需要写在启动脚本中。我放在
/etc/conf.d/local.start中。

要说明一下,linux内核2.6对scancode和keycode有着和以前不一样的对待方式。在以前,有程序要检查scancode的话,那么就会给这个程序scancode,但是现在不同,现在是根据生成的keycode,重新翻译一个scancode给应用程序,这样就把个个厂商可能都不同的scancode,在应用程序方面统一了起来。代价就是应用程序对于没有keycode的按键就完全不知道了。所以如果一个键没有keycode,那么一定要setkeycodes给它。而X,就是这样一个应用程序。

补充一下,如果想要直接输出真正的scancode,那么在2.6.9内核之后,可以使用kernel开关

代码: 全选

atkbd.softraw=0 
来达到目的。

那么这个标准的scancode从哪里可以知道定义呢?
答案是:
/usr/include/linux/input.h
#define KEY_MUTE 113
#define KEY_VOLUMEDOWN 114
#define KEY_VOLUMEUP 115
#define KEY_NEXTSONG 163
#define KEY_PLAYPAUSE 164
#define KEY_PREVIOUSSONG 165
#define KEY_STOPCD 166
显然,我的dell630m是完全被认出来了,只有一个媒体中心的键没有映射到。

2、终端下的伪多媒体键。
为什么说这是伪快捷键,因为这实际上只是把字符串连接上一个字串而已,相当于按一个键,直接输入了这么多字符而已。
keymaps所在的位置一般是在/usr/share/keymaps下。我们创建自己的keymap文件。
/usr/local/share/keymaps/dell.map
keycode 113 = F73
keycode 114 = F74
keycode 115 = F75
keycode 163 = F83
keycode 164 = F84
keycode 165 = F85
keycode 166 = F86

string F73 = "amixer -q set Master toggle
"
string F74 = "amixer -q set Master 2- unmute
"
string F75 = "amixer -q set Master 2+ unmute
"
string F83 = "mpc next
"
string F84 = "mpc toggle
"
string F85 = "mpc prev
"
string F86 = "mpc stop
"
这样就是把对应的keycode映照上指定的字串名字。注意每个字串,是包括后面的换行符。
同样的,这个map也需要每次启动时自动执行。我还是放在/etc/conf.d/local.start中。

代码: 全选

loadkeys /usr/local/share/keymaps/dell.map
(实际上看看/usr/share/keymaps/下面i386内的文件就知道,内核其实也是通过map来知道某个键的含义是什么的。)

3、X下的多媒体键绑定
首先,X中也有keycode的概念,但是这个keycode和终端中的keycode是不同的。
查看目录/usr/share/X11/xkb
下面的keycodes就是我们的keycode是怎样产生的。

代码: 全选

 setxkbmap -print
可以看出我们现在的xkb配置是怎样的。
简单的说来,每行的意思:
  • xkb_keycodes { include "xfree86+aliases(qwerty)" };从keycode转换到类似于<AE01>这样形式的符号,之后的x就不会再管keycode的事的。独立于硬件了。
  • xkb_types { include "complete" };将各种快捷键分级。例如shift+ctrl+xx什么的,就要后于shift+xx的识别,否则前面这个快捷不就永无出现之日?
  • xkb_compat { include "complete" };兼容性的简写,很奇怪的名字,相对于symbol,更像是只对xkb的状态改变之类的信号感兴趣。例如按下num_lock,就由方向键变成了数字键一样。
  • xkb_symbols { include "pc+us+inet(latitude)" };将keycode转换来的符号分组,结合象shift这样的修饰键,这样可以实现一个按键,产生不同的符号,例如1和!。
  • xkb_geometry { include "pc(latitude)" };键盘的物理布局,例如可能esc键,我们有时后也用"最左上角的键"来表示。这一层可以帮助X作出类似的alias。
上面讲的罗嗦,对我们有意义的只有一项,那就是keycode的识别。只要识别了keycode,那么我们就可以map上X事件。检查X的keycode识别了没有的很简单:

代码: 全选

xev
按键之后看输出的keycode是什么。如果识别了,直接看4部分。
重新看setxkbmap -print的输出:
xkb_keycodes { include "xfree86+aliases(qwerty)" };
xkb_symbols { include "pc+us+inet(latitude)" };
看xkb_keycode后面的include的内容。xfree86+aliases(qwerty),这代表的是:
在keycodes目录下的xfree86文件的内容(实质是xfree86文件中作为default存在的那段定义)和aliases文件中的qwerty段的内容的统一。
类似的,xbk_symbols后面的可以理解为symbols目录下的pc,us,和inet文件中latitude段定义。
所以,如果没有识别,我们只要修改上面对应的文件就好了。对我来说,主要是keycodes/xfree86。
xfree86的内容很多,我们要注意的是:
xkb_keycodes "basic" {

minimum= 8;
maximum= 255;
说明,在x中的keycode最小是8,最大是255。
basic段注释的非常好,再次提醒,这里面的keycode与终端中的无关!
但是对于特殊按键,并不是没有解释。象我们的多媒体键,通常就是所谓的“Internet key”
也就是<I01>这类的标识符表示的键。

前面说过,X的keycode的来历是由键盘scancode-->内核keycode-->由内核keycode生成的scancode-->X的keycode这总共3步转化成的。其中第一步可以修改,第二步和第三步都是内建的,所以我们完全可以做一个由内核keycode到X的keycode的对应表格,这个表格我做到后面附件pdf了。
这里是ascii的,排版不是很好看:
0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 76, 79, 80, 81, 82, 83, 84, 85, 86, 87,
88, 89, 90, 91, 111, 221, 94, 95, 96, 211, 128, 127, 129, 208, 131, 126,
108, 109, 112, 111, 113, 181, 97, 98, 99, 100, 102, 103, 104, 105, 106, 107,
239, 160, 174, 176, 222, 157, 123, 110, 139, 134, 209, 210, 133, 115, 116, 117,
232, 133, 134, 135, 140, 248, 191, 192, 122, 188, 245, 158, 161, 193, 223, 227,
198, 199, 200, 147, 159, 151, 178, 201, 146, 203, 166, 236, 230, 235, 234, 233,
163, 204, 253, 153, 162, 144, 164, 177, 152, 190, 208, 129, 130, 231, 209, 210,
136, 220, 143, 246, 251, 137, 138, 182, 183, 184, 93, 184, 247, 132, 170, 219,
249, 205, 207, 149, 150, 154, 155, 167, 168, 169, 171, 172, 173, 165, 175, 179,
180, 0, 185, 186, 187, 118, 119, 120, 121, 229, 194, 195, 196, 197, 148, 202,
101, 212, 237, 214, 215, 216, 217, 218, 228, 142, 213, 240, 241, 242, 243, 244,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

4、用程序映射keycode到特定的程序。
xev如果同时告诉了我们keysym是什么的话,那么直接用它给的keysym就好了。如果没有,用xmodmap将keycode绑定到特定的X keysym。
编辑文件~/.Xmodmap
keycode 162 = XF86AudioPlay
keycode 164 = XF86AudioStop
keycode 160 = XF86AudioMute
keycode 144 = XF86AudioPrev
keycode 153 = XF86AudioNext
keycode 176 = XF86AudioRaiseVolume
keycode 174 = XF86AudioLowerVolume
在启动脚本中添加

代码: 全选

xmodmap ~/.Xmodmap
这行命令。
我放在~/.xinitrc中。
然后编辑文件~/.xbindkeysrc
"amixer -q sset PCM 6- unmute"
XF86AudioLowerVolume
"amixer -q sset PCM 6+ unmute"
XF86AudioRaiseVolume
"amixer -q sset Master toggle"
XF86AudioMute
"/usr/bin/mpc prev"
XF86AudioPrev
"/usr/bin/mpc next"
XF86AudioNext
"/usr/bin/mpc stop"
XF86AudioStop
"/usr/bin/mpc toggle"
XF86AudioPlay
下面是事件keysym名称,上面是命令本身。
xbindkeys也需要加入启动脚本。

代码: 全选

xbindkeys
也可以用替代的方法,使用类似lineak或者hotkeys这样的程序。
其实这类软件,也就是做了一个keycode到keysym然后再到命令的转化过程。但是这些软件都会带上很多笔记本电脑的keycode等等的数据,如果在他的数据中有,那么识别就容易,out of box,如果没有,就会有些键用不上。
hotkeys的数据是简单的xml文件。可以自己手动编辑,很容易,不详述了。
另外,在使用了xbindkeys和xmodmap之后,再用xev似乎就看不到事件出现了。但是不影响快捷键的使用。

6、不应用程序,而是修改keymap本身或者创建自己的keymap。
直接改,比较简单,但是Xorg一更新,这个就替换掉了。
首先看X的keycode在keycodes/xfree86中是对应的什么符号:
例如
<I20> = 160;
<I2E> = 174;
<I30> = 176;
那么我们知道我的内核keycode为113,114,115的这三个键,现在叫<I20><I2E><I30>
于是改symbols/inet中的latitude段,
key <I20> { [ XF86AudioMute ] };
key <I2E> { [ XF86AudioLowerVolume ] };
key <I30> { [ XF86AudioRaiseVolume ] };
这样,这几个键一按下来,就会产生这些个事件了。当然,xbindkeys,hotkeys这样的程序也还是要的。
如果你的多媒体键的内核keycode所对应的X的keycode没有在keycodes/xfree86中出现,那么你可以自己添加一个这样的keysym。如果你的keysym没有在symbols/inet中有对应的事件,那么也是添加上即可。
创建什么的下次再写了,11点多了,也好晚了。

以上方法只针对Xorg的xkb本身,所以对一切桌面环境应该都是适用的。
头像
KyTor
帖子: 222
注册时间: 2006-12-05 22:23
来自: http://www.wengyuanhang.com/
联系:

#2

帖子 KyTor » 2007-09-19 17:23

辛苦了,很精彩,收藏了,谢了
虔诚的信徒啊!请相信KyTor吧!
http://www.wengyuanhang.com/
------------------
愿上帝赐我平静,接受我无法改变的事;
愿上帝赐我勇气,改变我能够改变的事;
愿上帝赐我智慧,能明辨这两者的差异;
Wang Lei
帖子: 214
注册时间: 2007-07-16 21:42

#3

帖子 Wang Lei » 2007-09-19 17:41

GOOD!
HP Compaq 6515b(GL087PA)
Sawfish+Emacs+Firefox+Xpdf+MPlayer...
大鸿
帖子: 36
注册时间: 2005-12-30 23:01
来自: 杭州

showkey

#4

帖子 大鸿 » 2007-10-26 10:56

showkey在哪个包啊,我是最小化安装的。系统提示没有这个命令
正是由于感动“乐于分享”的精神而来到这里,希望有一点帮助。
头像
carbont
帖子: 3406
注册时间: 2007-11-22 10:20
来自: 北京

#5

帖子 carbont » 2007-11-28 11:33

sudo showkey?
反正我是这样才能用的。

但是奇怪的是我在gnome的“键盘快捷键”里面能设置前进后退键(thinkpad r60i),能够看见0xea和0xe9的字样。
但是在键盘上面还是不能操作……

可能是我没有太看明白……

我也没有~/.Xmodmap……这个文件……
头像
zhuqin_83
帖子: 10606
注册时间: 2006-05-13 4:02
联系:

#6

帖子 zhuqin_83 » 2007-11-30 5:54

不用这么麻烦,装一个keytouch(GUI)就完事了,还可以自定义键。源里就有,当然不是最新。
HP Pavilion DV6-2064CA: AMD Turion II Ultra Dual-Core Mobile M640, HD4650, 2GBx2 DDR2-800, Seagate 500GB 7200RPM SATA, BD-ROM
DELL UltraSharp 2209WA
Arch64, Testing repo
回复