📄 sec-addingxinputsupport.html
字号:
segfault.)</P><P>The InputDialog has two buttons "Close" and "Save", which by defaulthave no actions assigned to them. In the above function we make"Close" hide the dialog, hide the "Save" button, since we don'timplement saving of XInput options in this program.</P></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN2919">25.4.2. Using extended device information</A></H2><P>Once we've enabled the device, we can just use the extended device information in the extra fields of the event structures.In fact, it is always safe to use this information since thesefields will have reasonable default values even when extendedevents are not enabled.</P><P>Once change we do have to make is to call<TTCLASS="LITERAL">gdk_input_window_get_pointer()</TT> instead of<TTCLASS="LITERAL">gdk_window_get_pointer</TT>. This is necessary because<TTCLASS="LITERAL">gdk_window_get_pointer</TT> doesn't return the extended deviceinformation.</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">void gdk_input_window_get_pointer( GdkWindow *window, guint32 deviceid, gdouble *x, gdouble *y, gdouble *pressure, gdouble *xtilt, gdouble *ytilt, GdkModifierType *mask);</PRE></TD></TR></TABLE><P>When calling this function, we need to specify the device ID aswell as the window. Usually, we'll get the device ID from the<TTCLASS="LITERAL">deviceid</TT> field of an event structure. Again, this functionwill return reasonable values when extension events are notenabled. (In this case, <TTCLASS="LITERAL">event->deviceid</TT> will have the value<TTCLASS="LITERAL">GDK_CORE_POINTER</TT>).</P><P>So the basic structure of our button-press and motion event handlersdoesn't change much - we just need to add code to deal with theextended information.</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">static gintbutton_press_event (GtkWidget *widget, GdkEventButton *event){ print_button_press (event->deviceid); if (event->button == 1 && pixmap != NULL) draw_brush (widget, event->source, event->x, event->y, event->pressure); return TRUE;}static gintmotion_notify_event (GtkWidget *widget, GdkEventMotion *event){ gdouble x, y; gdouble pressure; GdkModifierType state; if (event->is_hint) gdk_input_window_get_pointer (event->window, event->deviceid, &x, &y, &pressure, NULL, NULL, &state); else { x = event->x; y = event->y; pressure = event->pressure; state = event->state; } if (state & GDK_BUTTON1_MASK && pixmap != NULL) draw_brush (widget, event->source, x, y, pressure); return TRUE;}</PRE></TD></TR></TABLE><P>We also need to do something with the new information. Our new<TTCLASS="LITERAL">draw_brush()</TT> function draws with a different color foreach <TTCLASS="LITERAL">event->source</TT> and changes the brush size dependingon the pressure.</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">/* Draw a rectangle on the screen, size depending on pressure, and color on the type of device */static voiddraw_brush (GtkWidget *widget, GdkInputSource source, gdouble x, gdouble y, gdouble pressure){ GdkGC *gc; GdkRectangle update_rect; switch (source) { case GDK_SOURCE_MOUSE: gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)]; break; case GDK_SOURCE_PEN: gc = widget->style->black_gc; break; case GDK_SOURCE_ERASER: gc = widget->style->white_gc; break; default: gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)]; } update_rect.x = x - 10 * pressure; update_rect.y = y - 10 * pressure; update_rect.width = 20 * pressure; update_rect.height = 20 * pressure; gdk_draw_rectangle (pixmap, gc, TRUE, update_rect.x, update_rect.y, update_rect.width, update_rect.height); gtk_widget_draw (widget, &update_rect);}</PRE></TD></TR></TABLE></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN2937">25.4.3. Finding out more about a device</A></H2><P>As an example of how to find out more about a device, our programwill print the name of the device that generates each buttonpress. To find out the name of a device, we call the function:</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">GList *gdk_input_list_devices (void);</PRE></TD></TR></TABLE><P>which returns a GList (a linked list type from the GLib library)of GdkDeviceInfo structures. The GdkDeviceInfo structure is definedas:</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">struct _GdkDeviceInfo{ guint32 deviceid; gchar *name; GdkInputSource source; GdkInputMode mode; gint has_cursor; gint num_axes; GdkAxisUse *axes; gint num_keys; GdkDeviceKey *keys;};</PRE></TD></TR></TABLE><P>Most of these fields are configuration information that you can ignoreunless you are implementing XInput configuration saving. The fieldweare interested in here is <TTCLASS="LITERAL">name</TT> which is simply the name that Xassigns to the device. The other field that isn't configurationinformation is <TTCLASS="LITERAL">has_cursor</TT>. If <TTCLASS="LITERAL">has_cursor</TT> is false, then wewe need to draw our own cursor. But since we've specified<TTCLASS="LITERAL">GDK_EXTENSION_EVENTS_CURSOR</TT>, we don't have to worry about this.</P><P>Our <TTCLASS="LITERAL">print_button_press()</TT> function simply iterates throughthe returned list until it finds a match, then prints outthe name of the device.</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">static voidprint_button_press (guint32 deviceid){ GList *tmp_list; /* gdk_input_list_devices returns an internal list, so we shouldn't free it afterwards */ tmp_list = gdk_input_list_devices(); while (tmp_list) { GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data; if (info->deviceid == deviceid) { printf("Button press on device '%s'\n", info->name); return; } tmp_list = tmp_list->next; }}</PRE></TD></TR></TABLE><P>That completes the changes to "XInputize" our program.</P></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="SEC-FURTHERSOPHISTICATIONS">25.4.4. Further sophistications</A></H2><P>Although our program now supports XInput quite well, it lacks somefeatures we would want in a full-featured application. First, the userprobably doesn't want to have to configure their device each time theyrun the program, so we should allow them to save the deviceconfiguration. This is done by iterating through the return of<TTCLASS="LITERAL">gdk_input_list_devices()</TT> and writing out the configuration to afile.</P><P>To restore the state next time the program is run, GDK providesfunctions to change device configuration:</P><TABLEBORDER="0"BGCOLOR="#E0E0E0"WIDTH="100%"><TR><TD><PRECLASS="PROGRAMLISTING">gdk_input_set_extension_events()gdk_input_set_source()gdk_input_set_mode()gdk_input_set_axes()gdk_input_set_key()</PRE></TD></TR></TABLE><P>(The list returned from <TTCLASS="LITERAL">gdk_input_list_devices()</TT> should not bemodified directly.) An example of doing this can be found in thedrawing program gsumi. (Available from <AHREF="http://www.msc.cornell.edu/~otaylor/gsumi/"TARGET="_top">http://www.msc.cornell.edu/~otaylor/gsumi/</A>) Eventually, itwould be nice to have a standard way of doing this for allapplications. This probably belongs at a slightly higher level thanGTK, perhaps in the GNOME library.</P><P>Another major omission that we have mentioned above is the lack ofcursor drawing. Platforms other than XFree86 currently do not allowsimultaneously using a device as both the core pointer and directly byan application. See the <AHREF="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"TARGET="_top">XInput-HOWTO</A> for more information about this. This means thatapplications that want to support the widest audience need to drawtheir own cursor.</P><P>An application that draws its own cursor needs to do two things:determine if the current device needs a cursor drawn or not, anddetermine if the current device is in proximity. (If the currentdevice is a drawing tablet, it's a nice touch to make the cursor disappear when the stylus is lifted from the tablet. When thedevice is touching the stylus, that is called "in proximity.")The first is done by searching the device list, as we didto find out the device name. The second is achieved by selecting"proximity_out" events. An example of drawing one's own cursor isfound in the "testinput" program found in the GTK distribution.</P></DIV></DIV><DIVCLASS="NAVFOOTER"><HRALIGN="LEFT"WIDTH="100%"><TABLEWIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><AHREF="sec-thedrawingareawidget.html"><<< Previous</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="gtk-tut.html">Home</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><AHREF="ch-tips.html">Next >>></A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">The DrawingArea Widget, And Drawing</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="ch-scribble.html">Up</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">Tips For Writing GTK Applications</TD></TR></TABLE></DIV> </td> </tr></table> </td> </tr></table></body></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -