~ubuntu-branches/ubuntu/natty/libglobalhotkeys-ruby/natty

« back to all changes in this revision

Viewing changes to globalhotkeys.c

  • Committer: Bazaar Package Importer
  • Author(s): Vincent Carmona
  • Date: 2010-08-03 19:10:14 UTC
  • Revision ID: james.westby@ubuntu.com-20100803191014-iaann8qgshv4l7uz
Tags: upstream-0.1.1
ImportĀ upstreamĀ versionĀ 0.1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Copyright 2010 Vincent Carmona
 
3
vinc4mai@gmail.com
 
4
 
 
5
This file is part of rghk.
 
6
 
 
7
    rghk is free software; you can redistribute it and/or modify
 
8
    it under the terms of the GNU General Public License as published by
 
9
    the Free Software Foundation; either version 2 of the License, or
 
10
    (at your option) any later version.
 
11
 
 
12
    rghk is distributed in the hope that it will be useful,
 
13
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
    GNU General Public License for more details.
 
16
 
 
17
    You should have received a copy of the GNU General Public License
 
18
    along with ZiK; if not, write to the Free Software
 
19
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
20
*/
 
21
 
 
22
#include <ruby.h>
 
23
#include <gdk/gdkx.h>
 
24
#include <gdk/gdkevents.h>
 
25
#include <X11/Xlib.h>
 
26
//xev to see keycode
 
27
//take a look at http://www.gnu.org/prep/standards/standards.html
 
28
 
 
29
//Modifier Key
 
30
enum Modifier
 
31
{
 
32
        RGHK_SHIFT_MASK=1<<0,   
 
33
        RGHK_LOCK_MASK=1<<1,    
 
34
        RGHK_CONTROL_MASK=1<<2, 
 
35
        RGHK_MOD1_MASK=1<<3,    
 
36
        RGHK_MOD2_MASK=1<<4,    
 
37
        RGHK_MOD3_MASK=1<<5,    
 
38
        RGHK_MOD4_MASK=1<<6,    
 
39
        RGHK_MOD5_MASK=1<<7,
 
40
        RGHK_NUM_LOCK_MASK=RGHK_MOD2_MASK//Is it true for all keyboards?
 
41
        //RGHK_SCROLL_LOCK=??
 
42
};
 
43
 
 
44
VALUE mGlobalHotKeys;
 
45
VALUE mModifier;
 
46
VALUE cKeyBinder;
 
47
 
 
48
/*
 
49
 * call-seq: bind(key, modifier) {block}
 
50
 * 
 
51
 * key: a key value. Gdk::Keyval constants can be used.
 
52
 * 
 
53
 * modifier: a GlobalHotKeys::Modifier.
 
54
 * 
 
55
 * Set a global hotkey.
 
56
 * block will be called when the key and the modifier are hitted.
 
57
*/
 
58
VALUE
 
59
kb_bind(VALUE self, VALUE key, VALUE modifier)
 
