zoukankan      html  css  js  c++  java
  • X Window研究笔记(6)

    X Window研究笔记(6)

    转载时请注明出处和作者联系方式
    作者联系方式:李先静 <xianjimli at hotmail dot com>

    6.X Window输入设备(TinyX)

    X Window支持的基本输入设备有keyboard、mouse和touchscreen,keyboard有自己的驱动接口,而后两者具有相同的驱动接口。

    输入设备的初始化。

    1. X Server在初始化时会调用InitInput函数初始化输入设备。
    2. InitInput调用KdInitInput完成TinyX输入设备的初始化。其参数LinuxMouseFuncs指向mouse驱动函数,LinuxKeyboardFuncs指向keyboard驱动的函数。
    3. 在KdInitInput中,创建一个KdMouseInfo对象,放入kdMouseInfo链表中,并初始化这个KdMouseInfo对象。
    4. 在KdInitInput中,把指向keyboard和mouse驱动的指针保存到kdMouseFuncs和kdKeyboardFuncs两个全局变量之中。
    5. 在KdInitInput中,加载键盘映射表,初始化按键重复的数据结构,重置输入设备的状态。
    6. 在KdInitInput中,创建keyboard和mouse设备,并注册这两个输入设备到系统中。
    7. 如果支持touchscreen,把kdTsFuncs指向TsFuncs。

    keyboard的驱动接口

    typedef struct _KdKeyboardFuncs {
        
    void            (*Load) (void);
        
    int             (*Init) (void);
        
    void            (*Leds) (int);
        
    void            (*Bell) (intintint);
        
    void            (*Fini) (void);
        
    int             LockLed;
    }
     KdKeyboardFuncs;


    下面我们来看一个实际例子(tinyx/linux/keyboard.c):

    KdKeyboardFuncs LinuxKeyboardFuncs = {
        LinuxKeyboardLoad,
        LinuxKeyboardInit,
        LinuxKeyboardLeds,
        LinuxKeyboardBell,
        LinuxKeyboardFini,
        
    3,
    }
    ;

    LinuxKeyboardLoad: 构建一个键值映射表,即从原始的按键值到虚拟键值间VK之间的映射。让虚拟键值独立于硬件的,可以提高应用程序的可移植性。

    static void
    LinuxKeyboardLoad (
    void)
    {  
        readKernelMapping ();
    }
        


    LinuxKeyboardInit:初始化一些数据结构,并注册相关回调函数。这样,在有按键事件时,LinuxConsoleFd唤醒select,并调用函数LinuxKeyboardRead读取按键事件,经过一些转换动作之后,调用KdHandleKeyboardEvent把事件分发出去。
    static int
    LinuxKeyboardInit (
    void)
    {
        
    if (!LinuxKbdType)
            LinuxKbdType 
    = KdAllocInputType ();

        KdRegisterFd (LinuxKbdType, LinuxConsoleFd, LinuxKeyboardRead, 
    0);
        LinuxKeyboardEnable (LinuxConsoleFd, 
    0);
        KdRegisterFdEnableDisable (LinuxConsoleFd,
                                   LinuxKeyboardEnable,
                                   LinuxKeyboardDisable);
        
    return 1;
    }


    LinuxKeyboardLeds: 在某些键按下以后,需要点亮键盘灯(Caps Lock和 Num Lock等),这时候会调用这个函数,这是通过ioctl系统调用实现的。

    static void
    LinuxKeyboardLeds (
    int leds)
    {
        ioctl (LinuxConsoleFd, KDSETLED, leds 
    & 7);
    }


    LinuxKeyboardBell:它的功能是发出蜂鸣声,至于为什么作为键盘驱动的一部分,可能是由于输入某些键值时要响一声吧(如,/a)。这也是通过ioctl系统调用实现的。
    static void
    LinuxKeyboardBell (
    int volume, int pitch, int duration)
    {
        
    if (volume && pitch)
        
    {
            ioctl(LinuxConsoleFd, KDMKTONE,
                  ((
    1193190 / pitch) & 0xffff|
                  (((unsigned 
    long)duration *
                    volume 
    / 50<< 16));

        }

    }


    LinuxKeyboardFini:~初始化keyboard设备,即禁用keyboard,然后注销设备描述符。

    static void
    LinuxKeyboardFini (
    void)
    {
        LinuxKeyboardDisable (LinuxConsoleFd, 
    0);
        KdUnregisterFds (LinuxKbdType, FALSE);
    }


    鼠标的接口:


    typedef struct _KdMouseFuncs {
        
    int             (*Init) (void);
        
    void            (*Fini) (void);
    }
     KdMouseFuncs;

    下面看一个实际例子(tinyx/linux/mouse.c)

    KdMouseFuncs LinuxMouseFuncs = {
        MouseInit,
        MouseFini,
    }
    ;

    MouseInit 打开设备文件,并注册一些回调函数。这样,在有mouse事件时,fd唤醒select,并调用函数MouseRead读取mouse事件,经过一些转换动作之后,调用KdHandleMouseEvent把事件分发出去。

    char *kdefaultMouse[] =  {
        
    "/dev/mouse",
        
    "/dev/psaux",
        
    "/dev/input/mice",
        
    "/dev/adbmouse",
        
    "/dev/ttyS0",
        
    "/dev/ttyS1",
    }
    ;

    #define NUM_DEFAULT_MOUSE    (sizeof (kdefaultMouse) / sizeof (kdefaultMouse[0]))

    static int
    MouseInit (
    void)
    {
        
    int     i;
        
    int     fd = -1;
        Kmouse  
    *km;
        KdMouseInfo 
    *mi, *next;
        
    int     n = 0;
        
    char    *prot;

        
    if (!MouseInputType)
        MouseInputType 
    = KdAllocInputType ();

        
    for (mi = kdMouseInfo; mi; mi = next)
        
    {
        next 
    = mi->next;
        prot 
    = mi->prot;
        
    if (mi->inputType)
            
    continue;
        
    if (!mi->name)
        
    {
            
    for (i = 0; i < NUM_DEFAULT_MOUSE; i++)
            
    {
            
    if (kdNoSerialMouse && strstr(kdefaultMouse[i], "/dev/ttyS"))
                
    continue;
            fd 
    = open (kdefaultMouse[i], 2);
            
    if (fd >= 0)
            
    {
                mi
    ->name = KdSaveString (kdefaultMouse[i]);
                
    break;
            }

            }
      
        }

        
    else
            fd 
    = open (mi->name, 2);
               
        
    if (fd >= 0)
        
    {
            km 
    = (Kmouse *) xalloc (sizeof (Kmouse));
            
    if (km)
            
    {
            km
    ->iob.fd = fd;
            km
    ->iob.avail = km->iob.used = 0;
           km
    ->prot = 0;
            km
    ->i_prot = 0;
            km
    ->tty = isatty (fd);
            mi
    ->driver = km;
            mi
    ->inputType = MouseInputType;
            MouseFirstProtocol (km, mi
    ->prot);
            
    if (KdRegisterFd (MouseInputType, fd, MouseRead, (void *) mi))
                n
    ++;
            }

            
    else
            close (fd);
        }

        }

        
    return n;
    }


    MouseFini: ~初始化mouse设备,即注销回调函数,并释放一些数据结构。

    static void
    MouseFini (
    void)
    {
        KdMouseInfo 
    *mi;

        KdUnregisterFds (MouseInputType, TRUE);
        
    for (mi = kdMouseInfo; mi; mi = mi->next)
        
    {
        
    if (mi->inputType == MouseInputType)
        
    {
            xfree (mi
    ->driver);
            mi
    ->driver = 0;
            mi
    ->inputType = 0;
        }

        }

    }



    触摸屏的接口

    typedef struct _KdMouseFuncs {
        
    int             (*Init) (void);
        
    void            (*Fini) (void);
    }
     KdMouseFuncs;


    触摸屏是作为鼠标来实现的。下面看一个实际例子(tinyx/linux/tslib.c)
    KdMouseFuncs TsFuncs = {
        TslibInit,
        TslibFini
    }
    ;

    TslibInit:打开设备文件,并注册一些回调函数。由于触摸屏涉及到去抖、滤波、校准等功能,相关对于鼠标来说,要复杂得多,所以这里是调用tslib来实现的。

    在有笔点事件时,fd唤醒select,并调用函数TsRead读取笔点事件,经过一些转换动作之后,调用KdHandleMouseEvent把事件分发出去。

    int
    TslibInit (
    void)
    {
        
    int         i;
        KdMouseInfo 
    *mi, *next;
        
    int         fd= 0;
        
    int         n = 0;
       
        
    if (!TsInputType)
            TsInputType 
    = KdAllocInputType ();
           
        
    for (mi = kdMouseInfo; mi; mi = next)
        
    {
            next 
    = mi->next;
            
    if (mi->inputType)
                
    continue;
               
            
    if (!mi->name)
            
    {
                
    for (i = 0; i < NUM_TS_NAMES; i++)
                
    {
                    
    if(!(tsDev = ts_open(TsNames[i],0))) continue;
                    ts_config(tsDev);
                    fd
    =ts_fd(tsDev);
                    
    if (fd >= 0)
                    
    {
                        mi
    ->name = KdSaveString (TsNames[i]);
                        
    break;
                    }
      
                }
      
            }
      
           
            
    if (fd > 0 && tsDev != 0)
              
    {
                mi
    ->driver = (void *) fd;
                mi
    ->inputType = TsInputType;
                    
    if (KdRegisterFd (TsInputType, fd, TsRead, (void *) mi))
                        n
    ++;
              }

            
    else
              
    if (fd > 0) close(fd);
            }

    }


    TslibFini: ~初始化touchscreen设备,即注销相关的回调函数,并释放一些数据结构。

    void
    TslibFini (
    void)
    {
        KdMouseInfo 
    *mi;

        KdUnregisterFds (TsInputType, TRUE);
        
    for (mi = kdMouseInfo; mi; mi = mi->next)
        
    {
            
    if (mi->inputType == TsInputType)
            
    {
                
    if(mi->driver) ts_close(tsDev);
                mi
    ->driver = 0;
                mi
    ->inputType = 0;
                
    if (mi->name != NULL) {
                    free(mi
    ->name);
                    mi
    ->name = NULL;
                }

            }

        }

    }


    有意思的是,驱动本身的接口并不能说明设备的特性,它只提供初始化和~初始化这类通用接口,在初始化时才注册设备描述符和相应的读取函数。

    (待续)
     
  • 相关阅读:
    电位器的使用
    序言
    跨域之options请求详解
    redis config 实现切库 和指定序列化
    巨坑! druid1.1.0
    跨域问题解决
    canal解决缓存穿透 对数据库同步数据至redis 或EleasticSearch
    oauth2+spring security +jwt 完成分布式服务认证
    oauth2的数据库设计
    Gson 转换 Localdate 使用 GsonBuilder setDateFormat 无效
  • 原文地址:https://www.cnblogs.com/zhangyunlin/p/6167686.html
Copyright © 2011-2022 走看看