SHOW:
|
|
- or go back to the newest paste.
1 | #!/usr/bin/python2 | |
2 | # -*- coding: utf-8 -*- | |
3 | ||
4 | import gtk | |
5 | import glib | |
6 | import os | |
7 | import sys | |
8 | import ConfigParser | |
9 | import ctypes | |
10 | try: | |
11 | import pynotify | |
12 | if not pynotify.init("LockKeys"): | |
13 | print("Il y a eu une erreur pendant l'initialisation du système de notification. Les notifications ne fonctionnerons pas.") | |
14 | pynotify = None | |
15 | except: | |
16 | print("Il semble que python-notify ne soit pas installé. Les notifications ne fonctionnerons pas.") | |
17 | pynotify = None | |
18 | NotifyAvailable = pynotify | |
19 | ||
20 | class XKeyboardState(ctypes.Structure): | |
21 | _fields_ = [("key_click_percent", ctypes.c_int), | |
22 | ("bell_percent", ctypes.c_int), | |
23 | ("bell_pitch", ctypes.c_uint), | |
24 | ("bell_duration", ctypes.c_uint), | |
25 | ("led_mask", ctypes.c_ulong), | |
26 | ("global_auto_repeat", ctypes.c_int), | |
27 | ("auto_repeats", ctypes.c_char * 32)] | |
28 | ||
29 | def initXGetKeyboardControl(): | |
30 | global dpy, keyboardState, XGetKeyboardControl | |
31 | ||
32 | libX11 = ctypes.CDLL("libX11.so.6") | |
33 | XOpenDisplay = libX11.XOpenDisplay | |
34 | XOpenDisplay.restype = ctypes.c_void_p | |
35 | XOpenDisplay.argtypes = [ctypes.c_char_p] | |
36 | XGetKeyboardControl = libX11.XGetKeyboardControl | |
37 | XGetKeyboardControl.restype = ctypes.c_int | |
38 | XGetKeyboardControl.argtypes = [ctypes.c_void_p, ctypes.POINTER(XKeyboardState)] | |
39 | ||
40 | dpy = XOpenDisplay(None) | |
41 | keyboardState = XKeyboardState() | |
42 | ||
43 | def runXGetKeyboardControl(): | |
44 | global dpy, keyboardState, XGetKeyboardControl | |
45 | XGetKeyboardControl(dpy, ctypes.byref(keyboardState)) | |
46 | return keyboardState.led_mask | |
47 | ||
48 | #écrit dans le fichier de config | |
49 | def WriteConfig (Section, Key, Value): | |
50 | Config.set(Section,Key,Value) | |
51 | with open(ConfigFile, 'w') as myfile: | |
52 | Config.write(myfile) | |
53 | ||
54 | #Notification (état du clavier) si pynotify != None | |
55 | def notify(message,duration): | |
56 | if pynotify: | |
57 | n = pynotify.Notification('LockKeys', message) | |
58 | n.set_timeout(duration) | |
59 | n.set_icon_from_pixbuf(gtk.Label().render_icon(gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_LARGE_TOOLBAR)) | |
60 | n.show() | |
61 | ||
62 | ||
63 | class Systray(): | |
64 | def __init__(self): | |
65 | self.tray_object= gtk.StatusIcon() | |
66 | self.tray_object.connect("popup_menu", self.rightclick_menu) | |
67 | self.show_trayicon(1) ## fixed to one for now | |
68 | self._oldMask = -1 | |
69 | ||
70 | def show_trayicon(self,value): | |
71 | self.tray_object.set_visible(True) | |
72 | return | |
73 | ||
74 | def property_modified(self): | |
75 | # utilse xset pour connaître l'état des touches capslock et numlock | |
76 | # 0 -> aucun, 1 -> capslock, 2-> numlock, 3 -> les 2 | |
77 | mask=int(runXGetKeyboardControl()) & 3 | |
78 | if mask != self._oldMask: | |
79 | self._oldMask = mask | |
80 | if sound_status == True: | |
81 | os.system(Sound) | |
82 | notify(msg[mask],2000) | |
83 | ||
84 | - | # Todo : essayer d'abord usr/share/lockkeys/ voire ~/.local/lockkeys |
84 | + | # Todo : essayer d'abord usr/share/lockkeys/ voire ~/.local/lockkeys |
85 | - | icon_path = './' + str(mask) + '.png' |
85 | + | icon_path = './' + str(mask) + '.png' |
86 | - | self.tray_object.set_from_file(icon_path) |
86 | + | self.tray_object.set_from_file(icon_path) |
87 | ||
88 | # défini le menu clic droit sur l'icône | |
89 | def rightclick_menu(self, button, widget, event): | |
90 | menu = gtk.Menu() | |
91 | about_menu = gtk.ImageMenuItem(gtk.STOCK_ABOUT) | |
92 | about_menu.connect('activate', self.about) | |
93 | exit_menu = gtk.ImageMenuItem(gtk.STOCK_CLOSE) | |
94 | exit_menu.connect('activate', self.close) | |
95 | menu.append(about_menu) | |
96 | menu.append(exit_menu) | |
97 | sep = gtk.SeparatorMenuItem() | |
98 | menu.append(sep) | |
99 | sound_menu = gtk.CheckMenuItem("Activer le son") | |
100 | sound_menu.set_active(sound_status) | |
101 | sound_menu.connect("activate", self.sound_toggle) | |
102 | menu.append(sound_menu) | |
103 | notify_menu = gtk.CheckMenuItem("Activer les notifications") | |
104 | notify_menu.set_active(notify_status) | |
105 | notify_menu.connect("activate", self.notify_toggle) | |
106 | menu.append(notify_menu) | |
107 | menu.show_all() | |
108 | menu.popup(None, None, None, 2, event) | |
109 | ||
110 | # activation / désactivation du son et enregistrement dans le fichier config | |
111 | def sound_toggle(self, widget): | |
112 | global sound_status | |
113 | if widget.active: | |
114 | sound_status=True | |
115 | else: | |
116 | sound_status=False | |
117 | WriteConfig ('helpers','sound',sound_status) | |
118 | ||
119 | # activation / désactivation des notifications et enregistrement dans le fichier config | |
120 | def notify_toggle(self, widget): | |
121 | global notify_status | |
122 | global pynotify | |
123 | if widget.active: | |
124 | notify_status=True | |
125 | pynotify=NotifyAvailable | |
126 | else: | |
127 | notify_status=False | |
128 | pynotify=None | |
129 | WriteConfig ('helpers','notification',notify_status) | |
130 | ||
131 | def close(self,button): | |
132 | sys.exit(0) | |
133 | ||
134 | def about(self, button): | |
135 | about_dg = gtk.AboutDialog() | |
136 | about_dg.set_name('Lockkeys') | |
137 | about_dg.set_version('0.2') | |
138 | about_dg.set_copyright('(C) 2014 Vincent Gay <vgay@vintherine.org>') | |
139 | about_dg.set_comments(("Simple icône dans la zone de notification pour indiquer l'état de CapsLock et NumLock")) | |
140 | about_dg.set_license('Ce script est distribuable sous licence gpl version 3 ou supérieure\nhttp://www.gnu.org/licenses/gpl-3.0.fr.html') | |
141 | about_dg.set_website('http://blog.vintherine.org') | |
142 | about_dg.run() | |
143 | about_dg.destroy() | |
144 | ||
145 | class Manager: | |
146 | def __init__(self): | |
147 | self.listener = Systray() | |
148 | ||
149 | def __property_modified_handler(self): | |
150 | self.listener.property_modified() | |
151 | ||
152 | def update(self): | |
153 | self.__property_modified_handler() | |
154 | return True | |
155 | ||
156 | def main(): | |
157 | initXGetKeyboardControl() | |
158 | m = Manager() | |
159 | glib.timeout_add(300, m.update) | |
160 | gtk.main() | |
161 | ||
162 | ConfigFile=os.path.expanduser('~/.config/lockkeys.cfg') | |
163 | # aplay appartient au paquet alsa, est-ce la peine de vérifier ? | |
164 | Sound = 'aplay ./ding.wav > /dev/null 2>1&' | |
165 | sound_status=True | |
166 | pynotify = None | |
167 | Config = ConfigParser.ConfigParser() | |
168 | msg=[] | |
169 | msg.append('Capslock = off, Numlock = off') | |
170 | msg.append('Capslock = on, Numlock = off') | |
171 | msg.append('Capslock = off, Numlock = on') | |
172 | msg.append('Capslock = on, Numlock = on') | |
173 | ||
174 | #créer le fichier de config s'il n'existe pas | |
175 | if os.path.isfile(ConfigFile) == False: | |
176 | ini = open(ConfigFile,'w') | |
177 | Config.add_section('helpers') | |
178 | Config.set('helpers','sound',True) | |
179 | Config.set('helpers','notification',False) | |
180 | Config.write(ini) | |
181 | ini.close() | |
182 | ||
183 | # lire le fichier de configuration | |
184 | Config.read(ConfigFile) | |
185 | try: | |
186 | sound_status = Config.getboolean("helpers", "sound") | |
187 | except: | |
188 | WriteConfig ('helpers','sound',True) | |
189 | try: | |
190 | notify_status = Config.getboolean("helpers", "notification") | |
191 | except: | |
192 | WriteConfig ('helpers','notification',False) | |
193 | notify_status=False | |
194 | if notify_status: | |
195 | pynotify=NotifyAvailable | |
196 | ||
197 | main() |