*in progress*
[winnie] / src / fbdev / mouse.cc
1 #ifdef WINNIE_FBDEV
2 #include <errno.h>
3 #include <limits.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include <fcntl.h>
9 #include <sys/ioctl.h>
10 #include <termios.h>
11 #include <unistd.h>
12
13 #include "geom.h"
14 #include "gfx.h"
15 #include "mouse.h"
16 #include "window.h"
17 #include "wm.h"
18
19 #define BN_LEFT         1
20 #define BN_RIGHT        2
21 #define BN_MIDDLE       4
22
23 static int read_mouse();
24
25 static int dev_fd = -1; // file descriptor for /dev/psaux
26 static Rect bounds;
27 static int pointer_x, pointer_y;
28 static int bnstate;
29
30 bool init_mouse()
31 {
32         if((dev_fd = open("/dev/psaux", O_RDONLY | O_NONBLOCK)) == -1) {
33                 fprintf(stderr, "Cannot open /dev/psaux : %s\n", strerror(errno));
34                 return false;
35         }
36
37         set_mouse_bounds(get_screen_size());
38         return true;
39 }
40
41 void destroy_mouse()
42 {
43         if(dev_fd != -1) {
44                 close(dev_fd);
45                 dev_fd = -1;
46         }
47 }
48
49 void set_mouse_bounds(const Rect &rect)
50 {
51         bounds = rect;
52 }
53
54 int get_mouse_fd()
55 {
56         return dev_fd;
57 }
58
59 void process_mouse_event()
60 {
61         /* TODO:
62          * - read all pending events from mouse fd (use O_NONBLOCK so that
63          *   read will return -1 when there are no more events instead of blocking).
64          */
65
66         int prev_state = bnstate;
67         int prev_x = pointer_x;
68         int prev_y = pointer_y;
69
70         if(read_mouse() == -1) {
71                 return;
72         }
73
74         Window *top = wm->get_window_at_pos(pointer_x, pointer_y);
75         if(top) {
76                 wm->set_focused_window(top);
77         }
78         else {
79                 wm->set_focused_window(0);
80         }
81
82          /* - send each pointer move and button press/release to the topmost window
83          *   with the pointer on it.
84          */
85
86         int dx = pointer_x - prev_x;
87         int dy = pointer_y - prev_y;
88
89         if((dx || dy) && top) {
90                 MouseMotionFuncType motion_callback = top->get_mouse_motion_callback();
91                 if(motion_callback) {
92                         Rect rect = top->get_absolute_rect();
93                         motion_callback(top, pointer_x - rect.x, pointer_y - rect.y);
94                 }
95         }
96
97         MouseButtonFuncType button_callback;
98         if((bnstate != prev_state) && top && (button_callback = top->get_mouse_button_callback())) {
99                 int num_bits = sizeof bnstate * CHAR_BIT;
100                 for(int i=0; i<num_bits; i++) {
101                         int s = (bnstate >> i) & 1;
102                         int prev_s = (prev_state >> i) & 1;
103                         if(s != prev_s) {
104                                 Rect rect = top->get_absolute_rect();
105                                 button_callback(top, i, s, pointer_x - rect.x, pointer_y - rect.y);
106                         }
107                 }
108         }
109 }
110
111 void get_pointer_pos(int *x, int *y)
112 {
113         *x = pointer_x;
114         *y = pointer_y;
115 }
116
117 int get_button_state()
118 {
119         return bnstate;
120 }
121
122 int get_button(int bn)
123 {
124         if(bn < 0 || bn >= 3) {
125                 return 0;
126         }
127         return (bnstate & (1 << bn)) != 0;
128 }
129
130 static int read_mouse()
131 {
132         int rd;
133         signed char state[3] = {0, 0, 0};
134
135         if((rd = read(dev_fd, state, 3)) == -1) {
136                 fprintf(stderr, "Unable to get mouse state : %s\n", strerror(errno));
137                 return -1;
138         }
139
140         bnstate = state[0] & 7;
141         pointer_x += state[1];
142         pointer_y -= state[2];
143
144         if(pointer_x < bounds.x) {
145                 pointer_x = bounds.x;
146         }
147
148         if(pointer_y < bounds.y) {
149                 pointer_y = bounds.y;
150         }
151
152         if(pointer_x > bounds.x + bounds.width - 1) {
153                 pointer_x = bounds.x + bounds.width - 1;
154         }
155
156         if(pointer_y > bounds.y + bounds.height - 1) {
157                 pointer_y = bounds.y + bounds.height - 1;
158         }
159
160         return 0;
161 }
162 #endif // WINNIE_FBDEV