60
{
 
61
        GdkWindow *rootwin;
 
62
        Display *xdisplay;
 
63
        uint keycode;
 
64
        /*      uint ignored[]={0, RGHK_LOCK_MASK, RGHK_NUM_LOCK_MASK, RGHK_SCROLL_LOCK,
 
65
                RGHK_LOCK_MASK|RGHK_NUM_LOCK_MASK, RGHK_LOCK_MASK|RGHK_SCROLL_LOCK, RGHK_NUM_LOCK_MASK|RGHK_SCROLL_LOCK,
 
66
                RGHK_LOCK_MASK|RGHK_NUM_LOCK_MASK|RGHK_SCROLL_LOCK};*/
 
67
        uint ignored[]={0, RGHK_LOCK_MASK, RGHK_NUM_LOCK_MASK, RGHK_LOCK_MASK|RGHK_NUM_LOCK_MASK};
 
68
        uint mod;
 
69
 
 
70
        if (rb_funcall(rb_iv_get(cKeyBinder, "stock"), rb_intern("include?"), 1, self)==Qtrue)
 
71
                rb_raise(rb_eException, "KeyBinder allready binded.");
 
72
 
 
73
        rb_iv_set(self, "@key", key);
 
74
        rb_iv_set(self, "@mod", modifier);
 
75
        rb_iv_set(self, "block", rb_block_proc());
 
76
        rb_ary_push(rb_iv_get(cKeyBinder, "stock"), self);
 
77
 
 
78
        rootwin=gdk_get_default_root_window();//stock this window in variable once for all?
 
79
        xdisplay=GDK_WINDOW_XDISPLAY(rootwin);
 
80
 
 
81
        keycode=XKeysymToKeycode(xdisplay, FIX2UINT(key));
 
82
        if (keycode==0)
 
83
                rb_raise(rb_eException, "Invalid key value.");
 
84
 
 
85
        if NIL_P(modifier)
 
86
                mod=0;
 
87
        else
 
88
                mod=FIX2UINT(modifier);
 
89
 
 
90
        int i;
 
91
        for (i=0; i<4 ; i++)
 
92
        {
 
93
                XGrabKey(xdisplay, keycode, mod|ignored[i],  GDK_WINDOW_XWINDOW(rootwin), False,
 
94
                        GrabModeAsync, GrabModeAsync);
 
95
        }
 
96
//XGrabKey(xdisplay, keycode, AnyModifier, GDK_WINDOW_XWINDOW(rootwin), False, GrabModeAsync, GrabModeAsync);
 
97
        return Qtrue;
 
98
}
 
99
 
 
100
/*
 
101
 * Unset a global hotkey.
 
102
*/
 
103
VALUE
 
104
kb_unbind(VALUE self)
 
105
{
 
106
        VALUE del, ret;
 
107
        GdkWindow *rootwin;
 
108
        Display *xdisplay;
 
109
        uint keycode, mod;
 
110
        uint ignored[]={0, RGHK_LOCK_MASK, RGHK_NUM_LOCK_MASK, RGHK_LOCK_MASK|RGHK_NUM_LOCK_MASK};
 
111
 
 
112
        del=rb_funcall(rb_iv_get(cKeyBinder, "stock"), rb_intern("delete"), 1, self);
 
113
        if NIL_P(del)
 
114
                return Qfalse;
 
115
        
 
116
        rootwin=gdk_get_default_root_window();
 
117
        xdisplay=GDK_WINDOW_XDISPLAY(rootwin);
 
118
        keycode=XKeysymToKeycode(xdisplay, FIX2UINT(rb_iv_get(self, "@key")));
 
119
        mod=FIX2UINT(rb_iv_get(self, "@mod"));
 
120
 
 
121
        int i;
 
122
        for (i=0; i<4 ; i++)
 
123
                XUngrabKey(xdisplay, keycode, mod|ignored[i], GDK_WINDOW_XWINDOW (rootwin));
 
124
        return Qtrue;
 
125
}
 
126
 
 
127
/*
 
128
 * Unset a all global hotkeys.
 
129
*/
 
130
VALUE
 
131
kb_unbind_all(VALUE self)
 
132
{
 
133
        rb_iterate(rb_each, rb_iv_get(cKeyBinder, "stock"), kb_unbind, Qnil);
 
134
        return Qnil;
 
135
}
 
136
 
 
137
VALUE
 
138
process(VALUE kb_obj, VALUE xkey)
 
139
{
 
140
//rb_funcall(rb_stdout, rb_intern("puts"), 1, RARRAY(xkey)->ptr[1]);
 
141
        uint keycode=XKeysymToKeycode(GDK_WINDOW_XDISPLAY(gdk_get_default_root_window()), FIX2UINT(rb_iv_get(kb_obj, "@key")));
 
142
 
 
143
        if (keycode==FIX2UINT(RARRAY(xkey)->ptr[0]))
 
144
        {
 
145
                uint ignored=RGHK_LOCK_MASK|RGHK_NUM_LOCK_MASK;
 
146
                uint mod=FIX2UINT(RARRAY(xkey)->ptr[1])&~ignored;
 
147
                uint keymod;
 
148
 
 
149
                if NIL_P(rb_iv_get(kb_obj, "@mod"))
 
150
                        keymod=0;
 
151
                else
 
152
                        keymod=FIX2UINT(rb_iv_get(kb_obj, "@mod"));
 
153
 
 
154
                if (keymod==mod)
 
155
                        rb_funcall(rb_iv_get(kb_obj, "block"), rb_intern("call"), 1, kb_obj);
 
156
        }
 
157
        return Qnil;
 
158
}
 
159
 
 
160
GdkFilterReturn
 
161
filter_func(GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
 
162
{
 
163
        GdkFilterReturn ret;
 
164
        XEvent *xevent=(XEvent*)gdk_xevent;
 
165
 
 
166
        if (xevent->type==KeyPress)
 
167
        {
 
168
                VALUE xev=rb_ary_new3(2, INT2FIX(xevent->xkey.keycode), INT2FIX(xevent->xkey.state));
 
169
 
 
170
                rb_iterate(rb_each, rb_iv_get(cKeyBinder, "stock"), process, xev);
 
171
        }
 
172
 
 
173
        return GDK_FILTER_CONTINUE;
 
174
}
 
175
 
 
176
// :nodoc: It is called by rghk when it is required.
 
177
VALUE
 
178
mInit(VALUE self)
 
179
{
 
180
        gdk_window_add_filter(gdk_get_default_root_window(), filter_func, NULL);
 
181
        return Qtrue;
 
182
}
 
183
 
 
184
void
 
185
Init_rghk()
 
186
{
 
187
/*
 
188
 * rghk provides a simple way to set global hotkeys.
 
189
 * 
 
190
 * Example:
 
191
 *   kb=GlobalHotKeys::KeyBinder.new
 
192
 *   kb.bind(Gdk::Keyval::GDK_a,  GlobalHotKeys::Modifier::CONTROL_MASK){puts 'Binded'}
 
193
 *   kb.unbind
 
194
 * 
 
195
 * It probably a good idea to require 'gtk2' before 'rghk'.
 
196
 * The librairy rghk  was not tested without ruby/gtk2.
 
197
*/
 
198
        mGlobalHotKeys=rb_define_module("GlobalHotKeys");
 
199
        rb_define_module_function(mGlobalHotKeys, "init", mInit, 0);
 
200
 
 
201
        mModifier=rb_define_module_under(mGlobalHotKeys, "Modifier");
 
202
        rb_define_const(mModifier, "SHIFT_MASK", INT2FIX(RGHK_SHIFT_MASK));
 
203
        rb_define_const(mModifier, "CONTROL_MASK", INT2FIX(RGHK_CONTROL_MASK));
 
204
        rb_define_const(mModifier, "MOD1_MASK", INT2FIX(RGHK_MOD1_MASK));//Alt
 
205
        //rb_define_const(mModifier, "MOD2_MASK", INT2FIX(RGHK_MOD2_MASK));//NUM_LOCK
 
206
        rb_define_const(mModifier, "MOD3_MASK", INT2FIX(RGHK_MOD3_MASK));
 
207
        rb_define_const(mModifier, "MOD4_MASK", INT2FIX(RGHK_MOD4_MASK));
 
208
        rb_define_const(mModifier, "MOD5_MASK", INT2FIX(RGHK_MOD5_MASK));//AltGr?
 
209
 
 
210
        cKeyBinder=rb_define_class_under(mGlobalHotKeys, "KeyBinder", rb_cObject);
 
211
        rb_iv_set(cKeyBinder, "stock", rb_ary_new());
 
212
        rb_define_method(cKeyBinder, "bind", kb_bind, 2);
 
213
        rb_define_method(cKeyBinder, "unbind", kb_unbind, 0);
 
214
        rb_define_module_function(cKeyBinder, "unbind_all", kb_unbind_all,0);
 
215
}